Error uploading SVG files in php 7.1+

Permalink 0 0 Browser Info Environment
Uploading an SVG file on a site running php7.1 or php7.2 results in an error.

At the end of the upload sequence the progress band turn red and the following error message shows within the file upload area. When the browser is refreshed the file has in fact uploaded but the image preview is missing.

Concrete\Core\File\Image\Svg\SanitizerException: A non-numeric value encountered in /var/www/vhosts/dev16.katalysis.net/httpdocs/concrete/src/File/Image/Svg/SanitizerException.php:47 Stack trace: #0 /var/www/vhosts/dev16.katalysis.net/httpdocs/concrete/src/File/Image/Svg/Sanitizer.php(118): Concrete\Core\File\Image\Svg\SanitizerException::create(10, 'A non-numeric v...') #1 /var/www/vhosts/dev16.katalysis.net/httpdocs/concrete/src/File/Image/Svg/Sanitizer.php(69): Concrete\Core\File\Image\Svg\Sanitizer->dataToXml('<?xml version="...') #2 /var/www/vhosts/dev16.katalysis.net/httpdocs/concrete/src/File/ImportProcessor/SvgSanitizerProcessor.php(63): Concrete\Core\File\Image\Svg\Sanitizer->sanitizeData('<?xml version="...', Object(Concrete\Core\File\Image\Svg\SanitizerOptions)) #3 /var/www/vhosts/dev16.katalysis.net/httpdocs/concrete/src/File/Importer.php(329): Concrete\Core\File\ImportProcessor\SvgSanitizerProcessor->process(Object(Concrete\Core\Entity\File\Version)) #4 /var/www/vhosts/dev16.katalysis.net/httpdocs/concrete/controllers/backend/file.php(510): Concrete\Core\File\Importer->import('/tmp/phpO5y9pq', 'email.svg', Object(Concrete\Core\Tree\Node\Type\FileFolder)) #5 /var/www/vhosts/dev16.katalysis.net/httpdocs/concrete/controllers/backend/file.php(197): Concrete\Controller\Backend\File->handleUpload('file') #6 [internal function]: Concrete\Controller\Backend\File->upload() #7 /var/www/vhosts/dev16.katalysis.net/httpdocs/concrete/src/Controller/AbstractController.php(294): call_user_func_array(Array, Array) #8 /var/www/vhosts/dev16.katalysis.net/httpdocs/concrete/src/Routing/ControllerRouteAction.php(61): Concrete\Core\Controller\AbstractController->runAction('upload', Array) #9 /var/www/vhosts/dev16.katalysis.net/httpdocs/concrete/src/Http/RouteDispatcher.php(37): Concrete\Core\Routing\ControllerRouteAction->execute(Object(Concrete\Core\Http\Request), Object(Concrete\Core\Routing\Route), Array) #10 /var/www/vhosts/dev16.katalysis.net/httpdocs/concrete/src/Http/Middleware/DispatcherDelegate.php(39): Concrete\Core\Http\RouteDispatcher->dispatch(Object(Concrete\Core\Http\Request)) #11 /var/www/vhosts/dev16.katalysis.net/httpdocs/concrete/src/Http/Middleware/MiddlewareStack.php(86): Concrete\Core\Http\Middleware\DispatcherDelegate->next(Object(Concrete\Core\Http\Request)) #12 /var/www/vhosts/dev16.katalysis.net/httpdocs/concrete/src/Http/DefaultDispatcher.php(126): Concrete\Core\Http\Middleware\MiddlewareStack->process(Object(Concrete\Core\Http\Request)) #13 /var/www/vhosts/dev16.katalysis.net/httpdocs/concrete/src/Http/DefaultDispatcher.php(58): Concrete\Core\Http\DefaultDispatcher->handleDispatch(Object(Concrete\Core\Http\Request)) #14 /var/www/vhosts/dev16.katalysis.net/httpdocs/concrete/src/Http/Middleware/DispatcherDelegate.php(39): Concrete\Core\Http\DefaultDispatcher->dispatch(Object(Concrete\Core\Http\Request)) #15 /var/www/vhosts/dev16.katalysis.net/httpdocs/concrete/src/Http/Middleware/ThumbnailMiddleware.php(76): Concrete\Core\Http\Middleware\DispatcherDelegate->next(Object(Concrete\Core\Http\Request)) #16 /var/www/vhosts/dev16.katalysis.net/httpdocs/concrete/src/Http/Middleware/MiddlewareDelegate.php(50): Concrete\Core\Http\Middleware\ThumbnailMiddleware->process(Object(Concrete\Core\Http\Request), Object(Concrete\Core\Http\Middleware\DispatcherDelegate)) #17 /var/www/vhosts/dev16.katalysis.net/httpdocs/concrete/src/Http/Middleware/FrameOptionsMiddleware.php(39): Concrete\Core\Http\Middleware\MiddlewareDelegate->next(Object(Concrete\Core\Http\Request)) #18 /var/www/vhosts/dev16.katalysis.net/httpdocs/concrete/src/Http/Middleware/MiddlewareDelegate.php(50): Concrete\Core\Http\Middleware\FrameOptionsMiddleware->process(Object(Concrete\Core\Http\Request), Object(Concrete\Core\Http\Middleware\MiddlewareDelegate)) #19 /var/www/vhosts/dev16.katalysis.net/httpdocs/concrete/src/Http/Middleware/CookieMiddleware.php(35): Concrete\Core\Http\Middleware\MiddlewareDelegate->next(Object(Concrete\Core\Http\Request)) #20 /var/www/vhosts/dev16.katalysis.net/httpdocs/concrete/src/Http/Middleware/MiddlewareDelegate.php(50): Concrete\Core\Http\Middleware\CookieMiddleware->process(Object(Concrete\Core\Http\Request), Object(Concrete\Core\Http\Middleware\MiddlewareDelegate)) #21 /var/www/vhosts/dev16.katalysis.net/httpdocs/concrete/src/Http/Middleware/ApplicationMiddleware.php(29): Concrete\Core\Http\Middleware\MiddlewareDelegate->next(Object(Concrete\Core\Http\Request)) #22 /var/www/vhosts/dev16.katalysis.net/httpdocs/concrete/src/Http/Middleware/MiddlewareDelegate.php(50): Concrete\Core\Http\Middleware\ApplicationMiddleware->process(Object(Concrete\Core\Http\Request), Object(Concrete\Core\Http\Middleware\MiddlewareDelegate)) #23 /var/www/vhosts/dev16.katalysis.net/httpdocs/concrete/src/Http/Middleware/MiddlewareStack.php(86): Concrete\Core\Http\Middleware\MiddlewareDelegate->next(Object(Concrete\Core\Http\Request)) #24 /var/www/vhosts/dev16.katalysis.net/httpdocs/concrete/src/Http/DefaultServer.php(85): Concrete\Core\Http\Middleware\MiddlewareStack->process(Object(Concrete\Core\Http\Request)) #25 /var/www/vhosts/dev16.katalysis.net/httpdocs/concrete/src/Foundation/Runtime/Run/DefaultRunner.php(119): Concrete\Core\Http\DefaultServer->handleRequest(Object(Concrete\Core\Http\Request)) #26 /var/www/vhosts/dev16.katalysis.net/httpdocs/concrete/src/Foundation/Runtime/DefaultRuntime.php(102): Concrete\Core\Foundation\Runtime\Run\DefaultRunner->run() #27 /var/www/vhosts/dev16.katalysis.net/httpdocs/concrete/dispatcher.php(36): Concrete\Core\Foundation\Runtime\DefaultRuntime->run() #28 /var/www/vhosts/dev16.katalysis.net/httpdocs/index.php(3): require('/var/www/vhosts...') #29 {main}


