1
0
mirror of https://github.com/ezyang/htmlpurifier.git synced 2025-08-02 20:27:40 +02:00

feat: PHP 8.4 support (#441)

This commit is contained in:
Kieran
2025-03-19 18:25:28 +01:00
committed by GitHub
parent c2bc3549a3
commit ff005f6edc
26 changed files with 48 additions and 81 deletions

View File

@@ -10,7 +10,7 @@ jobs:
strategy: strategy:
fail-fast: true fail-fast: true
matrix: 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 }} name: PHP ${{ matrix.php }}

View File

@@ -16,7 +16,7 @@ TODO:
*/ */
if (version_compare(PHP_VERSION, '5.2', '<')) exit('PHP 5.2+ required.'); 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 // load dual-libraries
require_once dirname(__FILE__) . '/../extras/HTMLPurifierExtras.auto.php'; require_once dirname(__FILE__) . '/../extras/HTMLPurifierExtras.auto.php';

View File

@@ -25,12 +25,7 @@ class HTMLPurifier_AttrDef_HTML_LinkTypes extends HTMLPurifier_AttrDef
'rev' => 'AllowedRev' 'rev' => 'AllowedRev'
); );
if (!isset($configLookup[$name])) { if (!isset($configLookup[$name])) {
trigger_error( throw new Exception('Unrecognized attribute name for link relationship.');
'Unrecognized attribute name for link ' .
'relationship.',
E_USER_ERROR
);
return;
} }
$this->name = $configLookup[$name]; $this->name = $configLookup[$name];
} }

View File

@@ -77,7 +77,7 @@ class HTMLPurifier_AttrTypes
} }
if (!isset($this->info[$type])) { 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;
} }
return $this->info[$type]->make($string); return $this->info[$type]->make($string);

View File

