Skip to content
7 changes: 6 additions & 1 deletion phpstan.neon.dist
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
parameters:
level: 6
level: 7
bootstrapFiles:
- tests/bootstrap.php
paths:
Expand All @@ -9,6 +9,11 @@ parameters:
ignoreErrors:
# # PHP 8.0 & Attribute
- '#^Attribute class PHPUnit\\Framework\\Attributes\\DataProvider does not exist\.#'
# DOMNodeList's generic type (TNode) cannot be pinned across the PHP matrix:
# DOMXPath::query() returns DOMNodeList<DOMNode> on PHP 7.x but
# DOMNodeList<DOMNameSpaceNode|DOMNode> on PHP 8.x, so no single generic is valid
# on every version. The list is only consumed through length/item(), never by node type.
- '#return type with generic class DOMNodeList does not specify its types: TNode#'

## Remove after remove ArrayObject
treatPhpDocTypesAsCertain: false
8 changes: 5 additions & 3 deletions src/Common/Adapter/Zip/PclZipAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,17 @@ public function addFromString(string $localname, string $contents, bool $withCom
$pathData = pathinfo($localname);

$hFile = fopen($this->tmpDir . '/' . $pathData['basename'], 'wb');
fwrite($hFile, $contents);
fclose($hFile);
if ($hFile !== false) {
fwrite($hFile, $contents);
fclose($hFile);
}

$params = [
$this->tmpDir . '/' . $pathData['basename'],
PCLZIP_OPT_REMOVE_PATH,
$this->tmpDir,
PCLZIP_OPT_ADD_PATH,
$pathData['dirname'],
dirname($localname),
];
if (!$withCompression) {
$params[] = PCLZIP_OPT_NO_COMPRESSION;
Expand Down
2 changes: 1 addition & 1 deletion src/Common/Autoloader.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public static function autoload(string $class): void
$prefixLength = strlen(self::NAMESPACE_PREFIX);
if (0 === strncmp(self::NAMESPACE_PREFIX, $class, $prefixLength)) {
$file = str_replace('\\', DIRECTORY_SEPARATOR, substr($class, $prefixLength));
$file = realpath(__DIR__ . (empty($file) ? '' : DIRECTORY_SEPARATOR) . $file . '.php');
$file = (string) realpath(__DIR__ . (empty($file) ? '' : DIRECTORY_SEPARATOR) . $file . '.php');
if (file_exists($file)) {
/** @noinspection PhpIncludeInspection Dynamic includes */
require_once $file;
Expand Down
6 changes: 3 additions & 3 deletions src/Common/Drawing.php
Original file line number Diff line number Diff line change
Expand Up @@ -140,9 +140,9 @@ public static function htmlToRGB(string $pValue): ?array
return null;
}

$colorR = hexdec($colorR);
$colorG = hexdec($colorG);
$colorB = hexdec($colorB);
$colorR = (int) hexdec($colorR);
$colorG = (int) hexdec($colorG);
$colorB = (int) hexdec($colorB);

return [$colorR, $colorG, $colorB];
}
Expand Down
6 changes: 4 additions & 2 deletions src/Common/File.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,16 @@ public static function fileGetContents(string $pFilename): ?string
$returnValue = $zip->getFromName($archiveFile);
$zip->close();

return $returnValue;
return $returnValue === false ? null : $returnValue;
}

return null;
}

// Regular file contents
return file_get_contents($pFilename);
$contents = file_get_contents($pFilename);

return $contents === false ? null : $contents;
}