Status: New
katalysis
mlocati replied on at Permalink Reply
mlocati
Could you share the SVG that's causing this error?
katalysis replied on at Permalink Reply
katalysis
I tried a variety of files including some that had previously uploaded successfully, so I'm sure it's not the files.

I've done some further tests and the problem occurs consistently on sites running on our Plesk Centos containers but when I run on an Ubuntu container everything is fine.

I'm thinking maybe this an issue with a particular version of a php module?
mlocati replied on at Permalink Reply
mlocati
For security reasons, concrete5 version 8.5.1 "sanitizes" the SVG files, so that images uploaded by site users won't contain harmful code.

In order to do that, concrete5 needs to read the SVG files, but something is going wrong for you (when PHP reads your file it throws the "A non-numeric value encountered" you are experiencing).

You can disable this feature in the "/dashboard/system/files/image_uploading" dashboard page (check the "Allow unsafe SVG features" option), but I'd really like to know what's going wrong, so that I can fix it.
mlocati replied on at Permalink Reply
mlocati
PS: if you have access to the terminal on both the working and non working systems, you can compare the output of this command:
php --ri dom


That command will print the configuration of the "dom" php extension, used by concrete5 to read SVG files.
katalysis replied on at Permalink Reply 1 Attachment
katalysis
Thank you @mlocati.

