diff --git a/.scrutinizer.yml b/.scrutinizer.yml index 2b395afd26..d1fe59618d 100644 --- a/.scrutinizer.yml +++ b/.scrutinizer.yml @@ -3,6 +3,12 @@ build: analysis: tests: override: [php-scrutinizer-run] + environment: + php: + version: '7.4' + pecl_extensions: + - zip + filter: excluded_paths: [ 'vendor/*', 'tests/*', 'samples/*', 'src/PhpWord/Shared/PCLZip/*' ] diff --git a/.travis.yml b/.travis.yml index acdf95cc34..aca5dbf8b6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,29 +11,30 @@ php: - 7.1 - 7.2 - 7.3 - - 7.4snapshot + - 7.4 + - 8.0 matrix: include: - php: 5.3 dist: precise - env: COMPOSER_MEMORY_LIMIT=3G - php: 5.4 dist: trusty - php: 5.5 dist: trusty - php: 7.0 env: COVERAGE=1 - - php: 7.3 + - php: 8.0 env: DEPENDENCIES="--ignore-platform-reqs" exclude: - php: 5.3 + dist: xenial - php: 5.4 + dist: xenial - php: 5.5 - - php: 7.0 - - php: 7.3 + dist: xenial allow_failures: - - php: 7.4snapshot + - php: 8.0 cache: directories: @@ -55,7 +56,31 @@ before_script: - if [ -z "$COVERAGE" ]; then phpenv config-rm xdebug.ini || echo "xdebug not available" ; fi ## Composer - composer self-update + ## Composer in PHP versions 5.x requires 3 GB memory + - if [ ${TRAVIS_PHP_VERSION:0:2} == "5." ]; then export COMPOSER_MEMORY_LIMIT=3G ; fi + ## PHP 8 require PHPUnit 8 (ugly hack for support PHPUnit 7 and 8 together) + - | + if [[ ${TRAVIS_PHP_VERSION:0:2} == "8." ]] || [[ $TRAVIS_PHP_VERSION == "nightly" ]]; then + travis_wait composer remove phpunit/phpunit --dev --no-update --no-interaction + travis_wait composer require phpunit/phpunit ^8.0 --dev --no-update + fi + ## Install composer packages - travis_wait composer install --prefer-source $(if [ -n "$DEPENDENCIES" ]; then echo $DEPENDENCIES; fi) + ## PHP 8 require PHPUnit 8 (ugly hack for support PHPUnit 7 and 8 together) + - | + if [[ ${TRAVIS_PHP_VERSION:0:2} == "8." ]] || [[ $TRAVIS_PHP_VERSION == "nightly" ]]; then + find ./tests/ -name "*.php" -type f -exec sed -i -e 's/function setUpBeforeClass()$/function setUpBeforeClass(): void/' {} \; + find ./tests/ -name "*.php" -type f -exec sed -i -e 's/function tearDownAfterClass()$/function tearDownAfterClass(): void/' {} \; + find ./tests/ -name "*.php" -type f -exec sed -i -e 's/function setUp()$/function setUp(): void/' {} \; + find ./tests/ -name "*.php" -type f -exec sed -i -e 's/function tearDown()$/function tearDown(): void/' {} \; + + find ./tests/ -name "*.php" -type f -exec sed -i -e 's/->assertContains(/->assertStringContainsString(/' {} \; + find ./tests/ -name "*.php" -type f -exec sed -i -e 's/->assertNotContains(/->assertStringNotContainsString(/' {} \; + find ./tests/ -name "*.php" -type f -exec sed -i -e "s/->assertInternalType('array', /->assertIsArray(/" {} \; + + sed -i "s/\$this->addWarning('The @expectedException,/\/\/\$this->addWarning('The @expectedException,/" ./vendor/phpunit/phpunit/src/Framework/TestCase.php + sed -i "s/self::createWarning('The optional \$delta/\/\/self::createWarning('The optional \$delta/" ./vendor/phpunit/phpunit/src/Framework/Assert.php + fi ## PHPDocumentor ##- mkdir -p build/docs - mkdir -p build/coverage diff --git a/README.md b/README.md index b15f83d74e..30b008a28e 100644 --- a/README.md +++ b/README.md @@ -62,8 +62,7 @@ PHPWord requires the following: - PHP 5.3.3+ - [XML Parser extension](http://www.php.net/manual/en/xml.installation.php) -- [Zend\Escaper component](http://framework.zend.com/manual/current/en/modules/zend.escaper.introduction.html) -- [Zend\Stdlib component](http://framework.zend.com/manual/current/en/modules/zend.stdlib.hydrator.html) +- [Laminas Escaper component](https://docs.laminas.dev/laminas-escaper/intro/) - [Zip extension](http://php.net/manual/en/book.zip.php) (optional, used to write OOXML and ODF) - [GD extension](http://php.net/manual/en/book.image.php) (optional, used to add images) - [XMLWriter extension](http://php.net/manual/en/book.xmlwriter.php) (optional, used to write OOXML and ODF) diff --git a/composer.json b/composer.json index f5f751ec04..19997215be 100644 --- a/composer.json +++ b/composer.json @@ -58,24 +58,27 @@ "fix": "Fixes issues found by PHP-CS" }, "require": { - "php": "^5.3.3 || ^7.0", + "php": "^5.3.3 || ^7.0 || ^8.0", "ext-xml": "*", - "zendframework/zend-escaper": "^2.2", + "laminas/laminas-escaper": "^2.2", "phpoffice/common": "^0.2.9" }, "require-dev": { "ext-zip": "*", "ext-gd": "*", "phpunit/phpunit": "^4.8.36 || ^7.0", - "squizlabs/php_codesniffer": "^2.9", + "squizlabs/php_codesniffer": "^2.9 || ^3.5", "friendsofphp/php-cs-fixer": "^2.2", "phpmd/phpmd": "2.*", - "phploc/phploc": "2.* || 3.* || 4.*", + "phploc/phploc": "2.* || 3.* || 4.* || 5.* || 6.* || 7.*", "dompdf/dompdf":"0.8.*", "tecnickcom/tcpdf": "6.*", - "mpdf/mpdf": "5.7.4 || 6.* || 7.*", + "mpdf/mpdf": "5.7.4 || 6.* || 7.* || 8.*", "php-coveralls/php-coveralls": "1.1.0 || ^2.0" }, + "replace": { + "laminas/laminas-zendframework-bridge": "*" + }, "suggest": { "ext-zip": "Allows writing OOXML and ODF", "ext-gd2": "Allows adding images", diff --git a/docs/installing.rst b/docs/installing.rst index 2a9582d067..baf966bd0e 100644 --- a/docs/installing.rst +++ b/docs/installing.rst @@ -10,9 +10,7 @@ Mandatory: - PHP 5.3.3+ - `XML Parser `__ extension -- `Zend\\Escaper `__ component -- Zend\\Stdlib component -- `Zend\\Validator `__ component +- `Laminas Escaper `__ component Optional: diff --git a/phpmd.xml.dist b/phpmd.xml.dist index 2077e02b04..cfb9353b57 100644 --- a/phpmd.xml.dist +++ b/phpmd.xml.dist @@ -5,6 +5,8 @@ xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd" xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd"> + + diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index 0c773dbe69..6a1ed93013 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -109,6 +109,7 @@ public function __call($function, $args) } else { // All other elements array_unshift($args, $element); // Prepend element name to the beginning of args array + return call_user_func_array(array($this, 'addElement'), $args); } } diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index bae87ff5d8..2e25fd18e5 100644 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -454,7 +454,7 @@ private function setSourceType() } else { $this->sourceType = self::SOURCE_GD; } - } elseif (@file_exists($this->source)) { + } elseif ((strpos($this->source, chr(0)) === false) && @file_exists($this->source)) { $this->memoryImage = false; $this->sourceType = self::SOURCE_LOCAL; } else { diff --git a/src/PhpWord/Reader/MsDoc.php b/src/PhpWord/Reader/MsDoc.php index 1a9e4988bf..eb64e00ae9 100644 --- a/src/PhpWord/Reader/MsDoc.php +++ b/src/PhpWord/Reader/MsDoc.php @@ -1581,7 +1581,7 @@ private function readPrl($data, $pos, $cbNum) // Variables $sprmCPicLocation = null; $sprmCFData = null; - $sprmCFSpec = null; + //$sprmCFSpec = null; do { // Variables @@ -1830,7 +1830,7 @@ private function readPrl($data, $pos, $cbNum) break; // sprmCFSpec case 0x55: - $sprmCFSpec = $operand; + //$sprmCFSpec = $operand; break; // sprmCFtcBi case 0x5E: @@ -2094,11 +2094,11 @@ private function readPrl($data, $pos, $cbNum) $sprmCPicLocation += 1; // stPicName - $stPicName = ''; + //$stPicName = ''; for ($inc = 0; $inc <= $cchPicName; $inc++) { - $chr = self::getInt1d($this->dataData, $sprmCPicLocation); + //$chr = self::getInt1d($this->dataData, $sprmCPicLocation); $sprmCPicLocation += 1; - $stPicName .= chr($chr); + //$stPicName .= chr($chr); } } @@ -2143,11 +2143,11 @@ private function readPrl($data, $pos, $cbNum) $sprmCPicLocation += 1; // nameData if ($cbName > 0) { - $nameData = ''; + //$nameData = ''; for ($inc = 0; $inc <= ($cbName / 2); $inc++) { - $chr = self::getInt2d($this->dataData, $sprmCPicLocation); + //$chr = self::getInt2d($this->dataData, $sprmCPicLocation); $sprmCPicLocation += 2; - $nameData .= chr($chr); + //$nameData .= chr($chr); } } // embeddedBlip diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 06dfe37bb8..eab659fa83 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -573,11 +573,11 @@ private function readCellStyle(XMLReader $xmlReader, \DOMElement $domNode) * Returns the first child element found * * @param XMLReader $xmlReader - * @param \DOMElement $parentNode - * @param string|array $elements + * @param \DOMElement|null $parentNode + * @param string|array|null $elements * @return string|null */ - private function findPossibleElement(XMLReader $xmlReader, \DOMElement $parentNode = null, $elements) + private function findPossibleElement(XMLReader $xmlReader, \DOMElement $parentNode = null, $elements = null) { if (is_array($elements)) { //if element is an array, we take the first element that exists in the XML diff --git a/src/PhpWord/Shared/Converter.php b/src/PhpWord/Shared/Converter.php index 39e8054543..05755ef796 100644 --- a/src/PhpWord/Shared/Converter.php +++ b/src/PhpWord/Shared/Converter.php @@ -338,9 +338,9 @@ public static function htmlToRgb($value) return false; } - $red = hexdec($red); - $green = hexdec($green); - $blue = hexdec($blue); + $red = ctype_xdigit($red) ? hexdec($red) : 0; + $green = ctype_xdigit($green) ? hexdec($green) : 0; + $blue = ctype_xdigit($blue) ? hexdec($blue) : 0; return array($red, $green, $blue); } diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 54e9509e5f..252665e759 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -72,7 +72,9 @@ public static function addHtml($element, $html, $fullHTML = false, $preserveWhit } // Load DOM - $orignalLibEntityLoader = libxml_disable_entity_loader(true); + if (\PHP_VERSION_ID < 80000) { + $orignalLibEntityLoader = libxml_disable_entity_loader(true); + } $dom = new \DOMDocument(); $dom->preserveWhiteSpace = $preserveWhiteSpace; $dom->loadXML($html); @@ -80,7 +82,9 @@ public static function addHtml($element, $html, $fullHTML = false, $preserveWhit $node = $dom->getElementsByTagName('body'); self::parseNode($node->item(0), $element); - libxml_disable_entity_loader($orignalLibEntityLoader); + if (\PHP_VERSION_ID < 80000) { + libxml_disable_entity_loader($orignalLibEntityLoader); + } } /** @@ -178,7 +182,7 @@ protected static function parseNode($node, $element, $styles = array(), $data = } } $method = "parse{$method}"; - $newElement = call_user_func_array(array('PhpOffice\PhpWord\Shared\Html', $method), $arguments); + $newElement = call_user_func_array(array('PhpOffice\PhpWord\Shared\Html', $method), array_values($arguments)); // Retrieve back variables from arguments foreach ($keys as $key) { diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 7efc0f1ac8..8aadb8c573 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -170,7 +170,9 @@ protected function readPartWithRels($fileName) */ protected function transformSingleXml($xml, $xsltProcessor) { - $orignalLibEntityLoader = libxml_disable_entity_loader(true); + if (\PHP_VERSION_ID < 80000) { + $orignalLibEntityLoader = libxml_disable_entity_loader(true); + } $domDocument = new \DOMDocument(); if (false === $domDocument->loadXML($xml)) { throw new Exception('Could not load the given XML document.'); @@ -180,7 +182,9 @@ protected function transformSingleXml($xml, $xsltProcessor) if (false === $transformedXml) { throw new Exception('Could not transform the given XML document.'); } - libxml_disable_entity_loader($orignalLibEntityLoader); + if (\PHP_VERSION_ID < 80000) { + libxml_disable_entity_loader($orignalLibEntityLoader); + } return $transformedXml; } diff --git a/src/PhpWord/Writer/HTML/Element/AbstractElement.php b/src/PhpWord/Writer/HTML/Element/AbstractElement.php index dc5ccfaadc..30d1ccaa4c 100644 --- a/src/PhpWord/Writer/HTML/Element/AbstractElement.php +++ b/src/PhpWord/Writer/HTML/Element/AbstractElement.php @@ -17,9 +17,9 @@ namespace PhpOffice\PhpWord\Writer\HTML\Element; +use Laminas\Escaper\Escaper; use PhpOffice\PhpWord\Element\AbstractElement as Element; use PhpOffice\PhpWord\Writer\AbstractWriter; -use Zend\Escaper\Escaper; /** * Abstract HTML element writer @@ -50,7 +50,7 @@ abstract class AbstractElement protected $withoutP = false; /** - * @var \Zend\Escaper\Escaper|\PhpOffice\PhpWord\Escaper\AbstractEscaper + * @var \Laminas\Escaper\Escaper|\PhpOffice\PhpWord\Escaper\AbstractEscaper */ protected $escaper; diff --git a/src/PhpWord/Writer/HTML/Part/AbstractPart.php b/src/PhpWord/Writer/HTML/Part/AbstractPart.php index 2d86f399b0..97c763759a 100644 --- a/src/PhpWord/Writer/HTML/Part/AbstractPart.php +++ b/src/PhpWord/Writer/HTML/Part/AbstractPart.php @@ -17,9 +17,9 @@ namespace PhpOffice\PhpWord\Writer\HTML\Part; +use Laminas\Escaper\Escaper; use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\Writer\AbstractWriter; -use Zend\Escaper\Escaper; /** * @since 0.11.0 @@ -32,7 +32,7 @@ abstract class AbstractPart private $parentWriter; /** - * @var \Zend\Escaper\Escaper + * @var \Laminas\Escaper\Escaper */ protected $escaper; diff --git a/tests/PhpWord/Element/TableTest.php b/tests/PhpWord/Element/TableTest.php index 8ae5306c82..17aa13a38f 100644 --- a/tests/PhpWord/Element/TableTest.php +++ b/tests/PhpWord/Element/TableTest.php @@ -99,10 +99,10 @@ public function testCountColumns() { $oTable = new Table(); $oTable->addRow(); - $element = $oTable->addCell(); + $oTable->addCell(); $this->assertEquals($oTable->countColumns(), 1); - $element = $oTable->addCell(); - $element = $oTable->addCell(); + $oTable->addCell(); + $oTable->addCell(); $this->assertEquals($oTable->countColumns(), 3); } } diff --git a/tests/PhpWord/TemplateProcessorTest.php b/tests/PhpWord/TemplateProcessorTest.php index 4caca77aeb..5b922f714a 100644 --- a/tests/PhpWord/TemplateProcessorTest.php +++ b/tests/PhpWord/TemplateProcessorTest.php @@ -140,6 +140,11 @@ final public function testXslStyleSheetCanBeApplied($actualDocumentFqfn) */ final public function testXslStyleSheetCanNotBeAppliedOnFailureOfSettingParameterValue() { + // Test is not needed for PHP 8.0, because internally validation throws TypeError exception. + if (\PHP_VERSION_ID >= 80000) { + $this->markTestSkipped('not needed for PHP 8.0'); + } + $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/blank.docx'); $xslDomDocument = new \DOMDocument(); diff --git a/tests/PhpWord/Writer/PDF/TCPDFTest.php b/tests/PhpWord/Writer/PDF/TCPDFTest.php index 6dc8f24cb7..c8f5d2223e 100644 --- a/tests/PhpWord/Writer/PDF/TCPDFTest.php +++ b/tests/PhpWord/Writer/PDF/TCPDFTest.php @@ -33,6 +33,12 @@ class TCPDFTest extends \PHPUnit\Framework\TestCase */ public function testConstruct() { + // TCPDF version 6.3.5 doesn't support PHP 5.3, fixed via https://github.com/tecnickcom/TCPDF/pull/197, + // pending new release. + if (version_compare(PHP_VERSION, '5.4.0', '<')) { + return; + } + $file = __DIR__ . '/../../_files/tcpdf.pdf'; $phpWord = new PhpWord(); diff --git a/tests/PhpWord/_includes/XmlDocument.php b/tests/PhpWord/_includes/XmlDocument.php index 3a7869bcea..14735511ec 100644 --- a/tests/PhpWord/_includes/XmlDocument.php +++ b/tests/PhpWord/_includes/XmlDocument.php @@ -76,10 +76,14 @@ public function getFileDom($file = 'word/document.xml') $this->file = $file; $file = $this->path . '/' . $file; - $orignalLibEntityLoader = libxml_disable_entity_loader(false); + if (\PHP_VERSION_ID < 80000) { + $orignalLibEntityLoader = libxml_disable_entity_loader(false); + } $this->dom = new \DOMDocument(); $this->dom->load($file); - libxml_disable_entity_loader($orignalLibEntityLoader); + if (\PHP_VERSION_ID < 80000) { + libxml_disable_entity_loader($orignalLibEntityLoader); + } return $this->dom; }