From ff005f6edc4d55f03d756c2d25141c4278286137 Mon Sep 17 00:00:00 2001 From: Kieran <kieran@supportpal.com> Date: Wed, 19 Mar 2025 18:25:28 +0100 Subject: [PATCH] feat: PHP 8.4 support (#441) --- .github/workflows/ci.yml | 2 +- configdoc/generate.php | 2 +- .../HTMLPurifier/AttrDef/HTML/LinkTypes.php | 7 +------ library/HTMLPurifier/AttrTypes.php | 2 +- library/HTMLPurifier/Config.php | 6 +++++- library/HTMLPurifier/ConfigSchema.php | 2 +- library/HTMLPurifier/ContentSets.php | 5 ++--- library/HTMLPurifier/Context.php | 17 +++-------------- library/HTMLPurifier/DoctypeRegistry.php | 2 +- library/HTMLPurifier/Encoder.php | 18 ++++++++---------- library/HTMLPurifier/HTMLDefinition.php | 11 +++-------- library/HTMLPurifier/HTMLModule/Tidy.php | 8 +++----- library/HTMLPurifier/HTMLModuleManager.php | 6 +----- library/HTMLPurifier/LanguageFactory.php | 8 +------- library/HTMLPurifier/Lexer.php | 2 +- library/HTMLPurifier/URIScheme/data.php | 2 +- tests/HTMLPurifier/AttrTypesTest.php | 2 +- .../ChildDef/StrictBlockquoteTest.php | 2 +- tests/HTMLPurifier/ConfigTest.php | 4 ++-- tests/HTMLPurifier/ContextTest.php | 6 +++--- tests/HTMLPurifier/DoctypeRegistryTest.php | 2 +- tests/HTMLPurifier/EncoderTest.php | 2 +- tests/HTMLPurifier/HTMLModule/TidyTest.php | 2 +- tests/HTMLPurifier/Strategy/FixNestingTest.php | 2 +- tests/common.php | 2 +- tests/index.php | 5 ++--- 26 files changed, 48 insertions(+), 81 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f88d30a7..67307784 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,7 +10,7 @@ jobs: strategy: fail-fast: true matrix: - php: ['5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3'] + php: ['5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3', '8.4'] name: PHP ${{ matrix.php }} diff --git a/configdoc/generate.php b/configdoc/generate.php index e0c4e674..275415af 100644 --- a/configdoc/generate.php +++ b/configdoc/generate.php @@ -16,7 +16,7 @@ TODO: */ if (version_compare(PHP_VERSION, '5.2', '<')) exit('PHP 5.2+ required.'); -error_reporting(E_ALL | E_STRICT); +error_reporting(E_ALL); // load dual-libraries require_once dirname(__FILE__) . '/../extras/HTMLPurifierExtras.auto.php'; diff --git a/library/HTMLPurifier/AttrDef/HTML/LinkTypes.php b/library/HTMLPurifier/AttrDef/HTML/LinkTypes.php index 63fa04c1..3decf0c4 100644 --- a/library/HTMLPurifier/AttrDef/HTML/LinkTypes.php +++ b/library/HTMLPurifier/AttrDef/HTML/LinkTypes.php @@ -25,12 +25,7 @@ class HTMLPurifier_AttrDef_HTML_LinkTypes extends HTMLPurifier_AttrDef 'rev' => 'AllowedRev' ); if (!isset($configLookup[$name])) { - trigger_error( - 'Unrecognized attribute name for link ' . - 'relationship.', - E_USER_ERROR - ); - return; + throw new Exception('Unrecognized attribute name for link relationship.'); } $this->name = $configLookup[$name]; } diff --git a/library/HTMLPurifier/AttrTypes.php b/library/HTMLPurifier/AttrTypes.php index e4429e86..62575ca6 100644 --- a/library/HTMLPurifier/AttrTypes.php +++ b/library/HTMLPurifier/AttrTypes.php @@ -77,7 +77,7 @@ class HTMLPurifier_AttrTypes } if (!isset($this->info[$type])) { - trigger_error('Cannot retrieve undefined attribute type ' . $type, E_USER_ERROR); + throw new Exception('Cannot retrieve undefined attribute type ' . $type); return; } return $this->info[$type]->make($string); diff --git a/library/HTMLPurifier/Config.php b/library/HTMLPurifier/Config.php index e6566e80..37470c8c 100644 --- a/library/HTMLPurifier/Config.php +++ b/library/HTMLPurifier/Config.php @@ -898,7 +898,11 @@ class HTMLPurifier_Config break; } } - trigger_error($msg . $extra, $no); + if ($no == E_USER_ERROR) { + throw new Exception($msg . $extra); + } else { + trigger_error($msg . $extra, $no); + } } /** diff --git a/library/HTMLPurifier/ConfigSchema.php b/library/HTMLPurifier/ConfigSchema.php index c3fe8cd4..42f66047 100644 --- a/library/HTMLPurifier/ConfigSchema.php +++ b/library/HTMLPurifier/ConfigSchema.php @@ -72,7 +72,7 @@ class HTMLPurifier_ConfigSchema $r = unserialize($contents); if (!$r) { $hash = sha1($contents); - trigger_error("Unserialization of configuration schema failed, sha1 of file was $hash", E_USER_ERROR); + throw new Exception("Unserialization of configuration schema failed, sha1 of file was $hash"); } return $r; } diff --git a/library/HTMLPurifier/ContentSets.php b/library/HTMLPurifier/ContentSets.php index 543e3f8f..d3429952 100644 --- a/library/HTMLPurifier/ContentSets.php +++ b/library/HTMLPurifier/ContentSets.php @@ -142,12 +142,11 @@ class HTMLPurifier_ContentSets if ($return !== false) { return $return; } - // error-out - trigger_error( + + throw new Exception( 'Could not determine which ChildDef class to instantiate', E_USER_ERROR ); - return false; } /** diff --git a/library/HTMLPurifier/Context.php b/library/HTMLPurifier/Context.php index 00e509c8..5a0e7b91 100644 --- a/library/HTMLPurifier/Context.php +++ b/library/HTMLPurifier/Context.php @@ -24,11 +24,7 @@ class HTMLPurifier_Context public function register($name, &$ref) { if (array_key_exists($name, $this->_storage)) { - trigger_error( - "Name $name produces collision, cannot re-register", - E_USER_ERROR - ); - return; + throw new Exception("Name $name produces collision, cannot re-register"); } $this->_storage[$name] =& $ref; } @@ -43,10 +39,7 @@ class HTMLPurifier_Context { if (!array_key_exists($name, $this->_storage)) { if (!$ignore_error) { - trigger_error( - "Attempted to retrieve non-existent variable $name", - E_USER_ERROR - ); + throw new Exception("Attempted to retrieve non-existent variable $name"); } $var = null; // so we can return by reference return $var; @@ -61,11 +54,7 @@ class HTMLPurifier_Context public function destroy($name) { if (!array_key_exists($name, $this->_storage)) { - trigger_error( - "Attempted to destroy non-existent variable $name", - E_USER_ERROR - ); - return; + throw new Exception("Attempted to destroy non-existent variable $name"); } unset($this->_storage[$name]); } diff --git a/library/HTMLPurifier/DoctypeRegistry.php b/library/HTMLPurifier/DoctypeRegistry.php index acc1d64a..9ad7b4b1 100644 --- a/library/HTMLPurifier/DoctypeRegistry.php +++ b/library/HTMLPurifier/DoctypeRegistry.php @@ -86,7 +86,7 @@ class HTMLPurifier_DoctypeRegistry $doctype = $this->aliases[$doctype]; } if (!isset($this->doctypes[$doctype])) { - trigger_error('Doctype ' . htmlspecialchars($doctype) . ' does not exist', E_USER_ERROR); + throw new Exception('Doctype ' . htmlspecialchars($doctype) . ' does not exist'); $anon = new HTMLPurifier_Doctype($doctype); return $anon; } diff --git a/library/HTMLPurifier/Encoder.php b/library/HTMLPurifier/Encoder.php index d4791cc1..910181b2 100644 --- a/library/HTMLPurifier/Encoder.php +++ b/library/HTMLPurifier/Encoder.php @@ -12,7 +12,7 @@ class HTMLPurifier_Encoder */ private function __construct() { - trigger_error('Cannot instantiate encoder, call methods statically', E_USER_ERROR); + throw new Exception('Cannot instantiate encoder, call methods statically'); } /** @@ -390,7 +390,7 @@ class HTMLPurifier_Encoder $str = self::unsafeIconv($encoding, 'utf-8//IGNORE', $str); if ($str === false) { // $encoding is not a valid encoding - trigger_error('Invalid encoding ' . $encoding, E_USER_ERROR); + throw new Exception('Invalid encoding ' . $encoding); return ''; } // If the string is bjorked by Shift_JIS or a similar encoding @@ -404,12 +404,11 @@ class HTMLPurifier_Encoder } $bug = HTMLPurifier_Encoder::testIconvTruncateBug(); if ($bug == self::ICONV_OK) { - trigger_error('Encoding not supported, please install iconv', E_USER_ERROR); + throw new Exception('Encoding not supported, please install iconv'); } else { - trigger_error( + throw new Exception( 'You have a buggy version of iconv, see https://bugs.php.net/bug.php?id=48147 ' . - 'and http://sourceware.org/bugzilla/show_bug.cgi?id=13541', - E_USER_ERROR + 'and http://sourceware.org/bugzilla/show_bug.cgi?id=13541' ); } } @@ -454,7 +453,7 @@ class HTMLPurifier_Encoder $str = mb_convert_encoding($str, 'ISO-8859-1', 'UTF-8'); return $str; } - trigger_error('Encoding not supported', E_USER_ERROR); + throw new Exception('Encoding not supported'); // You might be tempted to assume that the ASCII representation // might be OK, however, this is *not* universally true over all // encodings. So we take the conservative route here, rather @@ -545,10 +544,9 @@ class HTMLPurifier_Encoder } elseif (($c = strlen($r)) < 9000) { $code = self::ICONV_TRUNCATES; } elseif ($c > 9000) { - trigger_error( + throw new Exception( 'Your copy of iconv is extremely buggy. Please notify HTML Purifier maintainers: ' . - 'include your iconv version as per phpversion()', - E_USER_ERROR + 'include your iconv version as per phpversion()' ); } else { $code = self::ICONV_OK; diff --git a/library/HTMLPurifier/HTMLDefinition.php b/library/HTMLPurifier/HTMLDefinition.php index 9b7b334d..dc2c33c7 100644 --- a/library/HTMLPurifier/HTMLDefinition.php +++ b/library/HTMLPurifier/HTMLDefinition.php @@ -264,9 +264,8 @@ class HTMLPurifier_HTMLDefinition extends HTMLPurifier_Definition if (isset($this->info_content_sets['Block'][$block_wrapper])) { $this->info_block_wrapper = $block_wrapper; } else { - trigger_error( - 'Cannot use non-block element as block wrapper', - E_USER_ERROR + throw new Exception( + 'Cannot use non-block element as block wrapper' ); } @@ -276,11 +275,7 @@ class HTMLPurifier_HTMLDefinition extends HTMLPurifier_Definition $this->info_parent = $parent; $this->info_parent_def = $def; } else { - trigger_error( - 'Cannot use unrecognized element as parent', - E_USER_ERROR - ); - $this->info_parent_def = $this->manager->getElement($this->info_parent, true); + throw new Exception('Cannot use unrecognized element as parent'); } // support template text diff --git a/library/HTMLPurifier/HTMLModule/Tidy.php b/library/HTMLPurifier/HTMLModule/Tidy.php index 76fd93a6..bd926dc2 100644 --- a/library/HTMLPurifier/HTMLModule/Tidy.php +++ b/library/HTMLPurifier/HTMLModule/Tidy.php @@ -112,9 +112,8 @@ class HTMLPurifier_HTMLModule_Tidy extends HTMLPurifier_HTMLModule return; } if (!isset($this->fixesForLevel[$this->defaultLevel])) { - trigger_error( - 'Default level ' . $this->defaultLevel . ' does not exist', - E_USER_ERROR + throw new Exception( + 'Default level ' . $this->defaultLevel . ' does not exist' ); return; } @@ -162,8 +161,7 @@ class HTMLPurifier_HTMLModule_Tidy extends HTMLPurifier_HTMLModule $e->$type = $fix; break; default: - trigger_error("Fix type $type not supported", E_USER_ERROR); - break; + throw new Exception("Fix type $type not supported"); } } } diff --git a/library/HTMLPurifier/HTMLModuleManager.php b/library/HTMLPurifier/HTMLModuleManager.php index 38c058fe..fc6927a3 100644 --- a/library/HTMLPurifier/HTMLModuleManager.php +++ b/library/HTMLPurifier/HTMLModuleManager.php @@ -183,11 +183,7 @@ class HTMLPurifier_HTMLModuleManager if (!$ok) { $module = $original_module; if (!class_exists($module)) { - trigger_error( - $original_module . ' module does not exist', - E_USER_ERROR - ); - return; + throw new Exception($original_module . ' module does not exist'); } } $module = new $module(); diff --git a/library/HTMLPurifier/LanguageFactory.php b/library/HTMLPurifier/LanguageFactory.php index 16a4f693..2f90a45c 100644 --- a/library/HTMLPurifier/LanguageFactory.php +++ b/library/HTMLPurifier/LanguageFactory.php @@ -173,14 +173,8 @@ class HTMLPurifier_LanguageFactory // infinite recursion guard if (isset($languages_seen[$code])) { - trigger_error( - 'Circular fallback reference in language ' . - $code, - E_USER_ERROR - ); - $fallback = 'en'; + throw new Exception('Circular fallback reference in language ' . $code); } - $language_seen[$code] = true; // load the fallback recursively $this->loadLanguage($fallback); diff --git a/library/HTMLPurifier/Lexer.php b/library/HTMLPurifier/Lexer.php index fe87fa4b..793edc89 100644 --- a/library/HTMLPurifier/Lexer.php +++ b/library/HTMLPurifier/Lexer.php @@ -238,7 +238,7 @@ class HTMLPurifier_Lexer */ public function tokenizeHTML($string, $config, $context) { - trigger_error('Call to abstract class', E_USER_ERROR); + throw new Exception('Call to abstract class'); } /** diff --git a/library/HTMLPurifier/URIScheme/data.php b/library/HTMLPurifier/URIScheme/data.php index 41c49d55..02e540cb 100644 --- a/library/HTMLPurifier/URIScheme/data.php +++ b/library/HTMLPurifier/URIScheme/data.php @@ -105,7 +105,7 @@ class HTMLPurifier_URIScheme_data extends HTMLPurifier_URIScheme } $image_code = $info[2]; } else { - trigger_error("could not find exif_imagetype or getimagesize functions", E_USER_ERROR); + throw new Exception("could not find exif_imagetype or getimagesize functions"); } $real_content_type = image_type_to_mime_type($image_code); if ($real_content_type != $content_type) { diff --git a/tests/HTMLPurifier/AttrTypesTest.php b/tests/HTMLPurifier/AttrTypesTest.php index 4881ac7b..8cd03d0f 100644 --- a/tests/HTMLPurifier/AttrTypesTest.php +++ b/tests/HTMLPurifier/AttrTypesTest.php @@ -12,7 +12,7 @@ class HTMLPurifier_AttrTypesTest extends HTMLPurifier_Harness new HTMLPurifier_AttrDef_Text() ); - $this->expectError('Cannot retrieve undefined attribute type foobar'); + $this->expectException(new Exception('Cannot retrieve undefined attribute type foobar')); $types->get('foobar'); $this->assertIdentical( diff --git a/tests/HTMLPurifier/ChildDef/StrictBlockquoteTest.php b/tests/HTMLPurifier/ChildDef/StrictBlockquoteTest.php index 0d74d334..cab3cb7f 100644 --- a/tests/HTMLPurifier/ChildDef/StrictBlockquoteTest.php +++ b/tests/HTMLPurifier/ChildDef/StrictBlockquoteTest.php @@ -84,7 +84,7 @@ extends HTMLPurifier_ChildDefHarness public function testError() { - $this->expectError('Cannot use non-block element as block wrapper'); + $this->expectException(new Exception('Cannot use non-block element as block wrapper')); $this->obj = new HTMLPurifier_ChildDef_StrictBlockquote('div | p'); $this->config->set('HTML.BlockWrapper', 'dav'); $this->config->set('Cache.DefinitionImpl', null); diff --git a/tests/HTMLPurifier/ConfigTest.php b/tests/HTMLPurifier/ConfigTest.php index 5b2ccd69..73397c3a 100644 --- a/tests/HTMLPurifier/ConfigTest.php +++ b/tests/HTMLPurifier/ConfigTest.php @@ -155,7 +155,7 @@ class HTMLPurifier_ConfigTest extends HTMLPurifier_Harness $this->assertIdentical($config->get('Home.Rug'), 3); - $this->expectError('Cannot get value from aliased directive, use real name Home.Rug'); + $this->expectException(new Exception('Cannot get value from aliased directive, use real name Home.Rug')); $config->get('Home.Carpet'); $this->expectError('Home.Carpet is an alias, preferred directive name is Home.Rug'); @@ -384,7 +384,7 @@ class HTMLPurifier_ConfigTest extends HTMLPurifier_Harness $config->finalize(); - $this->expectError('Cannot set directive after finalization'); + $this->expectException(new Exception('Cannot set directive after finalization')); $config->set('Poem.Meter', 'vedic'); $this->expectError('Cannot load directives after finalization'); diff --git a/tests/HTMLPurifier/ContextTest.php b/tests/HTMLPurifier/ContextTest.php index 8baaf27e..2cbd8011 100644 --- a/tests/HTMLPurifier/ContextTest.php +++ b/tests/HTMLPurifier/ContextTest.php @@ -27,11 +27,11 @@ class HTMLPurifier_ContextTest extends HTMLPurifier_Harness $this->context->destroy('IDAccumulator'); $this->assertFalse($this->context->exists('IDAccumulator')); - $this->expectError('Attempted to retrieve non-existent variable IDAccumulator'); + $this->expectException(new Exception('Attempted to retrieve non-existent variable IDAccumulator')); $accumulator_3 =& $this->context->get('IDAccumulator'); $this->assertNull($accumulator_3); - $this->expectError('Attempted to destroy non-existent variable IDAccumulator'); + $this->expectException(new Exception('Attempted to destroy non-existent variable IDAccumulator')); $this->context->destroy('IDAccumulator'); } @@ -41,7 +41,7 @@ class HTMLPurifier_ContextTest extends HTMLPurifier_Harness $var = true; $this->context->register('OnceOnly', $var); - $this->expectError('Name OnceOnly produces collision, cannot re-register'); + $this->expectException(new Exception('Name OnceOnly produces collision, cannot re-register')); $this->context->register('OnceOnly', $var); // destroy it, now registration is okay diff --git a/tests/HTMLPurifier/DoctypeRegistryTest.php b/tests/HTMLPurifier/DoctypeRegistryTest.php index b1012b1b..0b704b32 100644 --- a/tests/HTMLPurifier/DoctypeRegistryTest.php +++ b/tests/HTMLPurifier/DoctypeRegistryTest.php @@ -36,7 +36,7 @@ class HTMLPurifier_DoctypeRegistryTest extends HTMLPurifier_Harness $registry = new HTMLPurifier_DoctypeRegistry(); - $this->expectError('Doctype XHTML 2.0 does not exist'); + $this->expectException(new Exception('Doctype XHTML 2.0 does not exist')); $registry->get('XHTML 2.0'); // prevent XSS diff --git a/tests/HTMLPurifier/EncoderTest.php b/tests/HTMLPurifier/EncoderTest.php index c43e4240..238d25ae 100644 --- a/tests/HTMLPurifier/EncoderTest.php +++ b/tests/HTMLPurifier/EncoderTest.php @@ -47,7 +47,7 @@ class HTMLPurifier_EncoderTest extends HTMLPurifier_Harness { if (!HTMLPurifier_Encoder::iconvAvailable()) return; $this->config->set('Core.Encoding', 'utf99'); - $this->expectError('Invalid encoding utf99'); + $this->expectException(new Exception('Invalid encoding utf99')); $this->assertIdentical( HTMLPurifier_Encoder::convertToUTF8("\xF6", $this->config, $this->context), '' diff --git a/tests/HTMLPurifier/HTMLModule/TidyTest.php b/tests/HTMLPurifier/HTMLModule/TidyTest.php index 2a87ecec..47ec65cb 100644 --- a/tests/HTMLPurifier/HTMLModule/TidyTest.php +++ b/tests/HTMLPurifier/HTMLModule/TidyTest.php @@ -134,7 +134,7 @@ class HTMLPurifier_HTMLModule_TidyTest extends HTMLPurifier_Harness $module = new HTMLPurifier_HTMLModule_Tidy(); $module->defaultLevel = 'bananas'; - $this->expectError('Default level bananas does not exist'); + $this->expectException(new Exception('Default level bananas does not exist')); $module->makeFixesForLevel(array( 'fix-1' => 0 diff --git a/tests/HTMLPurifier/Strategy/FixNestingTest.php b/tests/HTMLPurifier/Strategy/FixNestingTest.php index 9e390745..094ffb0b 100644 --- a/tests/HTMLPurifier/Strategy/FixNestingTest.php +++ b/tests/HTMLPurifier/Strategy/FixNestingTest.php @@ -115,7 +115,7 @@ class HTMLPurifier_Strategy_FixNestingTest extends HTMLPurifier_StrategyHarness // test fallback to div $this->config->set('HTML.Parent', 'obviously-impossible'); $this->config->set('Cache.DefinitionImpl', null); - $this->expectError('Cannot use unrecognized element as parent'); + $this->expectException(new Exception('Cannot use unrecognized element as parent')); $this->assertResult('<div>Accept</div>'); } diff --git a/tests/common.php b/tests/common.php index db416ffa..7c914115 100644 --- a/tests/common.php +++ b/tests/common.php @@ -48,7 +48,7 @@ if ( is_string($GLOBALS['HTMLPurifierTest']['PEAR']) ) { } // after external libraries are loaded, turn on compile time errors -error_reporting(E_ALL | E_STRICT); +error_reporting(E_ALL); // initialize extra HTML Purifier libraries require '../extras/HTMLPurifierExtras.auto.php'; diff --git a/tests/index.php b/tests/index.php index d0fe4fa2..07914335 100644 --- a/tests/index.php +++ b/tests/index.php @@ -23,9 +23,8 @@ * $test_files) do not have underscores in their names. */ -// HTML Purifier runs error free on E_STRICT, so if code reports -// errors, we want to know about it. -error_reporting(E_ALL | E_STRICT); +// HTML Purifier runs error free. +error_reporting(E_ALL); // Because we always want to know about errors, and because SimpleTest // will notify us about them, logging the errors to stderr is