/**
Expand Down
10 changes: 5 additions & 5 deletions src/Common/Microsoft/OLERead.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,11 @@ class OLERead
*/
public $pictures;
/**
* @var int|null
* @var int
*/
public $rootEntry;
public $rootEntry = 0;
/**
* @var array<int, array<string, int|string>>
* @var array<int, array{name: string, type: int, startBlock: int, size: int}>
*/
public $props = [];
/**
Expand Down Expand Up @@ -115,15 +115,15 @@ public function read(string $sFileName): void

// Get the file identifier
// Don't bother reading the whole file until we know it's a valid OLE file
$this->data = file_get_contents($sFileName, false, null, 0, 8);
$this->data = (string) file_get_contents($sFileName, false, null, 0, 8);

// Check OLE identifier
if ($this->data != self::IDENTIFIER_OLE) {
throw new \Exception('The filename ' . $sFileName . ' is not recognised as an OLE file');
}

// Get the file data
$this->data = file_get_contents($sFileName);
$this->data = (string) file_get_contents($sFileName);

// Total number of sectors used for the SAT
$numBigBlkDepotBlks = self::getInt4d($this->data, self::NUM_BIG_BLOCK_DEPOT_BLOCKS_POS);
Expand Down
4 changes: 2 additions & 2 deletions src/Common/Microsoft/PasswordEncoder.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class PasswordEncoder
/**
* Mapping between algorithm name and algorithm ID
*
* @var array<string, array<int, int|string>>
* @var array<string, array{0: int, 1: string}>
*
* @see https://msdn.microsoft.com/en-us/library/documentformat.openxml.wordprocessing.writeprotection.cryptographicalgorithmsid(v=office.14).aspx
*/
Expand Down Expand Up @@ -124,7 +124,7 @@ public static function hashPassword(string $password, string $algorithmName = se

// Get the single-byte values by iterating through the Unicode characters of the truncated password.
// For each character, if the low byte is not equal to 0, take it. Otherwise, take the high byte.
$passUtf8 = mb_convert_encoding($password, 'UCS-2LE', 'UTF-8');
$passUtf8 = (string) mb_convert_encoding($password, 'UCS-2LE', 'UTF-8');
$byteChars = [];

for ($i = 0; $i < mb_strlen($password); ++$i) {
Expand Down
11 changes: 5 additions & 6 deletions src/Common/Text.php
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ public static function numberFormat(float $number, int $decimals): string
public static function chr(int $dec): string
{
if ($dec <= 0x7F) {
return chr($dec);
return chr($dec & 0xFF);
}
if ($dec <= 0x7FF) {
return chr(($dec >> 6) + 192) . chr(($dec & 63) + 128);
Expand Down Expand Up @@ -226,7 +226,7 @@ private static function unicodeToEntities(array $unicode): string

foreach ($unicode as $value) {
if ($value != 65279) {
$entities .= $value > 127 ? '\uc0{\u' . $value . '}' : chr($value);
$entities .= $value > 127 ? '\uc0{\u' . $value . '}' : chr($value & 0xFF);
}
}

Expand All @@ -242,10 +242,9 @@ private static function unicodeToEntities(array $unicode): string
*/
public static function removeUnderscorePrefix(?string $value): string
{
if (!is_null($value)) {
if (substr($value, 0, 1) == '_') {
$value = substr($value, 1);
}
$value = (string) $value;
if (substr($value, 0, 1) == '_') {
$value = (string) substr($value, 1);
}

return $value;
Expand Down
12 changes: 6 additions & 6 deletions src/Common/XMLReader.php
Original file line number Diff line number Diff line change
Expand Up @@ -107,22 +107,22 @@ public function getDomFromString(string $content)
* @param string $path
* @param \DOMElement $contextNode
*
* @return \DOMNodeList<\DOMElement>
* @return \DOMNodeList
*/
public function getElements(string $path, ?\DOMElement $contextNode = null)
{
if ($this->dom === null) {
return new \DOMNodeList();
return (new \DOMDocument())->childNodes;
}
if ($this->xpath === null) {
$this->xpath = new \DOMXpath($this->dom);
}

if (is_null($contextNode)) {
return $this->xpath->query($path);
}
$elements = is_null($contextNode)
? $this->xpath->query($path)
: $this->xpath->query($path, $contextNode);

return $this->xpath->query($path, $contextNode);
return $elements === false ? (new \DOMDocument())->childNodes : $elements;
}

/**
Expand Down
13 changes: 9 additions & 4 deletions src/Common/XMLWriter.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,13 @@ public function __construct(int $pTemporaryStorage = self::STORAGE_MEMORY, ?stri
$pTemporaryStorageDir = sys_get_temp_dir();
}
// Create temporary filename
$this->tempFileName = @tempnam($pTemporaryStorageDir, 'xml');
$tempFileName = @tempnam($pTemporaryStorageDir, 'xml');
if ($tempFileName !== false) {
$this->tempFileName = $tempFileName;

// Open storage
$this->openUri($this->tempFileName);
// Open storage
$this->openUri($this->tempFileName);
}
}

if ($compatibility) {
Expand Down Expand Up @@ -106,7 +109,9 @@ public function getData()

$this->flush();

return file_get_contents($this->tempFileName);
$contents = file_get_contents($this->tempFileName);

return false === $contents ? '' : $contents;
}

/**
Expand Down
6 changes: 3 additions & 3 deletions tests/Common/Tests/Adapter/Zip/AbstractZipAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public function setUp(): void
parent::setUp();

$pathResources = PHPOFFICE_COMMON_TESTS_BASE_DIR . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR . 'files' . DIRECTORY_SEPARATOR;
$this->zipTest = tempnam(sys_get_temp_dir(), 'PhpOfficeCommon');
$this->zipTest = (string) tempnam(sys_get_temp_dir(), 'PhpOfficeCommon');
copy($pathResources . 'Sample_01_Simple.pptx', $this->zipTest);
}

Expand Down Expand Up @@ -53,7 +53,7 @@ public function testClose(): void
public function testAddFromStringWithCompression(): void
{
$expectedPath = 'file.png';
$expectedContent = file_get_contents(
$expectedContent = (string) file_get_contents(
PHPOFFICE_COMMON_TESTS_BASE_DIR
. DIRECTORY_SEPARATOR . 'resources'
. DIRECTORY_SEPARATOR . 'images'
Expand All @@ -73,7 +73,7 @@ public function testAddFromStringWithCompression(): void
public function testAddFromStringWithNoCompression(): void
{
$expectedPath = 'file.png';
$expectedContent = file_get_contents(
$expectedContent = (string) file_get_contents(
PHPOFFICE_COMMON_TESTS_BASE_DIR
. DIRECTORY_SEPARATOR . 'resources'
. DIRECTORY_SEPARATOR . 'images'
Expand Down
2 changes: 1 addition & 1 deletion tests/Common/Tests/AutoloaderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public function testRegister(): void
Autoloader::register();
$this->assertContains(
['PhpOffice\\Common\\Autoloader', 'autoload'],
spl_autoload_functions()
(array) spl_autoload_functions()
);
}

Expand Down
2 changes: 1 addition & 1 deletion tests/Common/Tests/FileTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public function testFileExists(): void
$this->assertFalse(File::fileExists('zip://' . $pathResources . 'files' . DIRECTORY_SEPARATOR . '404.pptx#404.xml'));

// Set a ZIP en ReadOnly Mode
$zipTest = tempnam(sys_get_temp_dir(), 'PhpOfficeCommon');
$zipTest = (string) tempnam(sys_get_temp_dir(), 'PhpOfficeCommon');
copy($pathResources . 'files' . DIRECTORY_SEPARATOR . 'Sample_01_Simple.pptx', $zipTest);
chmod($zipTest, 333);
$this->assertFalse(File::fileExists('zip://' . $zipTest));
Expand Down
3 changes: 3 additions & 0 deletions tests/Common/Tests/_includes/TestHelperZip.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ public static function assertFileIsCompressed(string $fileZip, string $path): bo
$oZip = new \ZipArchive();
$oZip->open($fileZip);
$stat = $oZip->statName($path);
if ($stat === false) {
return false;
}

// size: uncompressed
// comp_size: compressed
Expand Down
15 changes: 10 additions & 5 deletions tests/Common/Tests/_includes/XmlDocument.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class XmlDocument
*/
public function __construct(string $path)
{
$this->path = realpath($path);
$this->path = realpath($path) ?: '';
}

/**
Expand Down Expand Up @@ -93,7 +93,7 @@ public function getFileDom(string $file = 'word/document.xml'): \DOMDocument
* @param string $path
* @param string $file
*
* @return \DOMNodeList<\DOMElement>
* @return \DOMNodeList
*/
public function getNodeList(string $path, string $file = 'word/document.xml'): \DOMNodeList
{
Expand All @@ -105,7 +105,9 @@ public function getNodeList(string $path, string $file = 'word/document.xml'): \
$this->xpath = new \DOMXpath($this->dom);
}

return $this->xpath->query($path);
$elements = $this->xpath->query($path);

return $elements === false ? (new \DOMDocument())->childNodes : $elements;
}

/**
Expand All @@ -118,9 +120,12 @@ public function getNodeList(string $path, string $file = 'word/document.xml'): \
*/
public function getElement(string $path, string $file = 'word/document.xml'): \DOMNode
{
$elements = $this->getNodeList($path, $file);
$element = $this->getNodeList($path, $file)->item(0);
if (!$element instanceof \DOMNode) {
throw new \Exception('Element not found: ' . $path);
}

return $elements->item(0);
return $element;
}

/**
Expand Down
Loading