### Run composer update command Source: https://github.com/smalot/pdfparser/wiki/Installation Run this command in your terminal to download and install the PDFParser bundle via Composer. ```bash $ composer update smalot/pdfparser ``` -------------------------------- ### Include alt_autoload.php-dist without Composer Source: https://github.com/smalot/pdfparser/wiki/Installation If you cannot use Composer, include the alt_autoload.php-dist file to load all required files at once. Then you can use the PDFParser class and others. ```php ``` -------------------------------- ### Add PDFParser to composer.json Source: https://github.com/smalot/pdfparser/wiki/Installation Add the smalot/pdfparser package to your project's composer.json file under the require section. Use the version constraint '*' to get the latest version. ```json { "require": { "smalot/pdfparser": "*" } } ``` -------------------------------- ### Install with Composer Source: https://github.com/smalot/pdfparser/blob/master/README.md Install the smalot/pdfparser package via Composer. Requires PHP 7.1+. ```bash composer require smalot/pdfparser ``` -------------------------------- ### Application example with custom exception and mysqli Source: https://github.com/smalot/pdfparser/blob/master/samples/bugs/Issue334.pdf Shows a complete application pattern using mysqli with a custom exception class FuzDatabaseException. It prepares and executes an UPDATE query, throwing exceptions on failure. The example includes a constructor that accepts a mysqli instance and a try-catch block that catches FuzDatabaseException. ```php class FuzDatabaseException extends Exception { } class Foo { public $mysqli; public function __construct(mysqli $mysqli) { $this->mysqli = $mysqli; } public function updateBar() { $q = "UPDATE foo SET bar=1"; $statement = $this->mysqli->prepare($q); if (!$statement) { throw new FuzDatabaseException ($mysqli->error); } if (!$statement->execute()) { throw new FuzDatabaseException ($statement->error); } } } $foo = new Foo(new mysqli('localhost','buzUser','buzPassword')); try { $foo->updateBar(); } catch (FuzDatabaseException $e) $msg = $e->getMessage(); // Now send warning emails, write log ``` -------------------------------- ### Install Development Tools Source: https://github.com/smalot/pdfparser/wiki/For-Developer Installs and updates development tools like PHPUnit and PHP-CS-Fixer. Tools are installed in `dev-tools/vendor`; check `dev-tools/composer.json` for versions. ```bash make install-dev-tools ``` -------------------------------- ### Quick example: parse PDF with custom config Source: https://github.com/smalot/pdfparser/blob/master/README.md Shows how to use the Parser with a custom Config to set a decode memory limit, recommended for untrusted PDFs. Parses a file and outputs its text. ```php setDecodeMemoryLimit($decodeMemoryLimit); $parser = new Parser([], $config); $document = $parser->parseFile('/path/to/untrusted-file.pdf'); echo $document->getText(); ``` -------------------------------- ### Get pages width and height Source: https://github.com/smalot/pdfparser/blob/master/doc/Usage.md Retrieves the width and height of each page in a PDF. If a page's MediaBox is not set, it falls back to the header details from the Pages object. ```php $parser = new \Smalot\PdfParser\Parser(); $pdf = $parser->parseFile('document.pdf'); $pages = $pdf->getPages(); // this variable will contain the height and width of each page of the given PDF $mediaBox = []; foreach ($pages as $page) { $details = $page->getDetails(); // If Mediabox is not set in details of current $page instance, get details from the header instead if (!isset($details['MediaBox'])) { $pages = $pdf->getObjectsByType('Pages'); $details = reset($pages)->getHeader()->getDetails(); } $mediaBox[] = [ 'width' => $details['MediaBox'][2], 'height' => $details['MediaBox'][3] ]; } ``` -------------------------------- ### Get pages width and height Source: https://github.com/smalot/pdfparser/blob/master/doc/Usage.md Retrieves the width and height of each page in a PDF document. If a page's MediaBox is not set, it falls back to the document's Pages object details. ```APIDOC ## Get pages width and height ### Description Retrieves the width and height of each page in a PDF document. If a page's MediaBox is not set, it falls back to the document's Pages object details. ### Method PHP code snippet ### Endpoint `Parser::parseFile()` and `Page::getDetails()` ### Parameters - **$parser** (Parser) - Required - The PDF parser instance. - **$pdf** (Pdf) - Required - The parsed PDF document. - **$pages** (array) - Required - Array of Page objects. - **$page** (Page) - Required - A single page object. - **$details** (array) - Required - The page details array. - **$mediaBox** (array) - Required - Array to store width and height. ### Request Example ```php $parser = new \Smalot\PdfParser\Parser(); $pdf = $parser->parseFile('document.pdf'); $pages = $pdf->getPages(); // this variable will contain the height and width of each page of the given PDF $mediaBox = []; foreach ($pages as $page) { $details = $page->getDetails(); // If Mediabox is not set in details of current $page instance, get details from the header instead if (!isset($details['MediaBox'])) { $pages = $pdf->getObjectsByType('Pages'); $details = reset($pages)->getHeader()->getDetails(); } $mediaBox[] = [ 'width' => $details['MediaBox'][2], 'height' => $details['MediaBox'][3] ]; } ``` ### Response Returns an array of associative arrays with 'width' and 'height' keys. ``` -------------------------------- ### Extract metadata with getDetails() Source: https://github.com/smalot/pdfparser/blob/master/doc/Usage.md Retrieves PDF metadata such as Producer, CreatedOn, and Pages. The available data varies per PDF. ```php $metaData = $pdf->getDetails(); Array ( [Producer] => Adobe Acrobat [CreatedOn] => 2022-01-28T16:36:11+00:00 [Pages] => 35 ... ) ``` -------------------------------- ### Create Parser and Parse File Source: https://github.com/smalot/pdfparser/blob/master/doc/Usage.md Initialize the Smalot PDF parser and load a PDF file either from a file path or from content. Use parseFile for a file path and parseContent for raw content. ```php $parser = new \Smalot\PdfParser\Parser(); $pdf = $parser->parseFile('document.pdf'); // .. or ... $pdf = $parser->parseContent(file_get_contents('document.pdf')) ``` -------------------------------- ### XMP metadata appended to getDetails() output Source: https://github.com/smalot/pdfparser/blob/master/doc/Usage.md Shows how XMP metadata values, including namespaces like dc: and pdf:, are appended to the array returned by getDetails(). ```php Array ( ... [Pages] => 35 [dc:creator] => My Name [pdf:producer] => Adobe Acrobat [dc:title] => My Document Title ... ) ``` -------------------------------- ### PDF encryption Source: https://github.com/smalot/pdfparser/blob/master/doc/Usage.md Notes that the library cannot read encrypted PDF files and throws an exception. Mentions the setIgnoreEncryption option to override the check. ```APIDOC ## PDF encryption ### Description This library cannot currently read encrypted PDF files, i.e. those with a read password. Attempting to do so produces an exception. See the `setIgnoreEncryption` option in CustomConfig.md for how to override the check in specific cases. ### Error ``` Exception: Secured pdf file are currently not supported. ``` ``` -------------------------------- ### Run PHPUnit with code coverage Source: https://github.com/smalot/pdfparser/wiki/Unit-Test Executes the PHPUnit test suite via simple-phpunit, generating an HTML code coverage report in the 'coverage/' folder if Xdebug is installed. ```bash $ vendor/bin/simple-phpunit --coverage-html coverage ``` -------------------------------- ### Nested XMP metadata values Source: https://github.com/smalot/pdfparser/blob/master/doc/Usage.md Illustrates that XMP metadata values can be arrays, with nested values following the XML structure, e.g., xmptpg:maxpagesize and xmptpg:platenames. ```php Array ( ... [dc:title] => My Document Title [xmptpg:maxpagesize] => Array ( [stdim:w] => 21.500000 [stdim:h] => 6.222222 [stdim:unit] => Inches ) [xmptpg:platenames] => Array ( [0] => Cyan [1] => Magenta [2] => Yellow [3] => Black ) ... ) ``` -------------------------------- ### Parse Base64 encoded PDF with parseContent() Source: https://github.com/smalot/pdfparser/blob/master/doc/Usage.md Parses a Base64 encoded PDF string without saving to disk, then extracts text from each page using getText(). ```php parseContent(base64_decode($base64PDF)); $text = $pdf->getText(); echo $text; ``` -------------------------------- ### Include Font Info in dataTm via Config Source: https://github.com/smalot/pdfparser/blob/master/doc/Usage.md Enable font identifier and size in dataTm output by setting Config::setDataTmFontInfoHasToBeIncluded(true). The parser must be created with the config object. ```php // create config $config = new Smalot\PdfParser\Config(); $config->setDataTmFontInfoHasToBeIncluded(true); // use config and parse file $parser = new Smalot\PdfParser\Parser([], $config); $pdf = $parser->parseFile('document.pdf'); $firstpage = $pdf->getPages()[0]; $data = $firstpage->getDataTm(); Array ( [0] => Array ( [0] => Array ( [0] => 0.999429 [1] => 0 [2] => 0 [3] => 1 [4] => 201.96 [5] => 720.68 ) [1] => Document title [2] => R7 [3] => 27.96 ) [1] => Array ( [0] => Array ( [0] => 0.999402 [1] => 0 [2] => 0 [3] => 1 [4] => 70.8 [5] => 673.64 ) [1] => Calibri : Lorem ipsum dolor sit amet, consectetur a [2] => R9 [3] => 11.04 ) ) ``` -------------------------------- ### calculateTextWidth Source: https://github.com/smalot/pdfparser/blob/master/doc/Usage.md Calculates the width of a given text for a specific font. Characters without width information are added to the provided $missing array. ```APIDOC ## calculateTextWidth ### Description Calculates the width of a given text for a specific font. Characters without width information are added to the provided $missing array. ### Method PHP method ### Endpoint `Font::calculateTextWidth(string $text, array &$missing)` ### Parameters - **$text** (string) - Required - The text to measure. - **$missing** (array) - Required - Reference to an array that will be filled with characters that have no width information. ### Request Example ```php $parser = new \Smalot\PdfParser\Parser(); $pdf = $parser->parseFile('document.pdf'); $fonts = $pdf->getFonts(); // get first font (we assume here there is at least one) $font = reset($fonts); // get width $width = $font->calculateTextWidth('Some text', $missing); ``` ### Response Returns the calculated width as a float or integer. ``` -------------------------------- ### Set font space limit with setFontSpaceLimit Source: https://github.com/smalot/pdfparser/blob/master/doc/CustomConfig.md Use this option to adjust the font space limit when getText() returns too many spaces. The example sets the limit to -60 and then parses a PDF file with the custom config. ```php $config = new \Smalot\PdfParser\Config(); $config->setFontSpaceLimit(-60); $parser = new \Smalot\PdfParser\Parser([], $config); $pdf = $parser->parseFile('document.pdf'); ``` -------------------------------- ### Calculate text width for a font Source: https://github.com/smalot/pdfparser/blob/master/doc/Usage.md Calculates the width of a given text using a font from the PDF. Characters without width are added to the `$missing` array (second parameter). ```php $parser = new \Smalot\PdfParser\Parser(); $pdf = $parser->parseFile('document.pdf'); $fonts = $pdf->getFonts(); // get first font (we assume here there is at least one) $font = reset($fonts); // get width $width = $font->calculateTextWidth('Some text', $missing); ``` -------------------------------- ### Extract Text from PDF Source: https://github.com/smalot/pdfparser/blob/master/doc/Usage.md Extract text from the entire PDF, a specific page, or a limited number of pages. getText() without arguments returns all text, with an integer argument limits to that many pages. ```php // extract text of the whole PDF $text = $pdf->getText(); // or extract the text of a specific page (in this case the first page) $text = $pdf->getPages()[0]->getText(); // you can also extract text of a limited amount of pages. here, it will only use the first five pages. $text = $pdf->getText(5); ``` -------------------------------- ### Extract Text Positions with getDataTm Source: https://github.com/smalot/pdfparser/blob/master/doc/Usage.md Retrieve transformation matrix and x,y positions of text objects from a page. The output array includes matrix values (indexes 0-3) and position (indexes 4,5) for each text element. ```php $data = $pdf->getPages()[0]->getDataTm(); Array ( [0] => Array ( [0] => Array ( [0] => 0.999429 [1] => 0 [2] => 0 [3] => 1 [4] => 201.96 [5] => 720.68 ) [1] => Document title ) [1] => Array ( [0] => Array ( [0] => 0.999402 [1] => 0 [2] => 0 [3] => 1 [4] => 70.8 [5] => 673.64 ) [1] => Calibri : Lorem ipsum dolor sit amet, consectetur a ) ) ``` -------------------------------- ### Check each mysqli operation and die on failure Source: https://github.com/smalot/pdfparser/blob/master/samples/bugs/Issue334.pdf Checks the return value of prepare(), bind_param(), and execute() and terminates with die() if any fails. Each operation can fail for various reasons, and only the last error is stored per connection/statement, so continuing after a failure may lose error information. The example uses die() for simplicity, but more sophisticated error handling is recommended. ```php $stmt = $mysqli->prepare("INSERT INTO testtable VALUES (?,?,?)"); // prepare() can fail because of syntax errors, missing privileges, .... if ( false ===$stmt ) { // and since all the following operations need a valid/ready statement object // it doesn't make sense to go on // you might want to use a more sophisticated mechanism than die() // but's it's only an example die('prepare() failed: '. htmlspecialchars($mysqli->error)); } $rc = $stmt->bind_param('iii', $x, $y, $z); // bind_param() can fail because the number of parameter doesn't match the placeholders in the statement // or there's a type conflict(?), or .... if ( false ===$rc ) { // again execute() is useless if you can't bind the parameters. Bail out somehow. die('bind_param() failed: '. htmlspecialchars($stmt->error)); } $rc = $stmt->execute(); // execute() can fail for various reasons. And may it be as stupid as someone tripping over the network cable // 2006 "server gone away" is always an option if ( false ===$rc ) { die('execute() failed: '. htmlspecialchars($stmt->error)); } $stmt->close(); ``` -------------------------------- ### Checking execute() return value for execution errors Source: https://github.com/smalot/pdfparser/blob/master/samples/bugs/Issue334.pdf Use the return value of execute() to detect errors during execution. If execute() returns false, set an error flag. This is a suggested addition to the previous example to catch execution errors. ```php if($stmt_test->execute()) $errorflag=true; ``` -------------------------------- ### Calculate Text Width with Font Source: https://github.com/smalot/pdfparser/blob/master/doc/Usage.md Calculate the width of a text string using a font object obtained from the page. The font ID is taken from dataTm (index 2) and the text from index 1. ```php $font_id = $data[0][2]; //R7 $font = $firstpage->getFont($font_id); $text = $data[0][1]; $width = $font->calculateTextWidth($text, $missing); ``` -------------------------------- ### Checking prepare() return value for SQL errors Source: https://github.com/smalot/pdfparser/blob/master/samples/bugs/Issue334.pdf Use the return value of prepare() to detect errors during statement preparation. If prepare() returns false, the error message is available via $stmt_test->error. This example inserts a row into a test table. ```php $stmt_test = $mysqliDatabaseConnection->stmt_init(); if($stmt_test->prepare("INSERT INTO testtable VALUES (23,44,56)")) { $stmt_test->execute(); $stmt_test->close(); } else echo("Statement failed: ". $stmt_test->error. "
"); ``` -------------------------------- ### PDF encryption error message Source: https://github.com/smalot/pdfparser/blob/master/doc/Usage.md Error message produced when attempting to read an encrypted PDF. The library does not support encrypted files; see `setIgnoreEncryption` option in CustomConfig.md to override the check. ```text Exception: Secured pdf file are currently not supported. ``` -------------------------------- ### Run PHP-CS-Fixer via Make Source: https://github.com/smalot/pdfparser/wiki/For-Developer Checks coding styles using the make shortcut. ```bash make run-php-cs-fixer ``` -------------------------------- ### Run PHPUnit Tests Source: https://github.com/smalot/pdfparser/wiki/For-Developer Runs all tests using PHPUnit. ```bash make run-phpunit ``` -------------------------------- ### Run PHPStan Static Analysis Source: https://github.com/smalot/pdfparser/wiki/For-Developer Runs static code analysis with PHPStan. ```bash make run-phpstan ``` -------------------------------- ### Ignore encryption flag with setIgnoreEncryption Source: https://github.com/smalot/pdfparser/blob/master/doc/CustomConfig.md Use this option when a PDF is marked as encrypted but is actually readable. Set ignoreEncryption to true in a custom Config instance to bypass the encryption flag. ```php $config = new \Smalot\PdfParser\Config(); $config->setIgnoreEncryption(true); $parser = new \Smalot\PdfParser\Parser([], $config); $pdf = $parser->parseFile('document.pdf'); ``` -------------------------------- ### Create Config object and set font space limit Source: https://github.com/smalot/pdfparser/blob/master/doc/CustomConfig.md Use this snippet to change parser behavior by creating a Config object and passing it to the Parser constructor. Setting the font space limit to -60 can help when getText() returns text with too many spaces. ```php $config = new \Smalot\PdfParser\Config(); $config->setFontSpaceLimit(-60); $parser = new \Smalot\PdfParser\Parser([], $config); $pdf = $parser->parseFile('document.pdf'); // output extracted text // echo $pdf->getText(); ``` -------------------------------- ### Run PHP-CS-Fixer Manually Source: https://github.com/smalot/pdfparser/wiki/For-Developer Runs PHP-CS-Fixer in dry-run mode to check coding styles without making changes. ```bash dev-tools/vendor/bin/php-cs-fixer fix --verbose --dry-run ``` -------------------------------- ### Configure memory limits with setDecodeMemoryLimit and setRetainImageContent Source: https://github.com/smalot/pdfparser/blob/master/doc/CustomConfig.md Use these options to manage memory usage when parsing fails due to memory exhaustion. setRetainImageContent(false) discards raw image data to save memory, while setDecodeMemoryLimit(1000000) sets a byte limit for decompression, also protecting against decompression amplification. The default is unlimited, so choose a limit that fits your content. ```php $config = new \Smalot\PdfParser\Config(); // Whether to retain raw image data as content or discard it to save memory $config->setRetainImageContent(false); // Memory limit to use when de-compressing files, in bytes $config->setDecodeMemoryLimit(1000000); $parser = new \Smalot\PdfParser\Parser([], $config); ``` -------------------------------- ### setHorizontalOffset Source: https://github.com/smalot/pdfparser/blob/master/doc/CustomConfig.md Adjusts horizontal offset to handle broken words or preserve table structure. An empty string can prevent words from breaking up, while a tab can help preserve document structure. ```APIDOC ## setHorizontalOffset ### Description Adjusts horizontal offset to handle broken words or preserve table structure. An empty string can prevent words from breaking up, while a tab can help preserve document structure. ### Method - `setHorizontalOffset(string $offset)` - Sets the horizontal offset value. ### Usage Example ```php $config = new \Smalot\PdfParser\Config(); $config->setHorizontalOffset(''); $config->setHorizontalOffset("\t"); $parser = new \Smalot\PdfParser\Parser([], $config); ``` ``` -------------------------------- ### Adjust word breaking and table structure with setHorizontalOffset Source: https://github.com/smalot/pdfparser/blob/master/doc/CustomConfig.md Use setHorizontalOffset to fix broken words or preserve table structure. An empty string prevents words from breaking up, while a tab can help preserve document structure. ```php $config = new \Smalot\PdfParser\Config(); // An empty string can prevent words from breaking up $config->setHorizontalOffset(''); // A tab can help preserve the structure of your document $config->setHorizontalOffset("\t"); $parser = new \Smalot\PdfParser\Parser([], $config); ``` -------------------------------- ### setMaxNestingDepth Source: https://github.com/smalot/pdfparser/blob/master/doc/CustomConfig.md Bounds parser recursion depth for arrays and dictionaries to prevent call stack or memory exhaustion from pathologically nested objects. Beyond the limit, the container is skipped and parsing continues. ```APIDOC ## setMaxNestingDepth ### Description Bounds parser recursion depth for arrays and dictionaries to prevent call stack or memory exhaustion from pathologically nested objects. Beyond the limit, the container is skipped and parsing continues. ### Method - `setMaxNestingDepth(int $depth)` - Sets the maximum nesting depth for recursive parsing. ### Usage Example ```php $config = new \Smalot\PdfParser\Config(); $config->setMaxNestingDepth(5000); $parser = new \Smalot\PdfParser\Parser([], $config); ``` ### Notes - Default is far above regular PDFs, so it only affects malformed input. ``` -------------------------------- ### Simple script with trigger_error for mysqli prepare and execute Source: https://github.com/smalot/pdfparser/blob/master/samples/bugs/Issue334.pdf Uses trigger_error() with E_USER_ERROR to report failures in a simple command-line script. Checks both $mysqli and $statement, outputting the respective error property. This is efficient for scripts that may terminate, but for complex applications an exception-based error system is recommended. ```php # This is in a simple command line script $mysqli = new mysqli('localhost','buzUser','buzPassword'); $q = "UPDATE foo SET bar=1"; ($statement = $mysqli->prepare($q)) or trigger_error($mysqli->error, E_USER_ERROR); $statement->execute() or trigger_error($statement->error, E_USER_ERROR); ``` -------------------------------- ### setDecodeMemoryLimit + setRetainImageContent Source: https://github.com/smalot/pdfparser/blob/master/doc/CustomConfig.md Configures memory usage for PDF parsing. setRetainImageContent controls whether raw image data is retained, and setDecodeMemoryLimit sets a memory limit for decompression to prevent memory exhaustion and decompression amplification. ```APIDOC ## setDecodeMemoryLimit + setRetainImageContent ### Description Configures memory usage for PDF parsing. setRetainImageContent controls whether raw image data is retained, and setDecodeMemoryLimit sets a memory limit for decompression to prevent memory exhaustion and decompression amplification. ### Methods - `setRetainImageContent(bool $retain)` - Sets whether to retain raw image data as content or discard it to save memory. - `setDecodeMemoryLimit(int $limit)` - Sets the memory limit (in bytes) to use when de-compressing files. ### Usage Example ```php $config = new \Smalot\PdfParser\Config(); $config->setRetainImageContent(false); $config->setDecodeMemoryLimit(1000000); $parser = new \Smalot\PdfParser\Parser([], $config); ``` ### Notes - `setDecodeMemoryLimit` also controls decompression amplification; set it when parsing PDFs from untrusted sources. - Default for `setDecodeMemoryLimit` is unlimited; choose a limit that fits your content. ``` -------------------------------- ### Bound parser recursion with setMaxNestingDepth Source: https://github.com/smalot/pdfparser/blob/master/doc/CustomConfig.md Use setMaxNestingDepth to limit recursion depth when parsing arrays and dictionaries, preventing stack exhaustion from pathologically nested objects. The default is far above regular PDFs, so it only affects malformed input. ```php $config = new \Smalot\PdfParser\Config(); $config->setMaxNestingDepth(5000); $parser = new \Smalot\PdfParser\Parser([], $config); ``` -------------------------------- ### Checking errno after execution for errors Source: https://github.com/smalot/pdfparser/blob/master/samples/bugs/Issue334.pdf After executing the statement, check the errno property to detect any errors that occurred. If errno is non-zero, set an error flag. This is another suggested safety check. ```php if($stmt_test->errno) { $errorflag=true; } ``` -------------------------------- ### Echo mysqli connection error Source: https://github.com/smalot/pdfparser/blob/master/samples/bugs/Issue334.pdf Shows how to retrieve and display the last error from the MySQL database using the connection object's error property. This is useful for debugging query failures. ```php echo $mysqliDatabaseConnection->error ```