Skip to content

TypeError in PdfParser::decodeHexViaCMap() — strlen() receives an int from array_key_first($cmap) #12

Description

@ndeblauw

Package version: v0.8.3
PHP version: 8.4.20
Laravel version: 13.23.0

Summary

Parsing certain PDFs throws a fatal TypeError from inside the PDF parser: strlen(): Argument #1 ($string) must be of type string, int given

Location

src/Parsers/PdfParser.php:353, in decodeHexViaCMap():

$charLen = strlen(array_key_first($cmap));

Root cause

$cmap maps glyph hex codes → characters. PHP auto-casts integer-like string array keys to int (e.g. the key "1234" is stored as int 1234; keys with a leading zero like "0041" stay strings). When the first CMap key is a purely-numeric hex code with no leading zero, array_key_first($cmap) returns an int, and under PHP 8's strict typing strlen(int) throws a TypeError instead of coercing.

This is data-dependent, so it only triggers on PDFs whose font CMap happens to start with such a code. Because TypeError extends Error (not Exception/PaperdocException), consumers catching PaperdocException cannot handle it — it escapes as a fatal error.

Stack trace (abridged)

PdfParser::decodeHexViaCMap()      src/Parsers/PdfParser.php:353
PdfParser::parseTextBlockWithCtm() src/Parsers/PdfParser.php:733
PdfParser::extractTextLines()      src/Parsers/PdfParser.php:603
PdfParser::parse()                 src/Parsers/PdfParser.php:74
DocumentManager::open()            src/Support/DocumentManager.php:53

Suggested fix

Cast the key to string before measuring its length:

$charLen = strlen((string) array_key_first($cmap));

More broadly, $cmap keys should be treated as strings throughout decodeHexViaCMap() (the same int-key coercion could affect the isset($cmap[$code]) lookup on line 365, since $code from substr() is always a string while a matching key may be stored as an int). Consider building the CMap with string-forced keys, or normalizing keys with (string) at every access.

Expected behavior

A PDF with numeric-looking CMap keys should parse without error — or at minimum, an unreadable/malformed document should surface as a ParserException/PaperdocException rather than a native TypeError, so it can be caught with the library's documented exception hierarchy.

I unfortunately no longer have the PDF that caused the issue (due to holidays, the log file cycling already cleaned that out)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions