Skip to content

Scientific-notation width/height causes DivisionByZeroError #251

Description

@curtisgibby

width or height written in scientific notation (e.g. 1e3) crashes rasterization with an uncaught DivisionByZeroError. Exponent notation is valid in SVG attribute syntax, and real exporters emit it — I hit this on a production file.

Reproduction

<?php
require __DIR__ . '/vendor/autoload.php';

use SVG\SVG;

$svg = '<svg xmlns="http://www.w3.org/2000/svg" width="1e3" height="328.56">'
     . '<rect x="0" y="0" width="100" height="100" fill="#000000"/>'
     . '</svg>';

var_dump(SVG::fromString($svg)->getDocument()->getWidth());
SVG::fromString($svg)->toRasterImage(200, 200);

Output (php-svg v0.14.7, PHP 8.4):

string(3) "1e3"

Fatal error: Uncaught DivisionByZeroError: Division by zero in
  .../src/Rasterization/SVGRasterizer.php:83
Stack trace:
#0 .../src/SVG.php(62): SVG\Rasterization\SVGRasterizer->__construct('1e3', '328.56', NULL, 200, 200, NULL)
#1 repro.php(11): SVG\SVG->toRasterImage(200, 200)

Replacing width="1e3" with width="1000" renders correctly. Also reproduces with 1E3, and with an exponent in height (3.2856e2).

Cause

Length.php:24 has no exponent in its number pattern:

$regex = '/^([+-]?\d*\.?\d*)(px|pt|pc|cm|mm|in|%)?$/';

So convert() returns null, and SVGRasterizer.php:83 turns that into a zero denominator:

$scaleX = $width / (!empty($viewBox) ? $viewBox[2] : $this->docWidth ?? 0);

Suggested fix

Allow an optional exponent, requiring at least one digit in the mantissa:

$regex = '/^([+-]?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?)(px|pt|pc|cm|mm|in|%)?$/';

Parsing results, current vs proposed:

INPUT        CURRENT   PROPOSED
'1e3'        null      1000      <- fixed
'1E3'        null      1000      <- fixed
'3.2856e2'   null      328.56    <- fixed
'1e-3'       null      0.001     <- fixed
'+1.5e+2'    null      150       <- fixed
'1000'       1000      1000
'3.28'       3.28      3.28
'50%'        50        50
'12pt'       12        12
'.5'         0.5       0.5
'-2.5cm'     -2.5      -2.5
'abc'        null      null
'1e'         null      null
'e3'         null      null
'.'          0         null      <- behaviour change
'-'          0         null      <- behaviour change

Note the last two: '.' and '-' currently parse as 0 and would become null. Neither is a valid length, so returning null matches the documented contract ("null is returned if the string does not denote a valid length unit"), but it is a change beyond the exponent fix and you may want it handled separately.

Separately, ?? 0 at SVGRasterizer.php:83-84 converts any unparseable dimension into a division by zero. Guarding that would turn this class of bug into a graceful failure rather than a fatal, independent of the regex.

I have not run this against the test suite — the table above is from testing the patterns in isolation. Happy to open a PR with tests if the approach looks right to you.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions