Uploads and limitseasy_svg_max_php_tags

easy_svg_max_php_tags

Set how many processing instructions (the XML declaration included) an SVG may contain before Easy SVG refuses it, without reading it.

Filter · Easy SVG · Status: Stable

Some SVG files are small but built to make the cleaning step extremely slow. One trick is to stack many processing instructions, the snippets that start with a less-than sign and a question mark, such as the <?xml ... ?> line at the top of a file. Easy SVG counts them before cleaning and refuses the file when there are too many. This filter sets that number.

Usage

apply_filters( 'easy_svg_max_php_tags', int $max )

Applied in easy-svg.php, inside easy_svg_svg_too_complex(). The result is cast to an integer.

When to use it

  • You want to be stricter than the default of 10, for example 2 on a site where every SVG comes from the same export tool and has at most one XML declaration.
  • A legitimate file from a special tool is refused and you have confirmed that it really contains more than 10 processing instructions. This is very rare.

Do not use it when:

  • A file is refused because of its size. That is easy_svg_max_bytes.
  • A file is refused because the sanitizer cannot read it (broken XML, custom DTD entities). Raising this number does not help there.

Parameters

body
$maxint
Required

The highest number of processing instructions a file may contain. Default 10. There is no setting for it on the Icons screen, so the incoming value is always 10 unless another filter changed it first.

Return value

returnint

The bound. A file is refused when its count is greater than this number, so with 10 a file with exactly 10 still passes. Return 1 or more if you accept files that start with an XML declaration (most exported SVGs do).

Default

10

Examples

Stricter than the default

/**
 * Allow the XML declaration and one more processing instruction, nothing else.
 */
function mysite_svg_max_php_tags( $max ) {
	return 2;
}
add_filter( 'easy_svg_max_php_tags', 'mysite_svg_max_php_tags' );

Never lower than one

If the number comes from somewhere you do not control (an option, a constant), keep it at 1 or more, or every file with an XML declaration is refused.

function mysite_svg_max_php_tags_from_option( $max ) {
	$wanted = (int) get_option( 'mysite_svg_max_pi', $max );

	return max( 1, $wanted );
}
add_filter( 'easy_svg_max_php_tags', 'mysite_svg_max_php_tags_from_option' );

Only tighten, never loosen

A site plugin that should never make the default weaker:

function mysite_svg_max_php_tags_cap( $max ) {
	return min( (int) $max, 5 );
}
add_filter( 'easy_svg_max_php_tags', 'mysite_svg_max_php_tags_cap', 20 );

How it works

easy_svg_svg_too_complex() does a plain text count, before any parsing:

  • It counts every occurrence of the two characters less-than and question mark, in the raw bytes.
  • That includes the XML declaration <?xml version="1.0"?>, a stylesheet instruction <?xml-stylesheet ... ?>, PHP style tags, and the same characters inside comments or CDATA. Nothing is parsed, so the count does not know where it is.
  • The file is refused when the count is greater than this filter's result, or when the use count is greater than easy_svg_max_use_tags.

The reason for counting at all: the sanitizing library rescans the whole document once for each nested processing instruction, so the work grows much faster than the file. A counting check is cheap and runs in one pass.

The check runs on every way an SVG comes in, always after the size check and before the sanitizer:

  • media uploads, REST media uploads and sideloads (wp_handle_upload_prefilter, wp_handle_sideload_prefilter)
  • the safety net for new attachments (add_attachment), which deletes the attachment when the check fails
  • XML-RPC and wp_upload_bits()
  • every way into the icon library: add, add from the media library, replace

What people see when it fails: "Sorry, please check your SVG file." in the media library, the XML-RPC message for wp_upload_bits(), and "That SVG has too many parts to be read safely." when adding to the icon library (replacing an icon only says "That file is not an SVG this library can use.").

The filter is applied on every check, with no cache and no context. Your callback cannot tell an icon from an upload.

Pitfalls

  • The XML declaration counts. return 0; refuses every SVG that starts with <?xml, which is most files exported from design tools.
  • A negative number refuses everything. The check is "count greater than limit", and 0 is greater than -1, so even a file without any processing instruction is refused.
  • Raising it costs time. Every extra nested instruction lets one file keep a PHP worker busy for longer. There is no legitimate drawing that needs more than a handful.
  • The name says PHP, the count does not. It counts every processing instruction, not only PHP ones.
This bound protects the server from files designed to tie up PHP workers for minutes. Do not raise it on a site where people you do not fully trust can upload SVGs.