htmlpurifier icon indicating copy to clipboard operation
htmlpurifier copied to clipboard

Undefined property: Illuminate\Support\Number::$required

Open lyyka opened this issue 1 year ago • 4 comments

Using Laravel 11.36.1 with PHP 8.3, mews/purifier 3.4.2 and the latest version of ezyang/htmlpurifier.

When validating Number custom attributes, I get the following exception when i want to purify this string:

<p>Test</p>

This is the exception trace:

{
    "message": "Undefined property: Illuminate\\Support\\Number::$required",
    "exception": "ErrorException",
    "file": "/var/www/html/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrCollections.php",
    "line": 129,
    "trace": [
        {
            "file": "/var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Bootstrap/HandleExceptions.php",
            "line": 290,
            "function": "handleError",
            "class": "Illuminate\\Foundation\\Bootstrap\\HandleExceptions",
            "type": "->"
        },
        {
            "file": "/var/www/html/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrCollections.php",
            "line": 129,
            "function": "Illuminate\\Foundation\\Bootstrap\\{closure}",
            "class": "Illuminate\\Foundation\\Bootstrap\\HandleExceptions",
            "type": "->"
        },
        {
            "file": "/var/www/html/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModuleManager.php",
            "line": 437,
            "function": "expandIdentifiers",
            "class": "HTMLPurifier_AttrCollections",
            "type": "->"
        },
        {
            "file": "/var/www/html/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModuleManager.php",
            "line": 361,
            "function": "getElement",
            "class": "HTMLPurifier_HTMLModuleManager",
            "type": "->"
        },
        {
            "file": "/var/www/html/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLDefinition.php",
            "line": 253,
            "function": "getElements",
            "class": "HTMLPurifier_HTMLModuleManager",
            "type": "->"
        },
        {
            "file": "/var/www/html/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLDefinition.php",
            "line": 195,
            "function": "processModules",
            "class": "HTMLPurifier_HTMLDefinition",
            "type": "->"
        },
        {
            "file": "/var/www/html/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Definition.php",
            "line": 51,
            "function": "doSetup",
            "class": "HTMLPurifier_HTMLDefinition",
            "type": "->"
        },
        {
            "file": "/var/www/html/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Config.php",
            "line": 497,
            "function": "setup",
            "class": "HTMLPurifier_Definition",
            "type": "->"
        },
        {
            "file": "/var/www/html/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Config.php",
            "line": 415,
            "function": "getDefinition",
            "class": "HTMLPurifier_Config",
            "type": "->"
        },
        {
            "file": "/var/www/html/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Generator.php",
            "line": 74,
            "function": "getHTMLDefinition",
            "class": "HTMLPurifier_Config",
            "type": "->"
        },
        {
            "file": "/var/www/html/vendor/ezyang/htmlpurifier/library/HTMLPurifier.php",
            "line": 158,
            "function": "__construct",
            "class": "HTMLPurifier_Generator",
            "type": "->"
        },
        {
            "file": "/var/www/html/vendor/mews/purifier/src/Purifier.php",
            "line": 290,
            "function": "purify",
            "class": "HTMLPurifier",
            "type": "->"
        },
        // rest is omitted for clairty

Config:

return [
    'encoding' => 'UTF-8',
    'finalize' => true,
    'ignoreNonStrings' => false,
    'cachePath' => storage_path('app/purifier'),
    'cacheFileMode' => 0755,
    'settings' => [
        'default' => [
            'HTML.Doctype' => 'HTML 4.01 Transitional',
            'HTML.Allowed' => 'div,b,strong,i,em,u,a[href|title],ul,ol,li,p[style],br,span[style|data-mention|data-mention-user-id|data-mention-user-type],h1,h2,h3',
            'CSS.AllowedProperties' => 'font,font-size,font-weight,font-style,font-family,text-decoration,padding-left,color,background-color,text-align',
            'AutoFormat.AutoParagraph' => true,
            'AutoFormat.RemoveEmpty' => true,
        ],
        'custom_config_note' => [
            'HTML.Allowed' => 'div,b,strong,i,a[href|title],ul,ol,li,p,br,span[style|data-mention|data-mention-user-id|data-mention-user-type]',
            'AutoFormat.AutoParagraph' => true,
            'AutoFormat.RemoveEmpty' => true,
        ],
        'custom_config_svg_overlay' => [
            'HTML.Allowed' => 'svg,path[d|fill],circle[cx|cy|r|fill],rect[x|y|rx|ry|width|height]',
        ],
        'test' => [
            'Attr.EnableID' => 'true',
        ],
        "youtube" => [
            "HTML.SafeIframe" => 'true',
            "URI.SafeIframeRegexp" => "%^(http://|https://|//)(www.youtube.com/embed/|player.vimeo.com/video/)%",
        ],
        'custom_definition' => [
            'id' => 'html5-definitions',
            'rev' => 1,
            'debug' => false,
            'elements' => [
                // http://developers.whatwg.org/sections.html
                ['section', 'Block', 'Flow', 'Common'],
                ['nav', 'Block', 'Flow', 'Common'],
                ['article', 'Block', 'Flow', 'Common'],
                ['aside', 'Block', 'Flow', 'Common'],
                ['header', 'Block', 'Flow', 'Common'],
                ['footer', 'Block', 'Flow', 'Common'],

                // Content model actually excludes several tags, not modelled here
                ['address', 'Block', 'Flow', 'Common'],
                ['hgroup', 'Block', 'Required: h1 | h2 | h3 | h4 | h5 | h6', 'Common'],

                // http://developers.whatwg.org/grouping-content.html
                ['figure', 'Block', 'Optional: (figcaption, Flow) | (Flow, figcaption) | Flow', 'Common'],
                ['figcaption', 'Inline', 'Flow', 'Common'],

                // http://developers.whatwg.org/the-video-element.html#the-video-element
                ['video', 'Block', 'Optional: (source, Flow) | (Flow, source) | Flow', 'Common', [
                    'src' => 'URI',
                    'type' => 'Text',
                    'width' => 'Length',
                    'height' => 'Length',
                    'poster' => 'URI',
                    'preload' => 'Enum#auto,metadata,none',
                    'controls' => 'Bool',
                ]],
                ['source', 'Block', 'Flow', 'Common', [
                    'src' => 'URI',
                    'type' => 'Text',
                ]],

                // http://developers.whatwg.org/text-level-semantics.html
                ['s', 'Inline', 'Inline', 'Common'],
                ['var', 'Inline', 'Inline', 'Common'],
                ['sub', 'Inline', 'Inline', 'Common'],
                ['sup', 'Inline', 'Inline', 'Common'],
                ['mark', 'Inline', 'Inline', 'Common'],
                ['wbr', 'Inline', 'Empty', 'Core'],

                // http://developers.whatwg.org/edits.html
                ['ins', 'Block', 'Flow', 'Common', ['cite' => 'URI', 'datetime' => 'CDATA']],
                ['del', 'Block', 'Flow', 'Common', ['cite' => 'URI', 'datetime' => 'CDATA']],
            ],
            'attributes' => [
                ['iframe', 'allowfullscreen', 'Bool'],
                ['table', 'height', 'Text'],
                ['td', 'border', 'Text'],
                ['th', 'border', 'Text'],
                ['tr', 'width', 'Text'],
                ['tr', 'height', 'Text'],
                ['tr', 'border', 'Text'],
            ],
        ],
        'custom_attributes' => [
            ['a', 'target', 'Enum#_blank,_self,_target,_top'],

            // SVG <path> element attributes
            ['path', 'd', 'Text'],
            ['path', 'fill', 'Color'],

            // SVG <circle> element attributes
            ['circle', 'cx', 'Number'],
            ['circle', 'cy', 'Number'],
            ['circle', 'r', 'Number'],
            ['circle', 'fill', 'Color'],

            // SVG <rect> element attributes
            ['rect', 'rx', 'Number'],
            ['rect', 'ry', 'Number'],
            ['rect', 'x', 'Number'],
            ['rect', 'y', 'Number'],
            ['rect', 'width', 'Number'],
            ['rect', 'height', 'Number'],
            ['rect', 'pathLength', 'Number'],
            ['rect', 'fill', 'Color'],

            // CKEditor Mentions
            ['span', 'data-mention', 'Text'],
            ['span', 'data-mention-user-id', 'Text'],
            ['span', 'data-mention-user-type', 'Text'],
        ],
        'custom_elements' => [
            ['u', 'Inline', 'Inline', 'Common'],

            // SVG <path> element
            ['path', 'Inline', 'Empty', 'Common'],

            // SVG <circle> element
            ['circle', 'Inline', 'Empty', 'Common'],

            // SVG <rect> element
            ['rect', 'Inline', 'Empty', 'Common'],
        ],
    ],
];

lyyka avatar Dec 18 '24 21:12 lyyka

What is a Illuminate\Support\Number 🤔

ezyang avatar Dec 19 '24 05:12 ezyang

Hey, I should have posted more info. So basically this happens when using this library through mewebstudio/Purifier which is an adapter for Laravel. Laravel has a class Illuminate\Support\Number which is used for number formatting and so on.

Although the issue happened while using mewebstudio/Purifier - the exception was thrown here, so that's why I opened the issue here. It seems to me like the library resolves Number attribute validator as the above-mentioned class. Not sure why though. This happens in AttrCollections on line 129 and happens ONLY for Number validator (others work just fine).

Maybe I'm wrong and I should have opened an issue with mewebstudio/Purifier, really not sure :)

lyyka avatar Dec 19 '24 10:12 lyyka

Try there first? Feel free to come back if they disagree.

ezyang avatar Dec 19 '24 15:12 ezyang

There is no Number definition. I also tried it, but it doesn't exist, which is why it tries to load the Laravel class instead.

Use Text definition instead of Number, Integer doesn't work either.

baoanhng avatar Aug 05 '25 16:08 baoanhng