@@ -898,8 +898,12 @@ class HTMLPurifier_Config
break; break;
} }
} }
if ($no == E_USER_ERROR) {
throw new Exception($msg . $extra);
} else {
trigger_error($msg . $extra, $no); trigger_error($msg . $extra, $no);
} }
}
/** /**
* Returns a serialized form of the configuration object that can * Returns a serialized form of the configuration object that can

View File

@@ -72,7 +72,7 @@ class HTMLPurifier_ConfigSchema
$r = unserialize($contents); $r = unserialize($contents);
if (!$r) { if (!$r) {
$hash = sha1($contents); $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; return $r;
} }

View File

@@ -142,12 +142,11 @@ class HTMLPurifier_ContentSets
if ($return !== false) { if ($return !== false) {
return $return; return $return;
} }
// error-out
trigger_error( throw new Exception(
'Could not determine which ChildDef class to instantiate', 'Could not determine which ChildDef class to instantiate',
E_USER_ERROR E_USER_ERROR
); );
return false;
} }
/** /**

View File

@@ -24,11 +24,7 @@ class HTMLPurifier_Context
public function register($name, &$ref) public function register($name, &$ref)
{ {
if (array_key_exists($name, $this->_storage)) { if (array_key_exists($name, $this->_storage)) {
trigger_error( throw new Exception("Name $name produces collision, cannot re-register");
"Name $name produces collision, cannot re-register",
E_USER_ERROR
);
return;
} }
$this->_storage[$name] =& $ref; $this->_storage[$name] =& $ref;
} }
@@ -43,10 +39,7 @@ class HTMLPurifier_Context
{ {
if (!array_key_exists($name, $this->_storage)) { if (!array_key_exists($name, $this->_storage)) {
if (!$ignore_error) { if (!$ignore_error) {
trigger_error( throw new Exception("Attempted to retrieve non-existent variable $name");
"Attempted to retrieve non-existent variable $name",
E_USER_ERROR
);
} }
$var = null; // so we can return by reference $var = null; // so we can return by reference
return $var; return $var;
@@ -61,11 +54,7 @@ class HTMLPurifier_Context
public function destroy($name) public function destroy($name)
{ {
if (!array_key_exists($name, $this->_storage)) { if (!array_key_exists($name, $this->_storage)) {
trigger_error( throw new Exception("Attempted to destroy non-existent variable $name");
"Attempted to destroy non-existent variable $name",
E_USER_ERROR
);
return;
} }
unset($this->_storage[$name]); unset($this->_storage[$name]);
} }

View File

@@ -86,7 +86,7 @@ class HTMLPurifier_DoctypeRegistry
$doctype = $this->aliases[$doctype]; $doctype = $this->aliases[$doctype];
} }
if (!isset($this->doctypes[$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); $anon = new HTMLPurifier_Doctype($doctype);
return $anon; return $anon;
} }

View File

@@ -12,7 +12,7 @@ class HTMLPurifier_Encoder
*/ */
private function __construct() 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); $str = self::unsafeIconv($encoding, 'utf-8//IGNORE', $str);
if ($str === false) { if ($str === false) {
// $encoding is not a valid encoding // $encoding is not a valid encoding
trigger_error('Invalid encoding ' . $encoding, E_USER_ERROR); throw new Exception('Invalid encoding ' . $encoding);
return ''; return '';
} }
// If the string is bjorked by Shift_JIS or a similar encoding // If the string is bjorked by Shift_JIS or a similar encoding
@@ -404,12 +404,11 @@ class HTMLPurifier_Encoder
} }
$bug = HTMLPurifier_Encoder::testIconvTruncateBug(); $bug = HTMLPurifier_Encoder::testIconvTruncateBug();
if ($bug == self::ICONV_OK) { 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 { } else {
trigger_error( throw new Exception(
'You have a buggy version of iconv, see https://bugs.php.net/bug.php?id=48147 ' . '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', 'and http://sourceware.org/bugzilla/show_bug.cgi?id=13541'
E_USER_ERROR
); );
} }
} }
@@ -454,7 +453,7 @@ class HTMLPurifier_Encoder
$str = mb_convert_encoding($str, 'ISO-8859-1', 'UTF-8'); $str = mb_convert_encoding($str, 'ISO-8859-1', 'UTF-8');
return $str; 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 // You might be tempted to assume that the ASCII representation
// might be OK, however, this is *not* universally true over all // might be OK, however, this is *not* universally true over all
// encodings. So we take the conservative route here, rather // encodings. So we take the conservative route here, rather
@@ -545,10 +544,9 @@ class HTMLPurifier_Encoder
} elseif (($c = strlen($r)) < 9000) { } elseif (($c = strlen($r)) < 9000) {
$code = self::ICONV_TRUNCATES; $code = self::ICONV_TRUNCATES;
} elseif ($c > 9000) { } elseif ($c > 9000) {
trigger_error( throw new Exception(
'Your copy of iconv is extremely buggy. Please notify HTML Purifier maintainers: ' . 'Your copy of iconv is extremely buggy. Please notify HTML Purifier maintainers: ' .
'include your iconv version as per phpversion()', 'include your iconv version as per phpversion()'
E_USER_ERROR
); );
} else { } else {
$code = self::ICONV_OK; $code = self::ICONV_OK;

View File

@@ -264,9 +264,8 @@ class HTMLPurifier_HTMLDefinition extends HTMLPurifier_Definition
if (isset($this->info_content_sets['Block'][$block_wrapper])) { if (isset($this->info_content_sets['Block'][$block_wrapper])) {
$this->info_block_wrapper = $block_wrapper; $this->info_block_wrapper = $block_wrapper;
} else { } else {
trigger_error( throw new Exception(
'Cannot use non-block element as block wrapper', 'Cannot use non-block element as block wrapper'
E_USER_ERROR
); );
} }
@@ -276,11 +275,7 @@ class HTMLPurifier_HTMLDefinition extends HTMLPurifier_Definition
$this->info_parent = $parent; $this->info_parent = $parent;
$this->info_parent_def = $def; $this->info_parent_def = $def;
} else { } else {
trigger_error( throw new Exception('Cannot use unrecognized element as parent');
'Cannot use unrecognized element as parent',
E_USER_ERROR
);
$this->info_parent_def = $this->manager->getElement($this->info_parent, true);
} }
// support template text // support template text