Checking the "Allow unsafe SVG features" option does allow the file upload to complete.

Difference in working and not working versions is libxml Version 2.7.6 (not working) and 2.9.4 (working).

Guess a minimum version is needed to run the sanitizer. I've attached an example svg file in case useful and will try updating libxml on the centos servers next.
mlocati replied on at Permalink Reply
mlocati
I have been able to load your SVG file with a very old PHP version (5.3), with the DOM extension compiled with libxml 2.7.6 (same as yours), and everything worked fine.

Here's the script I used to test it:

<?php
echo 'Loading... ';
function getLoadFlags()
{
    $flags = LIBXML_NONET | LIBXML_NOWARNING;
    foreach (array(
        'LIBXML_PARSEHUGE', //  libxml >= 2.7.0
        'LIBXML_HTML_NOIMPLIED', // libxml >= 2.7.7
        'LIBXML_HTML_NODEFDTD', // libxml >= 2.7.8
        'LIBXML_BIGLINES', // libxml >= 2.9.0
    ) as $flagName) {
        if (defined($flagName)) {
            $flags |= constant($flagName);
        }
    }


Could you check if the above script is working for you on the system that's failing?
katalysis replied on at Permalink Reply
katalysis
That works, response:

Loading... ok.
mlocati replied on at Permalink Reply
mlocati
It's really strange: it should be the exact same code of the SVG Sanitizer that's failing...

concrete5 Environment Information

# concrete5 Version
Core Version - 8.5.1
Version Installed - 8.5.1
Database Version - 20190301133300

# concrete5 Packages
ExchangeCore reCAPTCHA (1.1.1), Good Care Group Theme (0.0.5.6), Katalysis Base (0.0.6.7), Migration Tool (0.9.0), Shortcodes (1.0.1)

# concrete5 Overrides
blocks/core_area_layout/templates/example_layout_template.php, blocks/core_area_layout/templates/parallax/view.js, blocks/core_area_layout/templates/parallax/view.php, blocks/core_area_layout/templates/parallax/view.css, blocks/core_area_layout/templates/parallax, blocks/core_area_layout/templates, blocks/core_area_layout/form.php, blocks/core_area_layout, blocks/core_stack_display/view.php, blocks/core_stack_display, elements/block_area_footer.php

# concrete5 Cache Settings
Block Cache - Off
Overrides Cache - Off
Full Page Caching - Off
Full Page Cache Lifetime - Every 6 hours (default setting).

# Server Software
Apache

# Server API
cgi-fcgi

# PHP Version
7.1.30

# PHP Extensions
bcmath, bz2, calendar, cgi-fcgi, Core, ctype, curl, date, dba, dom, enchant, exif, fileinfo, filter, ftp, gd, gettext, gmp, hash, iconv, imagick, imap, intl, ionCube Loader, json, ldap, libxml, mbstring, mcrypt, mysqli, mysqlnd, odbc, openssl, pcntl, pcre, PDO, pdo_mysql, PDO_ODBC, pdo_pgsql, pdo_sqlite, pgsql, Phar, posix, pspell, readline, redis, Reflection, session, SimpleXML, soap, sockets, sodium, SPL, sqlite3, standard, sysvmsg, sysvsem, sysvshm, tidy, tokenizer, xml, xmlreader, xmlrpc, xmlwriter, xsl, Zend OPcache, zip, zlib

# PHP Settings
max_execution_time - 30
log_errors_max_len - 1024
max_file_uploads - 20
max_input_nesting_level - 64
max_input_time - 60
max_input_vars - 1000
memory_limit - 256M
post_max_size - 128M
sql.safe_mode - Off
upload_max_filesize - 128M
ldap.max_links - Unlimited
mysqli.max_links - Unlimited
mysqli.max_persistent - Unlimited
odbc.max_links - Unlimited
odbc.max_persistent - Unlimited
pcre.backtrack_limit - 1000000
pcre.recursion_limit - 100000
pgsql.max_links - Unlimited
pgsql.max_persistent - Unlimited
session.cache_limiter - <i>no value</i>
session.gc_maxlifetime - 7200
soap.wsdl_cache_limit - 5
opcache.max_accelerated_files - 10000
opcache.max_file_size - 0
opcache.max_wasted_percentage - 5

Browser User-Agent String

Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36