Blame | Letzte Änderung | Log anzeigen | RSS feed
<?php//// FPDI - Version 1.4.2//// Copyright 2004-2011 Setasign - Jan Slabon//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at//// http://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.//if (!defined ('PDF_TYPE_NULL'))define ('PDF_TYPE_NULL', 0);if (!defined ('PDF_TYPE_NUMERIC'))define ('PDF_TYPE_NUMERIC', 1);if (!defined ('PDF_TYPE_TOKEN'))define ('PDF_TYPE_TOKEN', 2);if (!defined ('PDF_TYPE_HEX'))define ('PDF_TYPE_HEX', 3);if (!defined ('PDF_TYPE_STRING'))define ('PDF_TYPE_STRING', 4);if (!defined ('PDF_TYPE_DICTIONARY'))define ('PDF_TYPE_DICTIONARY', 5);if (!defined ('PDF_TYPE_ARRAY'))define ('PDF_TYPE_ARRAY', 6);if (!defined ('PDF_TYPE_OBJDEC'))define ('PDF_TYPE_OBJDEC', 7);if (!defined ('PDF_TYPE_OBJREF'))define ('PDF_TYPE_OBJREF', 8);if (!defined ('PDF_TYPE_OBJECT'))define ('PDF_TYPE_OBJECT', 9);if (!defined ('PDF_TYPE_STREAM'))define ('PDF_TYPE_STREAM', 10);if (!defined ('PDF_TYPE_BOOLEAN'))define ('PDF_TYPE_BOOLEAN', 11);if (!defined ('PDF_TYPE_REAL'))define ('PDF_TYPE_REAL', 12);require_once('pdf_context.php');if (!class_exists('pdf_parser', false)) {class pdf_parser {/*** Filename* @var string*/var $filename;/*** File resource* @var resource*/var $f;/*** PDF Context* @var object pdf_context-Instance*/var $c;/*** xref-Data* @var array*/var $xref;/*** root-Object* @var array*/var $root;/*** PDF version of the loaded document* @var string*/var $pdfVersion;/*** For reading encrypted documents and xref/objectstreams are in use** @var boolean*/var $readPlain = true;/*** Constructor** @param string $filename Source-Filename*/function pdf_parser($filename) {$this->filename = $filename;$this->f = @fopen($this->filename, 'rb');if (!$this->f)$this->error(sprintf('Cannot open %s !', $filename));$this->getPDFVersion();$this->c = new pdf_context($this->f);// Read xref-Data$this->xref = array();$this->pdf_read_xref($this->xref, $this->pdf_find_xref());// Check for Encryption$this->getEncryption();// Read root$this->pdf_read_root();}/*** Close the opened file*/function closeFile() {if (isset($this->f) && is_resource($this->f)) {fclose($this->f);unset($this->f);}}/*** Print Error and die** @param string $msg Error-Message*/function error($msg) {die('<b>PDF-Parser Error:</b> ' . $msg);}/*** Check Trailer for Encryption*/function getEncryption() {if (isset($this->xref['trailer'][1]['/Encrypt'])) {$this->error('File is encrypted!');}}/*** Find/Return /Root** @return array*/function pdf_find_root() {if ($this->xref['trailer'][1]['/Root'][0] != PDF_TYPE_OBJREF) {$this->error('Wrong Type of Root-Element! Must be an indirect reference');}return $this->xref['trailer'][1]['/Root'];}/*** Read the /Root*/function pdf_read_root() {// read root$this->root = $this->pdf_resolve_object($this->c, $this->pdf_find_root());}/*** Get PDF-Version** And reset the PDF Version used in FPDI if needed*/function getPDFVersion() {fseek($this->f, 0);preg_match('/\d\.\d/',fread($this->f, 16), $m);if (isset($m[0]))$this->pdfVersion = $m[0];return $this->pdfVersion;}/*** Find the xref-Table*/function pdf_find_xref() {$toRead = 1500;$stat = fseek ($this->f, -$toRead, SEEK_END);if ($stat === -1) {fseek ($this->f, 0);}$data = fread($this->f, $toRead);$pos = strlen($data) - strpos(strrev($data), strrev('startxref'));$data = substr($data, $pos);if (!preg_match('/\s*(\d+).*$/s', $data, $matches)) {$this->error('Unable to find pointer to xref table');}return (int) $matches[1];}/*** Read xref-table** @param array $result Array of xref-table* @param integer $offset of xref-table*/function pdf_read_xref(&$result, $offset) {$o_pos = $offset-min(20, $offset);fseek($this->f, $o_pos); // set some bytes backwards to fetch errorious docs$data = fread($this->f, 100);$xrefPos = strrpos($data, 'xref');if ($xrefPos === false) {fseek($this->f, $offset);$c = new pdf_context($this->f);$xrefStreamObjDec = $this->pdf_read_value($c);if (is_array($xrefStreamObjDec) && isset($xrefStreamObjDec[0]) && $xrefStreamObjDec[0] == PDF_TYPE_OBJDEC) {$this->error(sprintf('This document (%s) probably uses a compression technique which is not supported by the free parser shipped with FPDI.', $this->filename));} else {$this->error('Unable to find xref table.');}}if (!isset($result['xref_location'])) {$result['xref_location'] = $o_pos + $xrefPos;$result['max_object'] = 0;}$cylces = -1;$bytesPerCycle = 100;fseek($this->f, $o_pos = $o_pos + $xrefPos + 4); // set the handle directly after the "xref"-keyword$data = fread($this->f, $bytesPerCycle);while (($trailerPos = strpos($data, 'trailer', max($bytesPerCycle * $cylces++, 0))) === false && !feof($this->f)) {$data .= fread($this->f, $bytesPerCycle);}if ($trailerPos === false) {$this->error('Trailer keyword not found after xref table');}$data = substr($data, 0, $trailerPos);// get Line-Endingpreg_match_all("/(\r\n|\n|\r)/", substr($data, 0, 100), $m); // check the first 100 bytes for linebreaks$differentLineEndings = count(array_unique($m[0]));if ($differentLineEndings > 1) {$lines = preg_split("/(\r\n|\n|\r)/", $data, -1, PREG_SPLIT_NO_EMPTY);} else {$lines = explode($m[0][1], $data);}$data = $differentLineEndings = $m = null;unset($data, $differentLineEndings, $m);$linesCount = count($lines);$start = 1;for ($i = 0; $i < $linesCount; $i++) {$line = trim($lines[$i]);if ($line) {$pieces = explode(' ', $line);$c = count($pieces);switch($c) {case 2:$start = (int)$pieces[0];$end = $start + (int)$pieces[1];if ($end > $result['max_object'])$result['max_object'] = $end;break;case 3:if (!isset($result['xref'][$start]))$result['xref'][$start] = array();if (!array_key_exists($gen = (int) $pieces[1], $result['xref'][$start])) {$result['xref'][$start][$gen] = $pieces[2] == 'n' ? (int) $pieces[0] : null;}$start++;break;default:$this->error('Unexpected data in xref table');}}}$lines = $pieces = $line = $start = $end = $gen = null;unset($lines, $pieces, $line, $start, $end, $gen);fseek($this->f, $o_pos + $trailerPos + 7);$c = new pdf_context($this->f);$trailer = $this->pdf_read_value($c);$c = null;unset($c);if (!isset($result['trailer'])) {$result['trailer'] = $trailer;}if (isset($trailer[1]['/Prev'])) {$this->pdf_read_xref($result, $trailer[1]['/Prev'][1]);}$trailer = null;unset($trailer);return true;}/*** Reads an Value** @param object $c pdf_context* @param string $token a Token* @return mixed*/function pdf_read_value(&$c, $token = null) {if (is_null($token)) {$token = $this->pdf_read_token($c);}if ($token === false) {return false;}switch ($token) {case '<':// This is a hex string.// Read the value, then the terminator$pos = $c->offset;while(1) {$match = strpos ($c->buffer, '>', $pos);// If you can't find it, try// reading more data from the streamif ($match === false) {if (!$c->increase_length()) {return false;} else {continue;}}$result = substr ($c->buffer, $c->offset, $match - $c->offset);$c->offset = $match + 1;return array (PDF_TYPE_HEX, $result);}break;case '<<':// This is a dictionary.$result = array();// Recurse into this function until we reach// the end of the dictionary.while (($key = $this->pdf_read_token($c)) !== '>>') {if ($key === false) {return false;}if (($value = $this->pdf_read_value($c)) === false) {return false;}// Catch missing valueif ($value[0] == PDF_TYPE_TOKEN && $value[1] == '>>') {$result[$key] = array(PDF_TYPE_NULL);break;}$result[$key] = $value;}return array (PDF_TYPE_DICTIONARY, $result);case '[':// This is an array.$result = array();// Recurse into this function until we reach// the end of the array.while (($token = $this->pdf_read_token($c)) !== ']') {if ($token === false) {return false;}if (($value = $this->pdf_read_value($c, $token)) === false) {return false;}$result[] = $value;}return array (PDF_TYPE_ARRAY, $result);case '(' :// This is a string$pos = $c->offset;$openBrackets = 1;do {for (; $openBrackets != 0 && $pos < $c->length; $pos++) {switch (ord($c->buffer[$pos])) {case 0x28: // '('$openBrackets++;break;case 0x29: // ')'$openBrackets--;break;case 0x5C: // backslash$pos++;}}} while($openBrackets != 0 && $c->increase_length());$result = substr($c->buffer, $c->offset, $pos - $c->offset - 1);$c->offset = $pos;return array (PDF_TYPE_STRING, $result);case 'stream':$o_pos = ftell($c->file)-strlen($c->buffer);$o_offset = $c->offset;$c->reset($startpos = $o_pos + $o_offset);$e = 0; // ensure line breaks in front of the streamif ($c->buffer[0] == chr(10) || $c->buffer[0] == chr(13))$e++;if ($c->buffer[1] == chr(10) && $c->buffer[0] != chr(10))$e++;if ($this->actual_obj[1][1]['/Length'][0] == PDF_TYPE_OBJREF) {$tmp_c = new pdf_context($this->f);$tmp_length = $this->pdf_resolve_object($tmp_c, $this->actual_obj[1][1]['/Length']);$length = $tmp_length[1][1];} else {$length = $this->actual_obj[1][1]['/Length'][1];}if ($length > 0) {$c->reset($startpos + $e,$length);$v = $c->buffer;} else {$v = '';}$c->reset($startpos + $e + $length + 9); // 9 = strlen("endstream")return array(PDF_TYPE_STREAM, $v);default :if (is_numeric ($token)) {// A numeric token. Make sure that// it is not part of something else.if (($tok2 = $this->pdf_read_token ($c)) !== false) {if (is_numeric ($tok2)) {// Two numeric tokens in a row.// In this case, we're probably in// front of either an object reference// or an object specification.// Determine the case and return the dataif (($tok3 = $this->pdf_read_token ($c)) !== false) {switch ($tok3) {case 'obj':return array (PDF_TYPE_OBJDEC, (int) $token, (int) $tok2);case 'R':