View File

@@ -112,9 +112,8 @@ class HTMLPurifier_HTMLModule_Tidy extends HTMLPurifier_HTMLModule
return; return;
} }
if (!isset($this->fixesForLevel[$this->defaultLevel])) { if (!isset($this->fixesForLevel[$this->defaultLevel])) {
trigger_error( throw new Exception(
'Default level ' . $this->defaultLevel . ' does not exist', 'Default level ' . $this->defaultLevel . ' does not exist'
E_USER_ERROR
); );
return; return;
} }
@@ -162,8 +161,7 @@ class HTMLPurifier_HTMLModule_Tidy extends HTMLPurifier_HTMLModule
$e->$type = $fix; $e->$type = $fix;
break; break;
default: default:
trigger_error("Fix type $type not supported", E_USER_ERROR); throw new Exception("Fix type $type not supported");
break;
} }
} }
} }

View File

@@ -183,11 +183,7 @@ class HTMLPurifier_HTMLModuleManager
if (!$ok) { if (!$ok) {
$module = $original_module; $module = $original_module;
if (!class_exists($module)) { if (!class_exists($module)) {
trigger_error( throw new Exception($original_module . ' module does not exist');
$original_module . ' module does not exist',
E_USER_ERROR
);
return;
} }
} }
$module = new $module(); $module = new $module();

View File

@@ -173,14 +173,8 @@ class HTMLPurifier_LanguageFactory
// infinite recursion guard // infinite recursion guard
if (isset($languages_seen[$code])) { if (isset($languages_seen[$code])) {
trigger_error( throw new Exception('Circular fallback reference in language ' . $code);
'Circular fallback reference in language ' .
$code,
E_USER_ERROR
);
$fallback = 'en';
} }
$language_seen[$code] = true;
// load the fallback recursively // load the fallback recursively
$this->loadLanguage($fallback); $this->loadLanguage($fallback);

View File

@@ -238,7 +238,7 @@ class HTMLPurifier_Lexer
*/ */
public function tokenizeHTML($string, $config, $context) public function tokenizeHTML($string, $config, $context)
{ {
trigger_error('Call to abstract class', E_USER_ERROR); throw new Exception('Call to abstract class');
} }
/** /**

View File

@@ -105,7 +105,7 @@ class HTMLPurifier_URIScheme_data extends HTMLPurifier_URIScheme
} }
$image_code = $info[2]; $image_code = $info[2];
} else { } 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); $real_content_type = image_type_to_mime_type($image_code);
if ($real_content_type != $content_type) { if ($real_content_type != $content_type) {

View File

@@ -12,7 +12,7 @@ class HTMLPurifier_AttrTypesTest extends HTMLPurifier_Harness
new HTMLPurifier_AttrDef_Text() 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'); $types->get('foobar');
$this->assertIdentical( $this->assertIdentical(

View File

@@ -84,7 +84,7 @@ extends HTMLPurifier_ChildDefHarness
public function testError() 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->obj = new HTMLPurifier_ChildDef_StrictBlockquote('div | p');
$this->config->set('HTML.BlockWrapper', 'dav'); $this->config->set('HTML.BlockWrapper', 'dav');
$this->config->set('Cache.DefinitionImpl', null); $this->config->set('Cache.DefinitionImpl', null);

View File

@@ -155,7 +155,7 @@ class HTMLPurifier_ConfigTest extends HTMLPurifier_Harness
$this->assertIdentical($config->get('Home.Rug'), 3); $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'); $config->get('Home.Carpet');
$this->expectError('Home.Carpet is an alias, preferred directive name is Home.Rug'); $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(); $config->finalize();
$this->expectError('Cannot set directive after finalization'); $this->expectException(new Exception('Cannot set directive after finalization'));
$config->set('Poem.Meter', 'vedic'); $config->set('Poem.Meter', 'vedic');
$this->expectError('Cannot load directives after finalization'); $this->expectError('Cannot load directives after finalization');

View File

@@ -27,11 +27,11 @@ class HTMLPurifier_ContextTest extends HTMLPurifier_Harness
$this->context->destroy('IDAccumulator'); $this->context->destroy('IDAccumulator');
$this->assertFalse($this->context->exists('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'); $accumulator_3 =& $this->context->get('IDAccumulator');
$this->assertNull($accumulator_3); $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'); $this->context->destroy('IDAccumulator');
} }
@@ -41,7 +41,7 @@ class HTMLPurifier_ContextTest extends HTMLPurifier_Harness
$var = true; $var = true;
$this->context->register('OnceOnly', $var); $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); $this->context->register('OnceOnly', $var);
// destroy it, now registration is okay // destroy it, now registration is okay

View File

@@ -36,7 +36,7 @@ class HTMLPurifier_DoctypeRegistryTest extends HTMLPurifier_Harness
$registry = new HTMLPurifier_DoctypeRegistry(); $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'); $registry->get('XHTML 2.0');
// prevent XSS // prevent XSS

View File

@@ -47,7 +47,7 @@ class HTMLPurifier_EncoderTest extends HTMLPurifier_Harness
{ {
if (!HTMLPurifier_Encoder::iconvAvailable()) return; if (!HTMLPurifier_Encoder::iconvAvailable()) return;
$this->config->set('Core.Encoding', 'utf99'); $this->config->set('Core.Encoding', 'utf99');
$this->expectError('Invalid encoding utf99'); $this->expectException(new Exception('Invalid encoding utf99'));
$this->assertIdentical( $this->assertIdentical(
HTMLPurifier_Encoder::convertToUTF8("\xF6", $this->config, $this->context), HTMLPurifier_Encoder::convertToUTF8("\xF6", $this->config, $this->context),
'' ''

View File

@@ -134,7 +134,7 @@ class HTMLPurifier_HTMLModule_TidyTest extends HTMLPurifier_Harness
$module = new HTMLPurifier_HTMLModule_Tidy(); $module = new HTMLPurifier_HTMLModule_Tidy();
$module->defaultLevel = 'bananas'; $module->defaultLevel = 'bananas';
$this->expectError('Default level bananas does not exist'); $this->expectException(new Exception('Default level bananas does not exist'));
$module->makeFixesForLevel(array( $module->makeFixesForLevel(array(
'fix-1' => 0 'fix-1' => 0

View File

@@ -115,7 +115,7 @@ class HTMLPurifier_Strategy_FixNestingTest extends HTMLPurifier_StrategyHarness
// test fallback to div // test fallback to div
$this->config->set('HTML.Parent', 'obviously-impossible'); $this->config->set('HTML.Parent', 'obviously-impossible');
$this->config->set('Cache.DefinitionImpl', null); $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>'); $this->assertResult('<div>Accept</div>');
} }

View File

@@ -48,7 +48,7 @@ if ( is_string($GLOBALS['HTMLPurifierTest']['PEAR']) ) {
} }
// after external libraries are loaded, turn on compile time errors // 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 // initialize extra HTML Purifier libraries
require '../extras/HTMLPurifierExtras.auto.php'; require '../extras/HTMLPurifierExtras.auto.php';

View File

@@ -23,9 +23,8 @@
* $test_files) do not have underscores in their names. * $test_files) do not have underscores in their names.
*/ */
// HTML Purifier runs error free on E_STRICT, so if code reports // HTML Purifier runs error free.
// errors, we want to know about it. error_reporting(E_ALL);
error_reporting(E_ALL | E_STRICT);
// Because we always want to know about errors, and because SimpleTest // Because we always want to know about errors, and because SimpleTest
// will notify us about them, logging the errors to stderr is // will notify us about them, logging the errors to stderr is