Differences Between: [Versions 310 and 403] [Versions 311 and 403] [Versions 39 and 403] [Versions 400 and 403] [Versions 401 and 403]
1 <?php 2 //============================================================+ 3 // File name : tcpdf_static.php 4 // Version : 1.1.4 5 // Begin : 2002-08-03 6 // Last Update : 2022-08-12 7 // Author : Nicola Asuni - Tecnick.com LTD - www.tecnick.com - info@tecnick.com 8 // License : GNU-LGPL v3 (http://www.gnu.org/copyleft/lesser.html) 9 // ------------------------------------------------------------------- 10 // Copyright (C) 2002-2022 Nicola Asuni - Tecnick.com LTD 11 // 12 // This file is part of TCPDF software library. 13 // 14 // TCPDF is free software: you can redistribute it and/or modify it 15 // under the terms of the GNU Lesser General Public License as 16 // published by the Free Software Foundation, either version 3 of the 17 // License, or (at your option) any later version. 18 // 19 // TCPDF is distributed in the hope that it will be useful, but 20 // WITHOUT ANY WARRANTY; without even the implied warranty of 21 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 22 // See the GNU Lesser General Public License for more details. 23 // 24 // You should have received a copy of the License 25 // along with TCPDF. If not, see 26 // <http://www.tecnick.com/pagefiles/tcpdf/LICENSE.TXT>. 27 // 28 // See LICENSE.TXT file for more information. 29 // ------------------------------------------------------------------- 30 // 31 // Description : 32 // Static methods used by the TCPDF class. 33 // 34 //============================================================+ 35 36 /** 37 * @file 38 * This is a PHP class that contains static methods for the TCPDF class.<br> 39 * @package com.tecnick.tcpdf 40 * @author Nicola Asuni 41 * @version 1.1.2 42 */ 43 44 /** 45 * @class TCPDF_STATIC 46 * Static methods used by the TCPDF class. 47 * @package com.tecnick.tcpdf 48 * @brief PHP class for generating PDF documents without requiring external extensions. 49 * @version 1.1.1 50 * @author Nicola Asuni - info@tecnick.com 51 */ 52 class TCPDF_STATIC { 53 54 /** 55 * Current TCPDF version. 56 * @private static 57 */ 58 private static $tcpdf_version = '6.6.2'; 59 60 /** 61 * String alias for total number of pages. 62 * @public static 63 */ 64 public static $alias_tot_pages = '{:ptp:}'; 65 66 /** 67 * String alias for page number. 68 * @public static 69 */ 70 public static $alias_num_page = '{:pnp:}'; 71 72 /** 73 * String alias for total number of pages in a single group. 74 * @public static 75 */ 76 public static $alias_group_tot_pages = '{:ptg:}'; 77 78 /** 79 * String alias for group page number. 80 * @public static 81 */ 82 public static $alias_group_num_page = '{:png:}'; 83 84 /** 85 * String alias for right shift compensation used to correctly align page numbers on the right. 86 * @public static 87 */ 88 public static $alias_right_shift = '{rsc:'; 89 90 /** 91 * Encryption padding string. 92 * @public static 93 */ 94 public static $enc_padding = "\x28\xBF\x4E\x5E\x4E\x75\x8A\x41\x64\x00\x4E\x56\xFF\xFA\x01\x08\x2E\x2E\x00\xB6\xD0\x68\x3E\x80\x2F\x0C\xA9\xFE\x64\x53\x69\x7A"; 95 96 /** 97 * ByteRange placemark used during digital signature process. 98 * @since 4.6.028 (2009-08-25) 99 * @public static 100 */ 101 public static $byterange_string = '/ByteRange[0 ********** ********** **********]'; 102 103 /** 104 * Array page boxes names 105 * @public static 106 */ 107 public static $pageboxes = array('MediaBox', 'CropBox', 'BleedBox', 'TrimBox', 'ArtBox'); 108 109 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 110 111 /** 112 * Return the current TCPDF version. 113 * @return string TCPDF version string 114 * @since 5.9.012 (2010-11-10) 115 * @public static 116 */ 117 public static function getTCPDFVersion() { 118 return self::$tcpdf_version; 119 } 120 121 /** 122 * Return the current TCPDF producer. 123 * @return string TCPDF producer string 124 * @since 6.0.000 (2013-03-16) 125 * @public static 126 */ 127 public static function getTCPDFProducer() { 128 return "\x54\x43\x50\x44\x46\x20\x28\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x74\x63\x70\x64\x66\x2e\x6f\x72\x67\x29"; 129 } 130 131 /** 132 * Check if the URL exist. 133 * @param string $url URL to check. 134 * @return boolean true if the URl exist, false otherwise. 135 * @since 5.9.204 (2013-01-28) 136 * @public static 137 */ 138 public static function isValidURL($url) { 139 $headers = @get_headers($url); 140 if ($headers === false) { 141 return false; 142 } 143 return (strpos($headers[0], '200') !== false); 144 } 145 146 /** 147 * Removes SHY characters from text. 148 * Unicode Data:<ul> 149 * <li>Name : SOFT HYPHEN, commonly abbreviated as SHY</li> 150 * <li>HTML Entity (decimal): "&#173;"</li> 151 * <li>HTML Entity (hex): "&#xad;"</li> 152 * <li>HTML Entity (named): "&shy;"</li> 153 * <li>How to type in Microsoft Windows: [Alt +00AD] or [Alt 0173]</li> 154 * <li>UTF-8 (hex): 0xC2 0xAD (c2ad)</li> 155 * <li>UTF-8 character: chr(194).chr(173)</li> 156 * </ul> 157 * @param string $txt input string 158 * @param boolean $unicode True if we are in unicode mode, false otherwise. 159 * @return string without SHY characters. 160 * @since (4.5.019) 2009-02-28 161 * @public static 162 */ 163 public static function removeSHY($txt='', $unicode=true) { 164 $txt = preg_replace('/([\\xc2]{1}[\\xad]{1})/', '', $txt); 165 if (!$unicode) { 166 $txt = preg_replace('/([\\xad]{1})/', '', $txt); 167 } 168 return $txt; 169 } 170 171 172 /** 173 * Get the border mode accounting for multicell position (opens bottom side of multicell crossing pages) 174 * @param string|array|int $brd Indicates if borders must be drawn around the cell block. The value can be a number:<ul><li>0: no border (default)</li><li>1: frame</li></ul>or a string containing some or all of the following characters (in any order):<ul><li>L: left</li><li>T: top</li><li>R: right</li><li>B: bottom</li></ul> or an array of line styles for each border group: array('LTRB' => array('width' => 2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0))) 175 * @param string $position multicell position: 'start', 'middle', 'end' 176 * @param boolean $opencell True when the cell is left open at the page bottom, false otherwise. 177 * @return array border mode array 178 * @since 4.4.002 (2008-12-09) 179 * @public static 180 */ 181 public static function getBorderMode($brd, $position='start', $opencell=true) { 182 if ((!$opencell) OR empty($brd)) { 183 return $brd; 184 } 185 if ($brd == 1) { 186 $brd = 'LTRB'; 187 } 188 if (is_string($brd)) { 189 // convert string to array 190 $slen = strlen($brd); 191 $newbrd = array(); 192 for ($i = 0; $i < $slen; ++$i) { 193 $newbrd[$brd[$i]] = array('cap' => 'square', 'join' => 'miter'); 194 } 195 $brd = $newbrd; 196 } 197 foreach ($brd as $border => $style) { 198 switch ($position) { 199 case 'start': { 200 if (strpos($border, 'B') !== false) { 201 // remove bottom line 202 $newkey = str_replace('B', '', $border); 203 if (strlen($newkey) > 0) { 204 $brd[$newkey] = $style; 205 } 206 unset($brd[$border]); 207 } 208 break; 209 } 210 case 'middle': { 211 if (strpos($border, 'B') !== false) { 212 // remove bottom line 213 $newkey = str_replace('B', '', $border); 214 if (strlen($newkey) > 0) { 215 $brd[$newkey] = $style; 216 } 217 unset($brd[$border]); 218 $border = $newkey; 219 } 220 if (strpos($border, 'T') !== false) { 221 // remove bottom line 222 $newkey = str_replace('T', '', $border); 223 if (strlen($newkey) > 0) { 224 $brd[$newkey] = $style; 225 } 226 unset($brd[$border]); 227 } 228 break; 229 } 230 case 'end': { 231 if (strpos($border, 'T') !== false) { 232 // remove bottom line 233 $newkey = str_replace('T', '', $border); 234 if (strlen($newkey) > 0) { 235 $brd[$newkey] = $style; 236 } 237 unset($brd[$border]); 238 } 239 break; 240 } 241 } 242 } 243 return $brd; 244 } 245 246 /** 247 * Determine whether a string is empty. 248 * @param string $str string to be checked 249 * @return bool true if string is empty 250 * @since 4.5.044 (2009-04-16) 251 * @public static 252 */ 253 public static function empty_string($str) { 254 return (is_null($str) OR (is_string($str) AND (strlen($str) == 0))); 255 } 256 257 /** 258 * Returns a temporary filename for caching object on filesystem. 259 * @param string $type Type of file (name of the subdir on the tcpdf cache folder). 260 * @param string $file_id TCPDF file_id. 261 * @return string filename. 262 * @since 4.5.000 (2008-12-31) 263 * @public static 264 */ 265 public static function getObjFilename($type='tmp', $file_id='') { 266 return tempnam(K_PATH_CACHE, '__tcpdf_'.$file_id.'_'.$type.'_'.md5(TCPDF_STATIC::getRandomSeed()).'_'); 267 } 268 269 /** 270 * Add "\" before "\", "(" and ")" 271 * @param string $s string to escape. 272 * @return string escaped string. 273 * @public static 274 */ 275 public static function _escape($s) { 276 // the chr(13) substitution fixes the Bugs item #1421290. 277 return strtr($s, array(')' => '\\)', '(' => '\\(', '\\' => '\\\\', chr(13) => '\r')); 278 } 279 280 /** 281 * Escape some special characters (< > &) for XML output. 282 * @param string $str Input string to convert. 283 * @return string converted string 284 * @since 5.9.121 (2011-09-28) 285 * @public static 286 */ 287 public static function _escapeXML($str) { 288 $replaceTable = array("\0" => '', '&' => '&', '<' => '<', '>' => '>'); 289 $str = strtr($str === null ? '' : $str, $replaceTable); 290 return $str; 291 } 292 293 /** 294 * Creates a copy of a class object 295 * @param object $object class object to be cloned 296 * @return object cloned object 297 * @since 4.5.029 (2009-03-19) 298 * @public static 299 */ 300 public static function objclone($object) { 301 if (($object instanceof Imagick) AND (version_compare(phpversion('imagick'), '3.0.1') !== 1)) { 302 // on the versions after 3.0.1 the clone() method was deprecated in favour of clone keyword 303 return @$object->clone(); 304 } 305 return @clone($object); 306 } 307 308 /** 309 * Output input data and compress it if possible. 310 * @param string $data Data to output. 311 * @param int $length Data length in bytes. 312 * @since 5.9.086 313 * @public static 314 */ 315 public static function sendOutputData($data, $length) { 316 if (!isset($_SERVER['HTTP_ACCEPT_ENCODING']) OR empty($_SERVER['HTTP_ACCEPT_ENCODING'])) { 317 // the content length may vary if the server is using compression 318 header('Content-Length: '.$length); 319 } 320 echo $data; 321 } 322 323 /** 324 * Replace page number aliases with number. 325 * @param string $page Page content. 326 * @param array $replace Array of replacements (array keys are replacement strings, values are alias arrays). 327 * @param int $diff If passed, this will be set to the total char number difference between alias and replacements. 328 * @return array replaced page content and updated $diff parameter as array. 329 * @public static 330 */ 331 public static function replacePageNumAliases($page, $replace, $diff=0) { 332 foreach ($replace as $rep) { 333 foreach ($rep[3] as $a) { 334 if (strpos($page, $a) !== false) { 335 $page = str_replace($a, $rep[0], $page); 336 $diff += ($rep[2] - $rep[1]); 337 } 338 } 339 } 340 return array($page, $diff); 341 } 342 343 /** 344 * Returns timestamp in seconds from formatted date-time. 345 * @param string $date Formatted date-time. 346 * @return int seconds. 347 * @since 5.9.152 (2012-03-23) 348 * @public static 349 */ 350 public static function getTimestamp($date) { 351 if (($date[0] == 'D') AND ($date[1] == ':')) { 352 // remove date prefix if present 353 $date = substr($date, 2); 354 } 355 return strtotime($date); 356 } 357 358 /** 359 * Returns a formatted date-time. 360 * @param int $time Time in seconds. 361 * @return string escaped date string. 362 * @since 5.9.152 (2012-03-23) 363 * @public static 364 */ 365 public static function getFormattedDate($time) { 366 return substr_replace(date('YmdHisO', intval($time)), '\'', (0 - 2), 0).'\''; 367 } 368 369 /** 370 * Returns a string containing random data to be used as a seed for encryption methods. 371 * @param string $seed starting seed value 372 * @return string containing random data 373 * @author Nicola Asuni 374 * @since 5.9.006 (2010-10-19) 375 * @public static 376 */ 377 public static function getRandomSeed($seed='') { 378 $rnd = uniqid(rand().microtime(true), true); 379 if (function_exists('posix_getpid')) { 380 $rnd .= posix_getpid(); 381 } 382 if (function_exists('openssl_random_pseudo_bytes') AND (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN')) { 383 // this is not used on windows systems because it is very slow for a know bug 384 $rnd .= openssl_random_pseudo_bytes(512); 385 } else { 386 for ($i = 0; $i < 23; ++$i) { 387 $rnd .= uniqid('', true); 388 } 389 } 390 return $rnd.$seed.__FILE__.serialize($_SERVER).microtime(true); 391 } 392 393 /** 394 * Encrypts a string using MD5 and returns it's value as a binary string. 395 * @param string $str input string 396 * @return string MD5 encrypted binary string 397 * @since 2.0.000 (2008-01-02) 398 * @public static 399 */ 400 public static function _md5_16($str) { 401 return pack('H*', md5($str)); 402 } 403 404 /** 405 * Returns the input text encrypted using AES algorithm and the specified key. 406 * This method requires openssl or mcrypt. Text is padded to 16bytes blocks 407 * @param string $key encryption key 408 * @param string $text input text to be encrypted 409 * @return string encrypted text 410 * @author Nicola Asuni 411 * @since 5.0.005 (2010-05-11) 412 * @public static 413 */ 414 public static function _AES($key, $text) { 415 // padding (RFC 2898, PKCS #5: Password-Based Cryptography Specification Version 2.0) 416 $padding = 16 - (strlen($text) % 16); 417 $text .= str_repeat(chr($padding), $padding); 418 if (extension_loaded('openssl')) { 419 $algo = 'aes-256-cbc'; 420 if (strlen($key) == 16) { 421 $algo = 'aes-128-cbc'; 422 } 423 $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($algo)); 424 $text = openssl_encrypt($text, $algo, $key, OPENSSL_RAW_DATA, $iv); 425 return $iv.substr($text, 0, -16); 426 } 427 $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC), MCRYPT_RAND); 428 $text = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $text, MCRYPT_MODE_CBC, $iv); 429 $text = $iv.$text; 430 return $text; 431 } 432 433 /** 434 * Returns the input text encrypted using AES algorithm and the specified key. 435 * This method requires openssl or mcrypt. Text is not padded 436 * @param string $key encryption key 437 * @param string $text input text to be encrypted 438 * @return string encrypted text 439 * @author Nicola Asuni 440 * @since TODO 441 * @public static 442 */ 443 public static function _AESnopad($key, $text) { 444 if (extension_loaded('openssl')) { 445 $algo = 'aes-256-cbc'; 446 if (strlen($key) == 16) { 447 $algo = 'aes-128-cbc'; 448 } 449 $iv = str_repeat("\x00", openssl_cipher_iv_length($algo)); 450 $text = openssl_encrypt($text, $algo, $key, OPENSSL_RAW_DATA, $iv); 451 return substr($text, 0, -16); 452 } 453 $iv = str_repeat("\x00", mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC)); 454 $text = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $text, MCRYPT_MODE_CBC, $iv); 455 return $text; 456 } 457 458 /** 459 * Returns the input text encrypted using RC4 algorithm and the specified key. 460 * RC4 is the standard encryption algorithm used in PDF format 461 * @param string $key Encryption key. 462 * @param string $text Input text to be encrypted. 463 * @param string $last_enc_key Reference to last RC4 key encrypted. 464 * @param string $last_enc_key_c Reference to last RC4 computed key. 465 * @return string encrypted text 466 * @since 2.0.000 (2008-01-02) 467 * @author Klemen Vodopivec, Nicola Asuni 468 * @public static 469 */ 470 public static function _RC4($key, $text, &$last_enc_key, &$last_enc_key_c) { 471 if (function_exists('mcrypt_encrypt') AND ($out = @mcrypt_encrypt(MCRYPT_ARCFOUR, $key, $text, MCRYPT_MODE_STREAM, ''))) { 472 // try to use mcrypt function if exist 473 return $out; 474 } 475 if ($last_enc_key != $key) { 476 $k = str_repeat($key, (int) ((256 / strlen($key)) + 1)); 477 $rc4 = range(0, 255); 478 $j = 0; 479 for ($i = 0; $i < 256; ++$i) { 480 $t = $rc4[$i]; 481 $j = ($j + $t + ord($k[$i])) % 256; 482 $rc4[$i] = $rc4[$j]; 483 $rc4[$j] = $t; 484 } 485 $last_enc_key = $key; 486 $last_enc_key_c = $rc4; 487 } else { 488 $rc4 = $last_enc_key_c; 489 } 490 $len = strlen($text); 491 $a = 0; 492 $b = 0; 493 $out = ''; 494 for ($i = 0; $i < $len; ++$i) { 495 $a = ($a + 1) % 256; 496 $t = $rc4[$a]; 497 $b = ($b + $t) % 256; 498 $rc4[$a] = $rc4[$b]; 499 $rc4[$b] = $t; 500 $k = $rc4[($rc4[$a] + $rc4[$b]) % 256]; 501 $out .= chr(ord($text[$i]) ^ $k); 502 } 503 return $out; 504 } 505 506 /** 507 * Return the permission code used on encryption (P value). 508 * @param array $permissions the set of permissions (specify the ones you want to block). 509 * @param int $mode encryption strength: 0 = RC4 40 bit; 1 = RC4 128 bit; 2 = AES 128 bit; 3 = AES 256 bit. 510 * @since 5.0.005 (2010-05-12) 511 * @author Nicola Asuni 512 * @public static 513 */ 514 public static function getUserPermissionCode($permissions, $mode=0) { 515 $options = array( 516 'owner' => 2, // bit 2 -- inverted logic: cleared by default 517 'print' => 4, // bit 3 518 'modify' => 8, // bit 4 519 'copy' => 16, // bit 5 520 'annot-forms' => 32, // bit 6 521 'fill-forms' => 256, // bit 9 522 'extract' => 512, // bit 10 523 'assemble' => 1024,// bit 11 524 'print-high' => 2048 // bit 12 525 ); 526 $protection = 2147422012; // 32 bit: (01111111 11111111 00001111 00111100) 527 foreach ($permissions as $permission) { 528 if (isset($options[$permission])) { 529 if (($mode > 0) OR ($options[$permission] <= 32)) { 530 // set only valid permissions 531 if ($options[$permission] == 2) { 532 // the logic for bit 2 is inverted (cleared by default) 533 $protection += $options[$permission]; 534 } else { 535 $protection -= $options[$permission]; 536 } 537 } 538 } 539 } 540 return $protection; 541 } 542 543 /** 544 * Convert hexadecimal string to string 545 * @param string $bs byte-string to convert 546 * @return string 547 * @since 5.0.005 (2010-05-12) 548 * @author Nicola Asuni 549 * @public static 550 */ 551 public static function convertHexStringToString($bs) { 552 $string = ''; // string to be returned 553 $bslength = strlen($bs); 554 if (($bslength % 2) != 0) { 555 // padding 556 $bs .= '0'; 557 ++$bslength; 558 } 559 for ($i = 0; $i < $bslength; $i += 2) { 560 $string .= chr(hexdec($bs[$i].$bs[($i + 1)])); 561 } 562 return $string; 563 } 564 565 /** 566 * Convert string to hexadecimal string (byte string) 567 * @param string $s string to convert 568 * @return string byte string 569 * @since 5.0.010 (2010-05-17) 570 * @author Nicola Asuni 571 * @public static 572 */ 573 public static function convertStringToHexString($s) { 574 $bs = ''; 575 $chars = preg_split('//', $s, -1, PREG_SPLIT_NO_EMPTY); 576 foreach ($chars as $c) { 577 $bs .= sprintf('%02s', dechex(ord($c))); 578 } 579 return $bs; 580 } 581 582 /** 583 * Convert encryption P value to a string of bytes, low-order byte first. 584 * @param string $protection 32bit encryption permission value (P value) 585 * @return string 586 * @since 5.0.005 (2010-05-12) 587 * @author Nicola Asuni 588 * @public static 589 */ 590 public static function getEncPermissionsString($protection) { 591 $binprot = sprintf('%032b', $protection); 592 $str = chr(bindec(substr($binprot, 24, 8))); 593 $str .= chr(bindec(substr($binprot, 16, 8))); 594 $str .= chr(bindec(substr($binprot, 8, 8))); 595 $str .= chr(bindec(substr($binprot, 0, 8))); 596 return $str; 597 } 598 599 /** 600 * Encode a name object. 601 * @param string $name Name object to encode. 602 * @return string Encoded name object. 603 * @author Nicola Asuni 604 * @since 5.9.097 (2011-06-23) 605 * @public static 606 */ 607 public static function encodeNameObject($name) { 608 $escname = ''; 609 $length = strlen($name); 610 for ($i = 0; $i < $length; ++$i) { 611 $chr = $name[$i]; 612 if (preg_match('/[0-9a-zA-Z#_=-]/', $chr) == 1) { 613 $escname .= $chr; 614 } else { 615 $escname .= sprintf('#%02X', ord($chr)); 616 } 617 } 618 return $escname; 619 } 620 621 /** 622 * Convert JavaScript form fields properties array to Annotation Properties array. 623 * @param array $prop javascript field properties. Possible values are described on official Javascript for Acrobat API reference. 624 * @param array $spot_colors Reference to spot colors array. 625 * @param boolean $rtl True if in Right-To-Left text direction mode, false otherwise. 626 * @return array of annotation properties 627 * @author Nicola Asuni 628 * @since 4.8.000 (2009-09-06) 629 * @public static 630 */ 631 public static function getAnnotOptFromJSProp($prop, &$spot_colors, $rtl=false) { 632 if (isset($prop['aopt']) AND is_array($prop['aopt'])) { 633 // the annotation options are already defined 634 return $prop['aopt']; 635 } 636 $opt = array(); // value to be returned 637 // alignment: Controls how the text is laid out within the text field. 638 if (isset($prop['alignment'])) { 639 switch ($prop['alignment']) { 640 case 'left': { 641 $opt['q'] = 0; 642 break; 643 } 644 case 'center': { 645 $opt['q'] = 1; 646 break; 647 } 648 case 'right': { 649 $opt['q'] = 2; 650 break; 651 } 652 default: { 653 $opt['q'] = ($rtl)?2:0; 654 break; 655 } 656 } 657 } 658 // lineWidth: Specifies the thickness of the border when stroking the perimeter of a field's rectangle. 659 if (isset($prop['lineWidth'])) { 660 $linewidth = intval($prop['lineWidth']); 661 } else { 662 $linewidth = 1; 663 } 664 // borderStyle: The border style for a field. 665 if (isset($prop['borderStyle'])) { 666 switch ($prop['borderStyle']) { 667 case 'border.d': 668 case 'dashed': { 669 $opt['border'] = array(0, 0, $linewidth, array(3, 2)); 670 $opt['bs'] = array('w'=>$linewidth, 's'=>'D', 'd'=>array(3, 2)); 671 break; 672 } 673 case 'border.b': 674 case 'beveled': { 675 $opt['border'] = array(0, 0, $linewidth); 676 $opt['bs'] = array('w'=>$linewidth, 's'=>'B'); 677 break; 678 } 679 case 'border.i': 680 case 'inset': { 681 $opt['border'] = array(0, 0, $linewidth); 682 $opt['bs'] = array('w'=>$linewidth, 's'=>'I'); 683 break; 684 } 685 case 'border.u': 686 case 'underline': { 687 $opt['border'] = array(0, 0, $linewidth); 688 $opt['bs'] = array('w'=>$linewidth, 's'=>'U'); 689 break; 690 } 691 case 'border.s': 692 case 'solid': { 693 $opt['border'] = array(0, 0, $linewidth); 694 $opt['bs'] = array('w'=>$linewidth, 's'=>'S'); 695 break; 696 } 697 default: { 698 break; 699 } 700 } 701 } 702 if (isset($prop['border']) AND is_array($prop['border'])) { 703 $opt['border'] = $prop['border']; 704 } 705 if (!isset($opt['mk'])) { 706 $opt['mk'] = array(); 707 } 708 if (!isset($opt['mk']['if'])) { 709 $opt['mk']['if'] = array(); 710 } 711 $opt['mk']['if']['a'] = array(0.5, 0.5); 712 // buttonAlignX: Controls how space is distributed from the left of the button face with respect to the icon. 713 if (isset($prop['buttonAlignX'])) { 714 $opt['mk']['if']['a'][0] = $prop['buttonAlignX']; 715 } 716 // buttonAlignY: Controls how unused space is distributed from the bottom of the button face with respect to the icon. 717 if (isset($prop['buttonAlignY'])) { 718 $opt['mk']['if']['a'][1] = $prop['buttonAlignY']; 719 } 720 // buttonFitBounds: If true, the extent to which the icon may be scaled is set to the bounds of the button field. 721 if (isset($prop['buttonFitBounds']) AND ($prop['buttonFitBounds'] == 'true')) { 722 $opt['mk']['if']['fb'] = true; 723 } 724 // buttonScaleHow: Controls how the icon is scaled (if necessary) to fit inside the button face. 725 if (isset($prop['buttonScaleHow'])) { 726 switch ($prop['buttonScaleHow']) { 727 case 'scaleHow.proportional': { 728 $opt['mk']['if']['s'] = 'P'; 729 break; 730 } 731 case 'scaleHow.anamorphic': { 732 $opt['mk']['if']['s'] = 'A'; 733 break; 734 } 735 } 736 } 737 // buttonScaleWhen: Controls when an icon is scaled to fit inside the button face. 738 if (isset($prop['buttonScaleWhen'])) { 739 switch ($prop['buttonScaleWhen']) { 740 case 'scaleWhen.always': { 741 $opt['mk']['if']['sw'] = 'A'; 742 break; 743 } 744 case 'scaleWhen.never': { 745 $opt['mk']['if']['sw'] = 'N'; 746 break; 747 } 748 case 'scaleWhen.tooBig': { 749 $opt['mk']['if']['sw'] = 'B'; 750 break; 751 } 752 case 'scaleWhen.tooSmall': { 753 $opt['mk']['if']['sw'] = 'S'; 754 break; 755 } 756 } 757 } 758 // buttonPosition: Controls how the text and the icon of the button are positioned with respect to each other within the button face. 759 if (isset($prop['buttonPosition'])) { 760 switch ($prop['buttonPosition']) { 761 case 0: 762 case 'position.textOnly': { 763 $opt['mk']['tp'] = 0; 764 break; 765 } 766 case 1: 767 case 'position.iconOnly': { 768 $opt['mk']['tp'] = 1; 769 break; 770 } 771 case 2: 772 case 'position.iconTextV': { 773 $opt['mk']['tp'] = 2; 774 break; 775 } 776 case 3: 777 case 'position.textIconV': { 778 $opt['mk']['tp'] = 3; 779 break; 780 } 781 case 4: 782 case 'position.iconTextH': { 783 $opt['mk']['tp'] = 4; 784 break; 785 } 786 case 5: 787 case 'position.textIconH': { 788 $opt['mk']['tp'] = 5; 789 break; 790 } 791 case 6: 792 case 'position.overlay': { 793 $opt['mk']['tp'] = 6; 794 break; 795 } 796 } 797 } 798 // fillColor: Specifies the background color for a field. 799 if (isset($prop['fillColor'])) { 800 if (is_array($prop['fillColor'])) { 801 $opt['mk']['bg'] = $prop['fillColor']; 802 } else { 803 $opt['mk']['bg'] = TCPDF_COLORS::convertHTMLColorToDec($prop['fillColor'], $spot_colors); 804 } 805 } 806 // strokeColor: Specifies the stroke color for a field that is used to stroke the rectangle of the field with a line as large as the line width. 807 if (isset($prop['strokeColor'])) { 808 if (is_array($prop['strokeColor'])) { 809 $opt['mk']['bc'] = $prop['strokeColor']; 810 } else { 811 $opt['mk']['bc'] = TCPDF_COLORS::convertHTMLColorToDec($prop['strokeColor'], $spot_colors); 812 } 813 } 814 // rotation: The rotation of a widget in counterclockwise increments. 815 if (isset($prop['rotation'])) { 816 $opt['mk']['r'] = $prop['rotation']; 817 } 818 // charLimit: Limits the number of characters that a user can type into a text field. 819 if (isset($prop['charLimit'])) { 820 $opt['maxlen'] = intval($prop['charLimit']); 821 } 822 $ff = 0; 823 // readonly: The read-only characteristic of a field. If a field is read-only, the user can see the field but cannot change it. 824 if (isset($prop['readonly']) AND ($prop['readonly'] == 'true')) { 825 $ff += 1 << 0; 826 } 827 // required: Specifies whether a field requires a value. 828 if (isset($prop['required']) AND ($prop['required'] == 'true')) { 829 $ff += 1 << 1; 830 } 831 // multiline: Controls how text is wrapped within the field. 832 if (isset($prop['multiline']) AND ($prop['multiline'] == 'true')) { 833 $ff += 1 << 12; 834 } 835 // password: Specifies whether the field should display asterisks when data is entered in the field. 836 if (isset($prop['password']) AND ($prop['password'] == 'true')) { 837 $ff += 1 << 13; 838 } 839 // NoToggleToOff: If set, exactly one radio button shall be selected at all times; selecting the currently selected button has no effect. 840 if (isset($prop['NoToggleToOff']) AND ($prop['NoToggleToOff'] == 'true')) { 841 $ff += 1 << 14; 842 } 843 // Radio: If set, the field is a set of radio buttons. 844 if (isset($prop['Radio']) AND ($prop['Radio'] == 'true')) { 845 $ff += 1 << 15; 846 } 847 // Pushbutton: If set, the field is a pushbutton that does not retain a permanent value. 848 if (isset($prop['Pushbutton']) AND ($prop['Pushbutton'] == 'true')) { 849 $ff += 1 << 16; 850 } 851 // Combo: If set, the field is a combo box; if clear, the field is a list box. 852 if (isset($prop['Combo']) AND ($prop['Combo'] == 'true')) { 853 $ff += 1 << 17; 854 } 855 // editable: Controls whether a combo box is editable. 856 if (isset($prop['editable']) AND ($prop['editable'] == 'true')) { 857 $ff += 1 << 18; 858 } 859 // Sort: If set, the field's option items shall be sorted alphabetically. 860 if (isset($prop['Sort']) AND ($prop['Sort'] == 'true')) { 861 $ff += 1 << 19; 862 } 863 // fileSelect: If true, sets the file-select flag in the Options tab of the text field (Field is Used for File Selection). 864 if (isset($prop['fileSelect']) AND ($prop['fileSelect'] == 'true')) { 865 $ff += 1 << 20; 866 } 867 // multipleSelection: If true, indicates that a list box allows a multiple selection of items. 868 if (isset($prop['multipleSelection']) AND ($prop['multipleSelection'] == 'true')) { 869 $ff += 1 << 21; 870 } 871 // doNotSpellCheck: If true, spell checking is not performed on this editable text field. 872 if (isset($prop['doNotSpellCheck']) AND ($prop['doNotSpellCheck'] == 'true')) { 873 $ff += 1 << 22; 874 } 875 // doNotScroll: If true, the text field does not scroll and the user, therefore, is limited by the rectangular region designed for the field. 876 if (isset($prop['doNotScroll']) AND ($prop['doNotScroll'] == 'true')) { 877 $ff += 1 << 23; 878 } 879 // comb: If set to true, the field background is drawn as series of boxes (one for each character in the value of the field) and each character of the content is drawn within those boxes. The number of boxes drawn is determined from the charLimit property. It applies only to text fields. The setter will also raise if any of the following field properties are also set multiline, password, and fileSelect. A side-effect of setting this property is that the doNotScroll property is also set. 880 if (isset($prop['comb']) AND ($prop['comb'] == 'true')) { 881 $ff += 1 << 24; 882 } 883 // radiosInUnison: If false, even if a group of radio buttons have the same name and export value, they behave in a mutually exclusive fashion, like HTML radio buttons. 884 if (isset($prop['radiosInUnison']) AND ($prop['radiosInUnison'] == 'true')) { 885 $ff += 1 << 25; 886 } 887 // richText: If true, the field allows rich text formatting. 888 if (isset($prop['richText']) AND ($prop['richText'] == 'true')) { 889 $ff += 1 << 25; 890 } 891 // commitOnSelChange: Controls whether a field value is committed after a selection change. 892 if (isset($prop['commitOnSelChange']) AND ($prop['commitOnSelChange'] == 'true')) { 893 $ff += 1 << 26; 894 } 895 $opt['ff'] = $ff; 896 // defaultValue: The default value of a field - that is, the value that the field is set to when the form is reset. 897 if (isset($prop['defaultValue'])) { 898 $opt['dv'] = $prop['defaultValue']; 899 } 900 $f = 4; // default value for annotation flags 901 // readonly: The read-only characteristic of a field. If a field is read-only, the user can see the field but cannot change it. 902 if (isset($prop['readonly']) AND ($prop['readonly'] == 'true')) { 903 $f += 1 << 6; 904 } 905 // display: Controls whether the field is hidden or visible on screen and in print. 906 if (isset($prop['display'])) { 907 if ($prop['display'] == 'display.visible') { 908 // 909 } elseif ($prop['display'] == 'display.hidden') { 910 $f += 1 << 1; 911 } elseif ($prop['display'] == 'display.noPrint') { 912 $f -= 1 << 2; 913 } elseif ($prop['display'] == 'display.noView') { 914 $f += 1 << 5; 915 } 916 } 917 $opt['f'] = $f; 918 // currentValueIndices: Reads and writes single or multiple values of a list box or combo box. 919 if (isset($prop['currentValueIndices']) AND is_array($prop['currentValueIndices'])) { 920 $opt['i'] = $prop['currentValueIndices']; 921 } 922 // value: The value of the field data that the user has entered. 923 if (isset($prop['value'])) { 924 if (is_array($prop['value'])) { 925 $opt['opt'] = array(); 926 foreach ($prop['value'] AS $key => $optval) { 927 // exportValues: An array of strings representing the export values for the field. 928 if (isset($prop['exportValues'][$key])) { 929 $opt['opt'][$key] = array($prop['exportValues'][$key], $prop['value'][$key]); 930 } else { 931 $opt['opt'][$key] = $prop['value'][$key]; 932 } 933 } 934 } else { 935 $opt['v'] = $prop['value']; 936 } 937 } 938 // richValue: This property specifies the text contents and formatting of a rich text field. 939 if (isset($prop['richValue'])) { 940 $opt['rv'] = $prop['richValue']; 941 } 942 // submitName: If nonempty, used during form submission instead of name. Only applicable if submitting in HTML format (that is, URL-encoded). 943 if (isset($prop['submitName'])) { 944 $opt['tm'] = $prop['submitName']; 945 } 946 // name: Fully qualified field name. 947 if (isset($prop['name'])) { 948 $opt['t'] = $prop['name']; 949 } 950 // userName: The user name (short description string) of the field. 951 if (isset($prop['userName'])) { 952 $opt['tu'] = $prop['userName']; 953 } 954 // highlight: Defines how a button reacts when a user clicks it. 955 if (isset($prop['highlight'])) { 956 switch ($prop['highlight']) { 957 case 'none': 958 case 'highlight.n': { 959 $opt['h'] = 'N'; 960 break; 961 } 962 case 'invert': 963 case 'highlight.i': { 964 $opt['h'] = 'i'; 965 break; 966 } 967 case 'push': 968 case 'highlight.p': { 969 $opt['h'] = 'P'; 970 break; 971 } 972 case 'outline': 973 case 'highlight.o': { 974 $opt['h'] = 'O'; 975 break; 976 } 977 } 978 } 979 // Unsupported options: 980 // - calcOrderIndex: Changes the calculation order of fields in the document. 981 // - delay: Delays the redrawing of a field's appearance. 982 // - defaultStyle: This property defines the default style attributes for the form field. 983 // - style: Allows the user to set the glyph style of a check box or radio button. 984 // - textColor, textFont, textSize 985 return $opt; 986 } 987 988 /** 989 * Format the page numbers. 990 * This method can be overridden for custom formats. 991 * @param int $num page number 992 * @return string 993 * @since 4.2.005 (2008-11-06) 994 * @public static 995 */ 996 public static function formatPageNumber($num) { 997 return number_format((float)$num, 0, '', '.'); 998 } 999 1000 /** 1001 * Format the page numbers on the Table Of Content. 1002 * This method can be overridden for custom formats. 1003 * @param int $num page number 1004 * @return string 1005 * @since 4.5.001 (2009-01-04) 1006 * @see addTOC(), addHTMLTOC() 1007 * @public static 1008 */ 1009 public static function formatTOCPageNumber($num) { 1010 return number_format((float)$num, 0, '', '.'); 1011 } 1012 1013 /** 1014 * Extracts the CSS properties from a CSS string. 1015 * @param string $cssdata string containing CSS definitions. 1016 * @return array An array where the keys are the CSS selectors and the values are the CSS properties. 1017 * @author Nicola Asuni 1018 * @since 5.1.000 (2010-05-25) 1019 * @public static 1020 */ 1021 public static function extractCSSproperties($cssdata) { 1022 if (empty($cssdata)) { 1023 return array(); 1024 } 1025 // remove comments 1026 $cssdata = preg_replace('/\/\*[^\*]*\*\//', '', $cssdata); 1027 // remove newlines and multiple spaces 1028 $cssdata = preg_replace('/[\s]+/', ' ', $cssdata); 1029 // remove some spaces 1030 $cssdata = preg_replace('/[\s]*([;:\{\}]{1})[\s]*/', '\\1', $cssdata); 1031 // remove empty blocks 1032 $cssdata = preg_replace('/([^\}\{]+)\{\}/', '', $cssdata); 1033 // replace media type parenthesis 1034 $cssdata = preg_replace('/@media[\s]+([^\{]*)\{/i', '@media \\1§', $cssdata); 1035 $cssdata = preg_replace('/\}\}/si', '}§', $cssdata); 1036 // trim string 1037 $cssdata = trim($cssdata); 1038 // find media blocks (all, braille, embossed, handheld, print, projection, screen, speech, tty, tv) 1039 $cssblocks = array(); 1040 $matches = array(); 1041 if (preg_match_all('/@media[\s]+([^\§]*)§([^§]*)§/i', $cssdata, $matches) > 0) { 1042 foreach ($matches[1] as $key => $type) { 1043 $cssblocks[$type] = $matches[2][$key]; 1044 } 1045 // remove media blocks 1046 $cssdata = preg_replace('/@media[\s]+([^\§]*)§([^§]*)§/i', '', $cssdata); 1047 } 1048 // keep 'all' and 'print' media, other media types are discarded 1049 if (isset($cssblocks['all']) AND !empty($cssblocks['all'])) { 1050 $cssdata .= $cssblocks['all']; 1051 } 1052 if (isset($cssblocks['print']) AND !empty($cssblocks['print'])) { 1053 $cssdata .= $cssblocks['print']; 1054 } 1055 // reset css blocks array 1056 $cssblocks = array(); 1057 $matches = array(); 1058 // explode css data string into array 1059 if (substr($cssdata, -1) == '}') { 1060 // remove last parethesis 1061 $cssdata = substr($cssdata, 0, -1); 1062 } 1063 $matches = explode('}', $cssdata); 1064 foreach ($matches as $key => $block) { 1065 // index 0 contains the CSS selector, index 1 contains CSS properties 1066 $cssblocks[$key] = explode('{', $block); 1067 if (!isset($cssblocks[$key][1])) { 1068 // remove empty definitions 1069 unset($cssblocks[$key]); 1070 } 1071 } 1072 // split groups of selectors (comma-separated list of selectors) 1073 foreach ($cssblocks as $key => $block) { 1074 if (strpos($block[0], ',') > 0) { 1075 $selectors = explode(',', $block[0]); 1076 foreach ($selectors as $sel) { 1077 $cssblocks[] = array(0 => trim($sel), 1 => $block[1]); 1078 } 1079 unset($cssblocks[$key]); 1080 } 1081 } 1082 // covert array to selector => properties 1083 $cssdata = array(); 1084 foreach ($cssblocks as $block) { 1085 $selector = $block[0]; 1086 // calculate selector's specificity 1087 $matches = array(); 1088 $a = 0; // the declaration is not from is a 'style' attribute 1089 $b = intval(preg_match_all('/[\#]/', $selector, $matches)); // number of ID attributes 1090 $c = intval(preg_match_all('/[\[\.]/', $selector, $matches)); // number of other attributes 1091 $c += intval(preg_match_all('/[\:]link|visited|hover|active|focus|target|lang|enabled|disabled|checked|indeterminate|root|nth|first|last|only|empty|contains|not/i', $selector, $matches)); // number of pseudo-classes 1092 $d = intval(preg_match_all('/[\>\+\~\s]{1}[a-zA-Z0-9]+/', ' '.$selector, $matches)); // number of element names 1093 $d += intval(preg_match_all('/[\:][\:]/', $selector, $matches)); // number of pseudo-elements 1094 $specificity = $a.$b.$c.$d; 1095 // add specificity to the beginning of the selector 1096 $cssdata[$specificity.' '.$selector] = $block[1]; 1097 } 1098 // sort selectors alphabetically to account for specificity 1099 ksort($cssdata, SORT_STRING); 1100 // return array 1101 return $cssdata; 1102 } 1103 1104 /** 1105 * Cleanup HTML code (requires HTML Tidy library). 1106 * @param string $html htmlcode to fix 1107 * @param string $default_css CSS commands to add 1108 * @param array|null $tagvs parameters for setHtmlVSpace method 1109 * @param array|null $tidy_options options for tidy_parse_string function 1110 * @param array $tagvspaces Array of vertical spaces for tags. 1111 * @return string XHTML code cleaned up 1112 * @author Nicola Asuni 1113 * @since 5.9.017 (2010-11-16) 1114 * @see setHtmlVSpace() 1115 * @public static 1116 */ 1117 public static function fixHTMLCode($html, $default_css, $tagvs, $tidy_options, &$tagvspaces) { 1118 // configure parameters for HTML Tidy 1119 if (TCPDF_STATIC::empty_string($tidy_options)) { 1120 $tidy_options = array ( 1121 'clean' => 1, 1122 'drop-empty-paras' => 0, 1123 'drop-proprietary-attributes' => 1, 1124 'fix-backslash' => 1, 1125 'hide-comments' => 1, 1126 'join-styles' => 1, 1127 'lower-literals' => 1, 1128 'merge-divs' => 1, 1129 'merge-spans' => 1, 1130 'output-xhtml' => 1, 1131 'word-2000' => 1, 1132 'wrap' => 0, 1133 'output-bom' => 0, 1134 //'char-encoding' => 'utf8', 1135 //'input-encoding' => 'utf8', 1136 //'output-encoding' => 'utf8' 1137 ); 1138 } 1139 // clean up the HTML code 1140 $tidy = tidy_parse_string($html, $tidy_options); 1141 // fix the HTML 1142 $tidy->cleanRepair(); 1143 // get the CSS part 1144 $tidy_head = tidy_get_head($tidy); 1145 $css = $tidy_head->value; 1146 $css = preg_replace('/<style([^>]+)>/ims', '<style>', $css); 1147 $css = preg_replace('/<\/style>(.*)<style>/ims', "\n", $css); 1148 $css = str_replace('/*<![CDATA[*/', '', $css); 1149 $css = str_replace('/*]]>*/', '', $css); 1150 preg_match('/<style>(.*)<\/style>/ims', $css, $matches); 1151 if (isset($matches[1])) { 1152 $css = strtolower($matches[1]); 1153 } else { 1154 $css = ''; 1155 } 1156 // include default css 1157 $css = '<style>'.$default_css.$css.'</style>'; 1158 // get the body part 1159 $tidy_body = tidy_get_body($tidy); 1160 $html = $tidy_body->value; 1161 // fix some self-closing tags 1162 $html = str_replace('<br>', '<br />', $html); 1163 // remove some empty tag blocks 1164 $html = preg_replace('/<div([^\>]*)><\/div>/', '', $html); 1165 $html = preg_replace('/<p([^\>]*)><\/p>/', '', $html); 1166 if (!TCPDF_STATIC::empty_string($tagvs)) { 1167 // set vertical space for some XHTML tags 1168 $tagvspaces = $tagvs; 1169 } 1170 // return the cleaned XHTML code + CSS 1171 return $css.$html; 1172 } 1173 1174 /** 1175 * Returns true if the CSS selector is valid for the selected HTML tag 1176 * @param array $dom array of HTML tags and properties 1177 * @param int $key key of the current HTML tag 1178 * @param string $selector CSS selector string 1179 * @return true if the selector is valid, false otherwise 1180 * @since 5.1.000 (2010-05-25) 1181 * @public static 1182 */ 1183 public static function isValidCSSSelectorForTag($dom, $key, $selector) { 1184 $valid = false; // value to be returned 1185 $tag = $dom[$key]['value']; 1186 $class = array(); 1187 if (isset($dom[$key]['attribute']['class']) AND !empty($dom[$key]['attribute']['class'])) { 1188 $class = explode(' ', strtolower($dom[$key]['attribute']['class'])); 1189 } 1190 $id = ''; 1191 if (isset($dom[$key]['attribute']['id']) AND !empty($dom[$key]['attribute']['id'])) { 1192 $id = strtolower($dom[$key]['attribute']['id']); 1193 } 1194 $selector = preg_replace('/([\>\+\~\s]{1})([\.]{1})([^\>\+\~\s]*)/si', '\\1*.\\3', $selector); 1195 $matches = array(); 1196 if (preg_match_all('/([\>\+\~\s]{1})([a-zA-Z0-9\*]+)([^\>\+\~\s]*)/si', $selector, $matches, PREG_PATTERN_ORDER | PREG_OFFSET_CAPTURE) > 0) { 1197 $parentop = array_pop($matches[1]); 1198 $operator = $parentop[0]; 1199 $offset = $parentop[1]; 1200 $lasttag = array_pop($matches[2]); 1201 $lasttag = strtolower(trim($lasttag[0])); 1202 if (($lasttag == '*') OR ($lasttag == $tag)) { 1203 // the last element on selector is our tag or 'any tag' 1204 $attrib = array_pop($matches[3]); 1205 $attrib = strtolower(trim($attrib[0])); 1206 if (!empty($attrib)) { 1207 // check if matches class, id, attribute, pseudo-class or pseudo-element 1208 switch ($attrib[0]) { 1209 case '.': { // class 1210 if (in_array(substr($attrib, 1), $class)) { 1211 $valid = true; 1212 } 1213 break; 1214 } 1215 case '#': { // ID 1216 if (substr($attrib, 1) == $id) { 1217 $valid = true; 1218 } 1219 break; 1220 } 1221 case '[': { // attribute 1222 $attrmatch = array(); 1223 if (preg_match('/\[([a-zA-Z0-9]*)[\s]*([\~\^\$\*\|\=]*)[\s]*["]?([^"\]]*)["]?\]/i', $attrib, $attrmatch) > 0) { 1224 $att = strtolower($attrmatch[1]); 1225 $val = $attrmatch[3]; 1226 if (isset($dom[$key]['attribute'][$att])) { 1227 switch ($attrmatch[2]) { 1228 case '=': { 1229 if ($dom[$key]['attribute'][$att] == $val) { 1230 $valid = true; 1231 } 1232 break; 1233 } 1234 case '~=': { 1235 if (in_array($val, explode(' ', $dom[$key]['attribute'][$att]))) { 1236 $valid = true; 1237 } 1238 break; 1239 } 1240 case '^=': { 1241 if ($val == substr($dom[$key]['attribute'][$att], 0, strlen($val))) { 1242 $valid = true; 1243 } 1244 break; 1245 } 1246 case '$=': { 1247 if ($val == substr($dom[$key]['attribute'][$att], -strlen($val))) { 1248 $valid = true; 1249 } 1250 break; 1251 } 1252 case '*=': { 1253 if (strpos($dom[$key]['attribute'][$att], $val) !== false) { 1254 $valid = true; 1255 } 1256 break; 1257 } 1258 case '|=': { 1259 if ($dom[$key]['attribute'][$att] == $val) { 1260 $valid = true; 1261 } elseif (preg_match('/'.$val.'[\-]{1}/i', $dom[$key]['attribute'][$att]) > 0) { 1262 $valid = true; 1263 } 1264 break; 1265 } 1266 default: { 1267 $valid = true; 1268 } 1269 } 1270 } 1271 } 1272 break; 1273 } 1274 case ':': { // pseudo-class or pseudo-element 1275 if ($attrib[1] == ':') { // pseudo-element 1276 // pseudo-elements are not supported! 1277 // (::first-line, ::first-letter, ::before, ::after) 1278 } else { // pseudo-class 1279 // pseudo-classes are not supported! 1280 // (:root, :nth-child(n), :nth-last-child(n), :nth-of-type(n), :nth-last-of-type(n), :first-child, :last-child, :first-of-type, :last-of-type, :only-child, :only-of-type, :empty, :link, :visited, :active, :hover, :focus, :target, :lang(fr), :enabled, :disabled, :checked) 1281 } 1282 break; 1283 } 1284 } // end of switch 1285 } else { 1286 $valid = true; 1287 } 1288 if ($valid AND ($offset > 0)) { 1289 $valid = false; 1290 // check remaining selector part 1291 $selector = substr($selector, 0, $offset); 1292 switch ($operator) { 1293 case ' ': { // descendant of an element 1294 while ($dom[$key]['parent'] > 0) { 1295 if (self::isValidCSSSelectorForTag($dom, $dom[$key]['parent'], $selector)) { 1296 $valid = true; 1297 break; 1298 } else { 1299 $key = $dom[$key]['parent']; 1300 } 1301 } 1302 break; 1303 } 1304 case '>': { // child of an element 1305 $valid = self::isValidCSSSelectorForTag($dom, $dom[$key]['parent'], $selector); 1306 break; 1307 } 1308 case '+': { // immediately preceded by an element 1309 for ($i = ($key - 1); $i > $dom[$key]['parent']; --$i) { 1310 if ($dom[$i]['tag'] AND $dom[$i]['opening']) { 1311 $valid = self::isValidCSSSelectorForTag($dom, $i, $selector); 1312 break; 1313 } 1314 } 1315 break; 1316 } 1317 case '~': { // preceded by an element 1318 for ($i = ($key - 1); $i > $dom[$key]['parent']; --$i) { 1319 if ($dom[$i]['tag'] AND $dom[$i]['opening']) { 1320 if (self::isValidCSSSelectorForTag($dom, $i, $selector)) { 1321 break; 1322 } 1323 } 1324 } 1325 break; 1326 } 1327 } 1328 } 1329 } 1330 } 1331 return $valid; 1332 } 1333 1334 /** 1335 * Returns the styles array that apply for the selected HTML tag. 1336 * @param array $dom array of HTML tags and properties 1337 * @param int $key key of the current HTML tag 1338 * @param array $css array of CSS properties 1339 * @return array containing CSS properties 1340 * @since 5.1.000 (2010-05-25) 1341 * @public static 1342 */ 1343 public static function getCSSdataArray($dom, $key, $css) { 1344 $cssarray = array(); // style to be returned 1345 // get parent CSS selectors 1346 $selectors = array(); 1347 if (isset($dom[($dom[$key]['parent'])]['csssel'])) { 1348 $selectors = $dom[($dom[$key]['parent'])]['csssel']; 1349 } 1350 // get all styles that apply 1351 foreach($css as $selector => $style) { 1352 $pos = strpos($selector, ' '); 1353 // get specificity 1354 $specificity = substr($selector, 0, $pos); 1355 // remove specificity 1356 $selector = substr($selector, $pos); 1357 // check if this selector apply to current tag 1358 if (self::isValidCSSSelectorForTag($dom, $key, $selector)) { 1359 if (!in_array($selector, $selectors)) { 1360 // add style if not already added on parent selector 1361 $cssarray[] = array('k' => $selector, 's' => $specificity, 'c' => $style); 1362 $selectors[] = $selector; 1363 } 1364 } 1365 } 1366 if (isset($dom[$key]['attribute']['style'])) { 1367 // attach inline style (latest properties have high priority) 1368 $cssarray[] = array('k' => '', 's' => '1000', 'c' => $dom[$key]['attribute']['style']); 1369 } 1370 // order the css array to account for specificity 1371 $cssordered = array(); 1372 foreach ($cssarray as $key => $val) { 1373 $skey = sprintf('%04d', $key); 1374 $cssordered[$val['s'].'_'.$skey] = $val; 1375 } 1376 // sort selectors alphabetically to account for specificity 1377 ksort($cssordered, SORT_STRING); 1378 return array($selectors, $cssordered); 1379 } 1380 1381 /** 1382 * Compact CSS data array into single string. 1383 * @param array $css array of CSS properties 1384 * @return string containing merged CSS properties 1385 * @since 5.9.070 (2011-04-19) 1386 * @public static 1387 */ 1388 public static function getTagStyleFromCSSarray($css) { 1389 $tagstyle = ''; // value to be returned 1390 foreach ($css as $style) { 1391 // split single css commands 1392 $csscmds = explode(';', $style['c']); 1393 foreach ($csscmds as $cmd) { 1394 if (!empty($cmd)) { 1395 $pos = strpos($cmd, ':'); 1396 if ($pos !== false) { 1397 $cmd = substr($cmd, 0, ($pos + 1)); 1398 if (strpos($tagstyle, $cmd) !== false) { 1399 // remove duplicate commands (last commands have high priority) 1400 $tagstyle = preg_replace('/'.$cmd.'[^;]+/i', '', $tagstyle); 1401 } 1402 } 1403 } 1404 } 1405 $tagstyle .= ';'.$style['c']; 1406 } 1407 // remove multiple semicolons 1408 $tagstyle = preg_replace('/[;]+/', ';', $tagstyle); 1409 return $tagstyle; 1410 } 1411 1412 /** 1413 * Returns the Roman representation of an integer number 1414 * @param int $number number to convert 1415 * @return string roman representation of the specified number 1416 * @since 4.4.004 (2008-12-10) 1417 * @public static 1418 */ 1419 public static function intToRoman($number) { 1420 $roman = ''; 1421 if ($number >= 4000) { 1422 // do not represent numbers above 4000 in Roman numerals 1423 return strval($number); 1424 } 1425 while ($number >= 1000) { 1426 $roman .= 'M'; 1427 $number -= 1000; 1428 } 1429 while ($number >= 900) { 1430 $roman .= 'CM'; 1431 $number -= 900; 1432 } 1433 while ($number >= 500) { 1434 $roman .= 'D'; 1435 $number -= 500; 1436 } 1437 while ($number >= 400) { 1438 $roman .= 'CD'; 1439 $number -= 400; 1440 } 1441 while ($number >= 100) { 1442 $roman .= 'C'; 1443 $number -= 100; 1444 } 1445 while ($number >= 90) { 1446 $roman .= 'XC'; 1447 $number -= 90; 1448 } 1449 while ($number >= 50) { 1450 $roman .= 'L'; 1451 $number -= 50; 1452 } 1453 while ($number >= 40) { 1454 $roman .= 'XL'; 1455 $number -= 40; 1456 } 1457 while ($number >= 10) { 1458 $roman .= 'X'; 1459 $number -= 10; 1460 } 1461 while ($number >= 9) { 1462 $roman .= 'IX'; 1463 $number -= 9; 1464 } 1465 while ($number >= 5) { 1466 $roman .= 'V'; 1467 $number -= 5; 1468 } 1469 while ($number >= 4) { 1470 $roman .= 'IV'; 1471 $number -= 4; 1472 } 1473 while ($number >= 1) { 1474 $roman .= 'I'; 1475 --$number; 1476 } 1477 return $roman; 1478 } 1479 1480 /** 1481 * Find position of last occurrence of a substring in a string 1482 * @param string $haystack The string to search in. 1483 * @param string $needle substring to search. 1484 * @param int $offset May be specified to begin searching an arbitrary number of characters into the string. 1485 * @return int|false Returns the position where the needle exists. Returns FALSE if the needle was not found. 1486 * @since 4.8.038 (2010-03-13) 1487 * @public static 1488 */ 1489 public static function revstrpos($haystack, $needle, $offset = 0) { 1490 $length = strlen($haystack); 1491 $offset = ($offset > 0)?($length - $offset):abs($offset); 1492 $pos = strpos(strrev($haystack), strrev($needle), $offset); 1493 return ($pos === false)?false:($length - $pos - strlen($needle)); 1494 } 1495 1496 /** 1497 * Returns an array of hyphenation patterns. 1498 * @param string $file TEX file containing hypenation patterns. TEX patterns can be downloaded from http://www.ctan.org/tex-archive/language/hyph-utf8/tex/generic/hyph-utf8/patterns/ 1499 * @return array of hyphenation patterns 1500 * @author Nicola Asuni 1501 * @since 4.9.012 (2010-04-12) 1502 * @public static 1503 */ 1504 public static function getHyphenPatternsFromTEX($file) { 1505 // TEX patterns are available at: 1506 // http://www.ctan.org/tex-archive/language/hyph-utf8/tex/generic/hyph-utf8/patterns/ 1507 $data = file_get_contents($file); 1508 $patterns = array(); 1509 // remove comments 1510 $data = preg_replace('/\%[^\n]*/', '', $data); 1511 // extract the patterns part 1512 preg_match('/\\\\patterns\{([^\}]*)\}/i', $data, $matches); 1513 $data = trim(substr($matches[0], 10, -1)); 1514 // extract each pattern 1515 $patterns_array = preg_split('/[\s]+/', $data); 1516 // create new language array of patterns 1517 $patterns = array(); 1518 foreach($patterns_array as $val) { 1519 if (!TCPDF_STATIC::empty_string($val)) { 1520 $val = trim($val); 1521 $val = str_replace('\'', '\\\'', $val); 1522 $key = preg_replace('/[0-9]+/', '', $val); 1523 $patterns[$key] = $val; 1524 } 1525 } 1526 return $patterns; 1527 } 1528 1529 /** 1530 * Get the Path-Painting Operators. 1531 * @param string $style Style of rendering. Possible values are: 1532 * <ul> 1533 * <li>S or D: Stroke the path.</li> 1534 * <li>s or d: Close and stroke the path.</li> 1535 * <li>f or F: Fill the path, using the nonzero winding number rule to determine the region to fill.</li> 1536 * <li>f* or F*: Fill the path, using the even-odd rule to determine the region to fill.</li> 1537 * <li>B or FD or DF: Fill and then stroke the path, using the nonzero winding number rule to determine the region to fill.</li> 1538 * <li>B* or F*D or DF*: Fill and then stroke the path, using the even-odd rule to determine the region to fill.</li> 1539 * <li>b or fd or df: Close, fill, and then stroke the path, using the nonzero winding number rule to determine the region to fill.</li> 1540 * <li>b or f*d or df*: Close, fill, and then stroke the path, using the even-odd rule to determine the region to fill.</li> 1541 * <li>CNZ: Clipping mode using the even-odd rule to determine which regions lie inside the clipping path.</li> 1542 * <li>CEO: Clipping mode using the nonzero winding number rule to determine which regions lie inside the clipping path</li> 1543 * <li>n: End the path object without filling or stroking it.</li> 1544 * </ul> 1545 * @param string $default default style 1546 * @return string 1547 * @author Nicola Asuni 1548 * @since 5.0.000 (2010-04-30) 1549 * @public static 1550 */ 1551 public static function getPathPaintOperator($style, $default='S') { 1552 $op = ''; 1553 switch($style) { 1554 case 'S': 1555 case 'D': { 1556 $op = 'S'; 1557 break; 1558 } 1559 case 's': 1560 case 'd': { 1561 $op = 's'; 1562 break; 1563 } 1564 case 'f': 1565 case 'F': { 1566 $op = 'f'; 1567 break; 1568 } 1569 case 'f*': 1570 case 'F*': { 1571 $op = 'f*'; 1572 break; 1573 } 1574 case 'B': 1575 case 'FD': 1576 case 'DF': { 1577 $op = 'B'; 1578 break; 1579 } 1580 case 'B*': 1581 case 'F*D': 1582 case 'DF*': { 1583 $op = 'B*'; 1584 break; 1585 } 1586 case 'b': 1587 case 'fd': 1588 case 'df': { 1589 $op = 'b'; 1590 break; 1591 } 1592 case 'b*': 1593 case 'f*d': 1594 case 'df*': { 1595 $op = 'b*'; 1596 break; 1597 } 1598 case 'CNZ': { 1599 $op = 'W n'; 1600 break; 1601 } 1602 case 'CEO': { 1603 $op = 'W* n'; 1604 break; 1605 } 1606 case 'n': { 1607 $op = 'n'; 1608 break; 1609 } 1610 default: { 1611 if (!empty($default)) { 1612 $op = self::getPathPaintOperator($default, ''); 1613 } else { 1614 $op = ''; 1615 } 1616 } 1617 } 1618 return $op; 1619 } 1620 1621 /** 1622 * Get the product of two SVG tranformation matrices 1623 * @param array $ta first SVG tranformation matrix 1624 * @param array $tb second SVG tranformation matrix 1625 * @return array transformation array 1626 * @author Nicola Asuni 1627 * @since 5.0.000 (2010-05-02) 1628 * @public static 1629 */ 1630 public static function getTransformationMatrixProduct($ta, $tb) { 1631 $tm = array(); 1632 $tm[0] = ($ta[0] * $tb[0]) + ($ta[2] * $tb[1]); 1633 $tm[1] = ($ta[1] * $tb[0]) + ($ta[3] * $tb[1]); 1634 $tm[2] = ($ta[0] * $tb[2]) + ($ta[2] * $tb[3]); 1635 $tm[3] = ($ta[1] * $tb[2]) + ($ta[3] * $tb[3]); 1636 $tm[4] = ($ta[0] * $tb[4]) + ($ta[2] * $tb[5]) + $ta[4]; 1637 $tm[5] = ($ta[1] * $tb[4]) + ($ta[3] * $tb[5]) + $ta[5]; 1638 return $tm; 1639 } 1640 1641 /** 1642 * Get the tranformation matrix from SVG transform attribute 1643 * @param string $attribute transformation 1644 * @return array of transformations 1645 * @author Nicola Asuni 1646 * @since 5.0.000 (2010-05-02) 1647 * @public static 1648 */ 1649 public static function getSVGTransformMatrix($attribute) { 1650 // identity matrix 1651 $tm = array(1, 0, 0, 1, 0, 0); 1652 $transform = array(); 1653 if (preg_match_all('/(matrix|translate|scale|rotate|skewX|skewY)[\s]*\(([^\)]+)\)/si', $attribute, $transform, PREG_SET_ORDER) > 0) { 1654 foreach ($transform as $key => $data) { 1655 if (!empty($data[2])) { 1656 $a = 1; 1657 $b = 0; 1658 $c = 0; 1659 $d = 1; 1660 $e = 0; 1661 $f = 0; 1662 $regs = array(); 1663 switch ($data[1]) { 1664 case 'matrix': { 1665 if (preg_match('/([a-z0-9\-\.]+)[\,\s]+([a-z0-9\-\.]+)[\,\s]+([a-z0-9\-\.]+)[\,\s]+([a-z0-9\-\.]+)[\,\s]+([a-z0-9\-\.]+)[\,\s]+([a-z0-9\-\.]+)/si', $data[2], $regs)) { 1666 $a = $regs[1]; 1667 $b = $regs[2]; 1668 $c = $regs[3]; 1669 $d = $regs[4]; 1670 $e = $regs[5]; 1671 $f = $regs[6]; 1672 } 1673 break; 1674 } 1675 case 'translate': { 1676 if (preg_match('/([a-z0-9\-\.]+)[\,\s]+([a-z0-9\-\.]+)/si', $data[2], $regs)) { 1677 $e = $regs[1]; 1678 $f = $regs[2]; 1679 } elseif (preg_match('/([a-z0-9\-\.]+)/si', $data[2], $regs)) { 1680 $e = $regs[1]; 1681 } 1682 break; 1683 } 1684 case 'scale': { 1685 if (preg_match('/([a-z0-9\-\.]+)[\,\s]+([a-z0-9\-\.]+)/si', $data[2], $regs)) { 1686 $a = $regs[1]; 1687 $d = $regs[2]; 1688 } elseif (preg_match('/([a-z0-9\-\.]+)/si', $data[2], $regs)) { 1689 $a = $regs[1]; 1690 $d = $a; 1691 } 1692 break; 1693 } 1694 case 'rotate': { 1695 if (preg_match('/([0-9\-\.]+)[\,\s]+([a-z0-9\-\.]+)[\,\s]+([a-z0-9\-\.]+)/si', $data[2], $regs)) { 1696 $ang = deg2rad($regs[1]); 1697 $x = $regs[2]; 1698 $y = $regs[3]; 1699 $a = cos($ang); 1700 $b = sin($ang); 1701 $c = -$b; 1702 $d = $a; 1703 $e = ($x * (1 - $a)) - ($y * $c); 1704 $f = ($y * (1 - $d)) - ($x * $b); 1705 } elseif (preg_match('/([0-9\-\.]+)/si', $data[2], $regs)) { 1706 $ang = deg2rad($regs[1]); 1707 $a = cos($ang); 1708 $b = sin($ang); 1709 $c = -$b; 1710 $d = $a; 1711 $e = 0; 1712 $f = 0; 1713 } 1714 break; 1715 } 1716 case 'skewX': { 1717 if (preg_match('/([0-9\-\.]+)/si', $data[2], $regs)) { 1718 $c = tan(deg2rad($regs[1])); 1719 } 1720 break; 1721 } 1722 case 'skewY': { 1723 if (preg_match('/([0-9\-\.]+)/si', $data[2], $regs)) { 1724 $b = tan(deg2rad($regs[1])); 1725 } 1726 break; 1727 } 1728 } 1729 $tm = self::getTransformationMatrixProduct($tm, array($a, $b, $c, $d, $e, $f)); 1730 } 1731 } 1732 } 1733 return $tm; 1734 } 1735 1736 /** 1737 * Returns the angle in radiants between two vectors 1738 * @param int $x1 X coordinate of first vector point 1739 * @param int $y1 Y coordinate of first vector point 1740 * @param int $x2 X coordinate of second vector point 1741 * @param int $y2 Y coordinate of second vector point 1742 * @author Nicola Asuni 1743 * @since 5.0.000 (2010-05-04) 1744 * @public static 1745 */ 1746 public static function getVectorsAngle($x1, $y1, $x2, $y2) { 1747 $dprod = ($x1 * $x2) + ($y1 * $y2); 1748 $dist1 = sqrt(($x1 * $x1) + ($y1 * $y1)); 1749 $dist2 = sqrt(($x2 * $x2) + ($y2 * $y2)); 1750 $angle = acos($dprod / ($dist1 * $dist2)); 1751 if (is_nan($angle)) { 1752 $angle = M_PI; 1753 } 1754 if ((($x1 * $y2) - ($x2 * $y1)) < 0) { 1755 $angle *= -1; 1756 } 1757 return $angle; 1758 } 1759 1760 /** 1761 * Split string by a regular expression. 1762 * This is a wrapper for the preg_split function to avoid the bug: https://bugs.php.net/bug.php?id=45850 1763 * @param string $pattern The regular expression pattern to search for without the modifiers, as a string. 1764 * @param string $modifiers The modifiers part of the pattern, 1765 * @param string $subject The input string. 1766 * @param int $limit If specified, then only substrings up to limit are returned with the rest of the string being placed in the last substring. A limit of -1, 0 or NULL means "no limit" and, as is standard across PHP, you can use NULL to skip to the flags parameter. 1767 * @param int $flags The flags as specified on the preg_split PHP function. 1768 * @return array Returns an array containing substrings of subject split along boundaries matched by pattern.modifier 1769 * @author Nicola Asuni 1770 * @since 6.0.023 1771 * @public static 1772 */ 1773 public static function pregSplit($pattern, $modifiers, $subject, $limit=NULL, $flags=NULL) { 1774 // PHP 8.1 deprecates nulls for $limit and $flags 1775 $limit = $limit === null ? -1 : $limit; 1776 $flags = $flags === null ? 0 : $flags; 1777 // the bug only happens on PHP 5.2 when using the u modifier 1778 if ((strpos($modifiers, 'u') === FALSE) OR (count(preg_split('//u', "\n\t", -1, PREG_SPLIT_NO_EMPTY)) == 2)) { 1779 $ret = preg_split($pattern.$modifiers, $subject, $limit, $flags); 1780 if ($ret === false) { 1781 return array(); 1782 } 1783 return $ret; 1784 } 1785 // preg_split is bugged - try alternative solution 1786 $ret = array(); 1787 while (($nl = strpos($subject, "\n")) !== FALSE) { 1788 $ret = array_merge($ret, preg_split($pattern.$modifiers, substr($subject, 0, $nl), $limit, $flags)); 1789 $ret[] = "\n"; 1790 $subject = substr($subject, ($nl + 1)); 1791 } 1792 if (strlen($subject) > 0) { 1793 $ret = array_merge($ret, preg_split($pattern.$modifiers, $subject, $limit, $flags)); 1794 } 1795 return $ret; 1796 } 1797 1798 /** 1799 * Wrapper to use fopen only with local files 1800 * @param string $filename Name of the file to open 1801 * @param string $mode 1802 * @return resource|false Returns a file pointer resource on success, or FALSE on error. 1803 * @public static 1804 */ 1805 public static function fopenLocal($filename, $mode) { 1806 if (strpos($filename, '://') === false) { 1807 $filename = 'file://'.$filename; 1808 } elseif (stream_is_local($filename) !== true) { 1809 return false; 1810 } 1811 return fopen($filename, $mode); 1812 } 1813 1814 /** 1815 * Check if the URL exist. 1816 * @param string $url URL to check. 1817 * @return bool Returns TRUE if the URL exists; FALSE otherwise. 1818 * @public static 1819 * @since 6.2.25 1820 */ 1821 public static function url_exists($url) { 1822 $crs = curl_init(); 1823 // encode query params in URL to get right response form the server 1824 $url = self::encodeUrlQuery($url); 1825 curl_setopt($crs, CURLOPT_URL, $url); 1826 curl_setopt($crs, CURLOPT_NOBODY, true); 1827 curl_setopt($crs, CURLOPT_FAILONERROR, true); 1828 if ((ini_get('open_basedir') == '') && (!ini_get('safe_mode'))) { 1829 curl_setopt($crs, CURLOPT_FOLLOWLOCATION, true); 1830 } 1831 curl_setopt($crs, CURLOPT_CONNECTTIMEOUT, 5); 1832 curl_setopt($crs, CURLOPT_TIMEOUT, 30); 1833 curl_setopt($crs, CURLOPT_SSL_VERIFYPEER, false); 1834 curl_setopt($crs, CURLOPT_SSL_VERIFYHOST, false); 1835 curl_setopt($crs, CURLOPT_USERAGENT, 'tc-lib-file'); 1836 curl_setopt($crs, CURLOPT_MAXREDIRS, 5); 1837 if (defined('CURLOPT_PROTOCOLS')) { 1838 curl_setopt($crs, CURLOPT_PROTOCOLS, CURLPROTO_HTTPS | CURLPROTO_HTTP | CURLPROTO_FTP | CURLPROTO_FTPS); 1839 } 1840 curl_exec($crs); 1841 $code = curl_getinfo($crs, CURLINFO_HTTP_CODE); 1842 curl_close($crs); 1843 return ($code == 200); 1844 } 1845 1846 /** 1847 * Encode query params in URL 1848 * 1849 * @param string $url 1850 * @return string 1851 * @since 6.3.3 (2019-11-01) 1852 * @public static 1853 */ 1854 public static function encodeUrlQuery($url) { 1855 $urlData = parse_url($url); 1856 if (isset($urlData['query']) && $urlData['query']) { 1857 $urlQueryData = array(); 1858 parse_str(urldecode($urlData['query']), $urlQueryData); 1859 $port = isset($urlData['port']) ? ':'.$urlData['port'] : ''; 1860 $updatedUrl = $urlData['scheme'].'://'.$urlData['host'].$port.$urlData['path'].'?'.http_build_query($urlQueryData); 1861 } else { 1862 $updatedUrl = $url; 1863 } 1864 return $updatedUrl; 1865 } 1866 1867 /** 1868 * Wrapper for file_exists. 1869 * Checks whether a file or directory exists. 1870 * Only allows some protocols and local files. 1871 * @param string $filename Path to the file or directory. 1872 * @return bool Returns TRUE if the file or directory specified by filename exists; FALSE otherwise. 1873 * @public static 1874 */ 1875 public static function file_exists($filename) { 1876 if (preg_match('|^https?://|', $filename) == 1) { 1877 return self::url_exists($filename); 1878 } 1879 if (strpos($filename, '://')) { 1880 return false; // only support http and https wrappers for security reasons 1881 } 1882 return @file_exists($filename); 1883 } 1884 1885 /** 1886 * Reads entire file into a string. 1887 * The file can be also an URL. 1888 * @param string $file Name of the file or URL to read. 1889 * @return string|false The function returns the read data or FALSE on failure. 1890 * @author Nicola Asuni 1891 * @since 6.0.025 1892 * @public static 1893 */ 1894 public static function fileGetContents($file) { 1895 $alt = array($file); 1896 // 1897 if ((strlen($file) > 1) 1898 && ($file[0] === '/') 1899 && ($file[1] !== '/') 1900 && !empty($_SERVER['DOCUMENT_ROOT']) 1901 && ($_SERVER['DOCUMENT_ROOT'] !== '/') 1902 ) { 1903 $findroot = strpos($file, $_SERVER['DOCUMENT_ROOT']); 1904 if (($findroot === false) || ($findroot > 1)) { 1905 $alt[] = htmlspecialchars_decode(urldecode($_SERVER['DOCUMENT_ROOT'].$file)); 1906 } 1907 } 1908 // 1909 $protocol = 'http'; 1910 if (!empty($_SERVER['HTTPS']) && (strtolower($_SERVER['HTTPS']) != 'off')) { 1911 $protocol .= 's'; 1912 } 1913 // 1914 $url = $file; 1915 if (preg_match('%^//%', $url) && !empty($_SERVER['HTTP_HOST'])) { 1916 $url = $protocol.':'.str_replace(' ', '%20', $url); 1917 } 1918 $url = htmlspecialchars_decode($url); 1919 $alt[] = $url; 1920 // 1921 if (preg_match('%^(https?)://%', $url) 1922 && empty($_SERVER['HTTP_HOST']) 1923 && empty($_SERVER['DOCUMENT_ROOT']) 1924 ) { 1925 $urldata = parse_url($url); 1926 if (empty($urldata['query'])) { 1927 $host = $protocol.'://'.$_SERVER['HTTP_HOST']; 1928 if (strpos($url, $host) === 0) { 1929 // convert URL to full server path 1930 $tmp = str_replace($host, $_SERVER['DOCUMENT_ROOT'], $url); 1931 $alt[] = htmlspecialchars_decode(urldecode($tmp)); 1932 } 1933 } 1934 } 1935 // 1936 if (isset($_SERVER['SCRIPT_URI']) 1937 && !preg_match('%^(https?|ftp)://%', $file) 1938 && !preg_match('%^//%', $file) 1939 ) { 1940 $urldata = @parse_url($_SERVER['SCRIPT_URI']); 1941 $alt[] = $urldata['scheme'].'://'.$urldata['host'].(($file[0] == '/') ? '' : '/').$file; 1942 } 1943 // 1944 $alt = array_unique($alt); 1945 foreach ($alt as $path) { 1946 if (!self::file_exists($path)) { 1947 continue; 1948 } 1949 $ret = @file_get_contents($path); 1950 if ( $ret != false ) { 1951 return $ret; 1952 } 1953 // try to use CURL for URLs 1954 if (!ini_get('allow_url_fopen') 1955 && function_exists('curl_init') 1956 && preg_match('%^(https?|ftp)://%', $path) 1957 ) { 1958 // try to get remote file data using cURL 1959 $crs = curl_init(); 1960 curl_setopt($crs, CURLOPT_URL, $path); 1961 curl_setopt($crs, CURLOPT_BINARYTRANSFER, true); 1962 curl_setopt($crs, CURLOPT_FAILONERROR, true); 1963 curl_setopt($crs, CURLOPT_RETURNTRANSFER, true); 1964 if ((ini_get('open_basedir') == '') && (!ini_get('safe_mode'))) { 1965 curl_setopt($crs, CURLOPT_FOLLOWLOCATION, true); 1966 } 1967 curl_setopt($crs, CURLOPT_CONNECTTIMEOUT, 5); 1968 curl_setopt($crs, CURLOPT_TIMEOUT, 30); 1969 curl_setopt($crs, CURLOPT_SSL_VERIFYPEER, false); 1970 curl_setopt($crs, CURLOPT_SSL_VERIFYHOST, false); 1971 curl_setopt($crs, CURLOPT_USERAGENT, 'tc-lib-file'); 1972 curl_setopt($crs, CURLOPT_MAXREDIRS, 5); 1973 if (defined('CURLOPT_PROTOCOLS')) { 1974 curl_setopt($crs, CURLOPT_PROTOCOLS, CURLPROTO_HTTPS | CURLPROTO_HTTP | CURLPROTO_FTP | CURLPROTO_FTPS); 1975 } 1976 $ret = curl_exec($crs); 1977 curl_close($crs); 1978 if ($ret !== false) { 1979 return $ret; 1980 } 1981 } 1982 } 1983 return false; 1984 } 1985 1986 /** 1987 * Get ULONG from string (Big Endian 32-bit unsigned integer). 1988 * @param string $str string from where to extract value 1989 * @param int $offset point from where to read the data 1990 * @return int 32 bit value 1991 * @author Nicola Asuni 1992 * @since 5.2.000 (2010-06-02) 1993 * @public static 1994 */ 1995 public static function _getULONG($str, $offset) { 1996 $v = unpack('Ni', substr($str, $offset, 4)); 1997 return $v['i']; 1998 } 1999 2000 /** 2001 * Get USHORT from string (Big Endian 16-bit unsigned integer). 2002 * @param string $str string from where to extract value 2003 * @param int $offset point from where to read the data 2004 * @return int 16 bit value 2005 * @author Nicola Asuni 2006 * @since 5.2.000 (2010-06-02) 2007 * @public static 2008 */ 2009 public static function _getUSHORT($str, $offset) { 2010 $v = unpack('ni', substr($str, $offset, 2)); 2011 return $v['i']; 2012 } 2013 2014 /** 2015 * Get SHORT from string (Big Endian 16-bit signed integer). 2016 * @param string $str String from where to extract value. 2017 * @param int $offset Point from where to read the data. 2018 * @return int 16 bit value 2019 * @author Nicola Asuni 2020 * @since 5.2.000 (2010-06-02) 2021 * @public static 2022 */ 2023 public static function _getSHORT($str, $offset) { 2024 $v = unpack('si', substr($str, $offset, 2)); 2025 return $v['i']; 2026 } 2027 2028 /** 2029 * Get FWORD from string (Big Endian 16-bit signed integer). 2030 * @param string $str String from where to extract value. 2031 * @param int $offset Point from where to read the data. 2032 * @return int 16 bit value 2033 * @author Nicola Asuni 2034 * @since 5.9.123 (2011-09-30) 2035 * @public static 2036 */ 2037 public static function _getFWORD($str, $offset) { 2038 $v = self::_getUSHORT($str, $offset); 2039 if ($v > 0x7fff) { 2040 $v -= 0x10000; 2041 } 2042 return $v; 2043 } 2044 2045 /** 2046 * Get UFWORD from string (Big Endian 16-bit unsigned integer). 2047 * @param string $str string from where to extract value 2048 * @param int $offset point from where to read the data 2049 * @return int 16 bit value 2050 * @author Nicola Asuni 2051 * @since 5.9.123 (2011-09-30) 2052 * @public static 2053 */ 2054 public static function _getUFWORD($str, $offset) { 2055 $v = self::_getUSHORT($str, $offset); 2056 return $v; 2057 } 2058 2059 /** 2060 * Get FIXED from string (32-bit signed fixed-point number (16.16). 2061 * @param string $str string from where to extract value 2062 * @param int $offset point from where to read the data 2063 * @return int 16 bit value 2064 * @author Nicola Asuni 2065 * @since 5.9.123 (2011-09-30) 2066 * @public static 2067 */ 2068 public static function _getFIXED($str, $offset) { 2069 // mantissa 2070 $m = self::_getFWORD($str, $offset); 2071 // fraction 2072 $f = self::_getUSHORT($str, ($offset + 2)); 2073 $v = floatval(''.$m.'.'.$f.''); 2074 return $v; 2075 } 2076 2077 /** 2078 * Get BYTE from string (8-bit unsigned integer). 2079 * @param string $str String from where to extract value. 2080 * @param int $offset Point from where to read the data. 2081 * @return int 8 bit value 2082 * @author Nicola Asuni 2083 * @since 5.2.000 (2010-06-02) 2084 * @public static 2085 */ 2086 public static function _getBYTE($str, $offset) { 2087 $v = unpack('Ci', substr($str, $offset, 1)); 2088 return $v['i']; 2089 } 2090 /** 2091 * Binary-safe and URL-safe file read. 2092 * Reads up to length bytes from the file pointer referenced by handle. Reading stops as soon as one of the following conditions is met: length bytes have been read; EOF (end of file) is reached. 2093 * @param resource $handle 2094 * @param int $length 2095 * @return string|false Returns the read string or FALSE in case of error. 2096 * @author Nicola Asuni 2097 * @since 4.5.027 (2009-03-16) 2098 * @public static 2099 */ 2100 public static function rfread($handle, $length) { 2101 $data = fread($handle, $length); 2102 if ($data === false) { 2103 return false; 2104 } 2105 $rest = ($length - strlen($data)); 2106 if (($rest > 0) && !feof($handle)) { 2107 $data .= self::rfread($handle, $rest); 2108 } 2109 return $data; 2110 } 2111 2112 /** 2113 * Read a 4-byte (32 bit) integer from file. 2114 * @param resource $f file resource. 2115 * @return int 4-byte integer 2116 * @public static 2117 */ 2118 public static function _freadint($f) { 2119 $a = unpack('Ni', fread($f, 4)); 2120 return $a['i']; 2121 } 2122 2123 /** 2124 * Array of page formats 2125 * measures are calculated in this way: (inches * 72) or (millimeters * 72 / 25.4) 2126 * @public static 2127 * 2128 * @var array<string,float[]> 2129 */ 2130 public static $page_formats = array( 2131 // ISO 216 A Series + 2 SIS 014711 extensions 2132 'A0' => array( 2383.937, 3370.394), // = ( 841 x 1189 ) mm = ( 33.11 x 46.81 ) in 2133 'A1' => array( 1683.780, 2383.937), // = ( 594 x 841 ) mm = ( 23.39 x 33.11 ) in 2134 'A2' => array( 1190.551, 1683.780), // = ( 420 x 594 ) mm = ( 16.54 x 23.39 ) in 2135 'A3' => array( 841.890, 1190.551), // = ( 297 x 420 ) mm = ( 11.69 x 16.54 ) in 2136 'A4' => array( 595.276, 841.890), // = ( 210 x 297 ) mm = ( 8.27 x 11.69 ) in 2137 'A5' => array( 419.528, 595.276), // = ( 148 x 210 ) mm = ( 5.83 x 8.27 ) in 2138 'A6' => array( 297.638, 419.528), // = ( 105 x 148 ) mm = ( 4.13 x 5.83 ) in 2139 'A7' => array( 209.764, 297.638), // = ( 74 x 105 ) mm = ( 2.91 x 4.13 ) in 2140 'A8' => array( 147.402, 209.764), // = ( 52 x 74 ) mm = ( 2.05 x 2.91 ) in 2141 'A9' => array( 104.882, 147.402), // = ( 37 x 52 ) mm = ( 1.46 x 2.05 ) in 2142 'A10' => array( 73.701, 104.882), // = ( 26 x 37 ) mm = ( 1.02 x 1.46 ) in 2143 'A11' => array( 51.024, 73.701), // = ( 18 x 26 ) mm = ( 0.71 x 1.02 ) in 2144 'A12' => array( 36.850, 51.024), // = ( 13 x 18 ) mm = ( 0.51 x 0.71 ) in 2145 // ISO 216 B Series + 2 SIS 014711 extensions 2146 'B0' => array( 2834.646, 4008.189), // = ( 1000 x 1414 ) mm = ( 39.37 x 55.67 ) in 2147 'B1' => array( 2004.094, 2834.646), // = ( 707 x 1000 ) mm = ( 27.83 x 39.37 ) in 2148 'B2' => array( 1417.323, 2004.094), // = ( 500 x 707 ) mm = ( 19.69 x 27.83 ) in 2149 'B3' => array( 1000.630, 1417.323), // = ( 353 x 500 ) mm = ( 13.90 x 19.69 ) in 2150 'B4' => array( 708.661, 1000.630), // = ( 250 x 353 ) mm = ( 9.84 x 13.90 ) in 2151 'B5' => array( 498.898, 708.661), // = ( 176 x 250 ) mm = ( 6.93 x 9.84 ) in 2152 'B6' => array( 354.331, 498.898), // = ( 125 x 176 ) mm = ( 4.92 x 6.93 ) in 2153 'B7' => array( 249.449, 354.331), // = ( 88 x 125 ) mm = ( 3.46 x 4.92 ) in 2154 'B8' => array( 175.748, 249.449), // = ( 62 x 88 ) mm = ( 2.44 x 3.46 ) in 2155 'B9' => array( 124.724, 175.748), // = ( 44 x 62 ) mm = ( 1.73 x 2.44 ) in 2156 'B10' => array( 87.874, 124.724), // = ( 31 x 44 ) mm = ( 1.22 x 1.73 ) in 2157 'B11' => array( 62.362, 87.874), // = ( 22 x 31 ) mm = ( 0.87 x 1.22 ) in 2158 'B12' => array( 42.520, 62.362), // = ( 15 x 22 ) mm = ( 0.59 x 0.87 ) in 2159 // ISO 216 C Series + 2 SIS 014711 extensions + 5 EXTENSION 2160 'C0' => array( 2599.370, 3676.535), // = ( 917 x 1297 ) mm = ( 36.10 x 51.06 ) in 2161 'C1' => array( 1836.850, 2599.370), // = ( 648 x 917 ) mm = ( 25.51 x 36.10 ) in 2162 'C2' => array( 1298.268, 1836.850), // = ( 458 x 648 ) mm = ( 18.03 x 25.51 ) in 2163 'C3' => array( 918.425, 1298.268), // = ( 324 x 458 ) mm = ( 12.76 x 18.03 ) in 2164 'C4' => array( 649.134, 918.425), // = ( 229 x 324 ) mm = ( 9.02 x 12.76 ) in 2165 'C5' => array( 459.213, 649.134), // = ( 162 x 229 ) mm = ( 6.38 x 9.02 ) in 2166 'C6' => array( 323.150, 459.213), // = ( 114 x 162 ) mm = ( 4.49 x 6.38 ) in 2167 'C7' => array( 229.606, 323.150), // = ( 81 x 114 ) mm = ( 3.19 x 4.49 ) in 2168 'C8' => array( 161.575, 229.606), // = ( 57 x 81 ) mm = ( 2.24 x 3.19 ) in 2169 'C9' => array( 113.386, 161.575), // = ( 40 x 57 ) mm = ( 1.57 x 2.24 ) in 2170 'C10' => array( 79.370, 113.386), // = ( 28 x 40 ) mm = ( 1.10 x 1.57 ) in 2171 'C11' => array( 56.693, 79.370), // = ( 20 x 28 ) mm = ( 0.79 x 1.10 ) in 2172 'C12' => array( 39.685, 56.693), // = ( 14 x 20 ) mm = ( 0.55 x 0.79 ) in 2173 'C76' => array( 229.606, 459.213), // = ( 81 x 162 ) mm = ( 3.19 x 6.38 ) in 2174 'DL' => array( 311.811, 623.622), // = ( 110 x 220 ) mm = ( 4.33 x 8.66 ) in 2175 'DLE' => array( 323.150, 637.795), // = ( 114 x 225 ) mm = ( 4.49 x 8.86 ) in 2176 'DLX' => array( 340.158, 666.142), // = ( 120 x 235 ) mm = ( 4.72 x 9.25 ) in 2177 'DLP' => array( 280.630, 595.276), // = ( 99 x 210 ) mm = ( 3.90 x 8.27 ) in (1/3 A4) 2178 // SIS 014711 E Series 2179 'E0' => array( 2491.654, 3517.795), // = ( 879 x 1241 ) mm = ( 34.61 x 48.86 ) in 2180 'E1' => array( 1757.480, 2491.654), // = ( 620 x 879 ) mm = ( 24.41 x 34.61 ) in 2181 'E2' => array( 1247.244, 1757.480), // = ( 440 x 620 ) mm = ( 17.32 x 24.41 ) in 2182 'E3' => array( 878.740, 1247.244), // = ( 310 x 440 ) mm = ( 12.20 x 17.32 ) in 2183 'E4' => array( 623.622, 878.740), // = ( 220 x 310 ) mm = ( 8.66 x 12.20 ) in 2184 'E5' => array( 439.370, 623.622), // = ( 155 x 220 ) mm = ( 6.10 x 8.66 ) in 2185 'E6' => array( 311.811, 439.370), // = ( 110 x 155 ) mm = ( 4.33 x 6.10 ) in 2186 'E7' => array( 221.102, 311.811), // = ( 78 x 110 ) mm = ( 3.07 x 4.33 ) in 2187 'E8' => array( 155.906, 221.102), // = ( 55 x 78 ) mm = ( 2.17 x 3.07 ) in 2188 'E9' => array( 110.551, 155.906), // = ( 39 x 55 ) mm = ( 1.54 x 2.17 ) in 2189 'E10' => array( 76.535, 110.551), // = ( 27 x 39 ) mm = ( 1.06 x 1.54 ) in 2190 'E11' => array( 53.858, 76.535), // = ( 19 x 27 ) mm = ( 0.75 x 1.06 ) in 2191 'E12' => array( 36.850, 53.858), // = ( 13 x 19 ) mm = ( 0.51 x 0.75 ) in 2192 // SIS 014711 G Series 2193 'G0' => array( 2715.591, 3838.110), // = ( 958 x 1354 ) mm = ( 37.72 x 53.31 ) in 2194 'G1' => array( 1919.055, 2715.591), // = ( 677 x 958 ) mm = ( 26.65 x 37.72 ) in 2195 'G2' => array( 1357.795, 1919.055), // = ( 479 x 677 ) mm = ( 18.86 x 26.65 ) in 2196 'G3' => array( 958.110, 1357.795), // = ( 338 x 479 ) mm = ( 13.31 x 18.86 ) in 2197 'G4' => array( 677.480, 958.110), // = ( 239 x 338 ) mm = ( 9.41 x 13.31 ) in 2198 'G5' => array( 479.055, 677.480), // = ( 169 x 239 ) mm = ( 6.65 x 9.41 ) in 2199 'G6' => array( 337.323, 479.055), // = ( 119 x 169 ) mm = ( 4.69 x 6.65 ) in 2200 'G7' => array( 238.110, 337.323), // = ( 84 x 119 ) mm = ( 3.31 x 4.69 ) in 2201 'G8' => array( 167.244, 238.110), // = ( 59 x 84 ) mm = ( 2.32 x 3.31 ) in 2202 'G9' => array( 119.055, 167.244), // = ( 42 x 59 ) mm = ( 1.65 x 2.32 ) in 2203 'G10' => array( 82.205, 119.055), // = ( 29 x 42 ) mm = ( 1.14 x 1.65 ) in 2204 'G11' => array( 59.528, 82.205), // = ( 21 x 29 ) mm = ( 0.83 x 1.14 ) in 2205 'G12' => array( 39.685, 59.528), // = ( 14 x 21 ) mm = ( 0.55 x 0.83 ) in 2206 // ISO Press 2207 'RA0' => array( 2437.795, 3458.268), // = ( 860 x 1220 ) mm = ( 33.86 x 48.03 ) in 2208 'RA1' => array( 1729.134, 2437.795), // = ( 610 x 860 ) mm = ( 24.02 x 33.86 ) in 2209 'RA2' => array( 1218.898, 1729.134), // = ( 430 x 610 ) mm = ( 16.93 x 24.02 ) in 2210 'RA3' => array( 864.567, 1218.898), // = ( 305 x 430 ) mm = ( 12.01 x 16.93 ) in 2211 'RA4' => array( 609.449, 864.567), // = ( 215 x 305 ) mm = ( 8.46 x 12.01 ) in 2212 'SRA0' => array( 2551.181, 3628.346), // = ( 900 x 1280 ) mm = ( 35.43 x 50.39 ) in 2213 'SRA1' => array( 1814.173, 2551.181), // = ( 640 x 900 ) mm = ( 25.20 x 35.43 ) in 2214 'SRA2' => array( 1275.591, 1814.173), // = ( 450 x 640 ) mm = ( 17.72 x 25.20 ) in 2215 'SRA3' => array( 907.087, 1275.591), // = ( 320 x 450 ) mm = ( 12.60 x 17.72 ) in 2216 'SRA4' => array( 637.795, 907.087), // = ( 225 x 320 ) mm = ( 8.86 x 12.60 ) in 2217 // German DIN 476 2218 '4A0' => array( 4767.874, 6740.787), // = ( 1682 x 2378 ) mm = ( 66.22 x 93.62 ) in 2219 '2A0' => array( 3370.394, 4767.874), // = ( 1189 x 1682 ) mm = ( 46.81 x 66.22 ) in 2220 // Variations on the ISO Standard 2221 'A2_EXTRA' => array( 1261.417, 1754.646), // = ( 445 x 619 ) mm = ( 17.52 x 24.37 ) in 2222 'A3+' => array( 932.598, 1369.134), // = ( 329 x 483 ) mm = ( 12.95 x 19.02 ) in 2223 'A3_EXTRA' => array( 912.756, 1261.417), // = ( 322 x 445 ) mm = ( 12.68 x 17.52 ) in 2224 'A3_SUPER' => array( 864.567, 1440.000), // = ( 305 x 508 ) mm = ( 12.01 x 20.00 ) in 2225 'SUPER_A3' => array( 864.567, 1380.472), // = ( 305 x 487 ) mm = ( 12.01 x 19.17 ) in 2226 'A4_EXTRA' => array( 666.142, 912.756), // = ( 235 x 322 ) mm = ( 9.25 x 12.68 ) in 2227 'A4_SUPER' => array( 649.134, 912.756), // = ( 229 x 322 ) mm = ( 9.02 x 12.68 ) in 2228 'SUPER_A4' => array( 643.465, 1009.134), // = ( 227 x 356 ) mm = ( 8.94 x 14.02 ) in 2229 'A4_LONG' => array( 595.276, 986.457), // = ( 210 x 348 ) mm = ( 8.27 x 13.70 ) in 2230 'F4' => array( 595.276, 935.433), // = ( 210 x 330 ) mm = ( 8.27 x 12.99 ) in 2231 'SO_B5_EXTRA' => array( 572.598, 782.362), // = ( 202 x 276 ) mm = ( 7.95 x 10.87 ) in 2232 'A5_EXTRA' => array( 490.394, 666.142), // = ( 173 x 235 ) mm = ( 6.81 x 9.25 ) in 2233 // ANSI Series 2234 'ANSI_E' => array( 2448.000, 3168.000), // = ( 864 x 1118 ) mm = ( 34.00 x 44.00 ) in 2235 'ANSI_D' => array( 1584.000, 2448.000), // = ( 559 x 864 ) mm = ( 22.00 x 34.00 ) in 2236 'ANSI_C' => array( 1224.000, 1584.000), // = ( 432 x 559 ) mm = ( 17.00 x 22.00 ) in 2237 'ANSI_B' => array( 792.000, 1224.000), // = ( 279 x 432 ) mm = ( 11.00 x 17.00 ) in 2238 'ANSI_A' => array( 612.000, 792.000), // = ( 216 x 279 ) mm = ( 8.50 x 11.00 ) in 2239 // Traditional 'Loose' North American Paper Sizes 2240 'USLEDGER' => array( 1224.000, 792.000), // = ( 432 x 279 ) mm = ( 17.00 x 11.00 ) in 2241 'LEDGER' => array( 1224.000, 792.000), // = ( 432 x 279 ) mm = ( 17.00 x 11.00 ) in 2242 'ORGANIZERK' => array( 792.000, 1224.000), // = ( 279 x 432 ) mm = ( 11.00 x 17.00 ) in 2243 'BIBLE' => array( 792.000, 1224.000), // = ( 279 x 432 ) mm = ( 11.00 x 17.00 ) in 2244 'USTABLOID' => array( 792.000, 1224.000), // = ( 279 x 432 ) mm = ( 11.00 x 17.00 ) in 2245 'TABLOID' => array( 792.000, 1224.000), // = ( 279 x 432 ) mm = ( 11.00 x 17.00 ) in 2246 'ORGANIZERM' => array( 612.000, 792.000), // = ( 216 x 279 ) mm = ( 8.50 x 11.00 ) in 2247 'USLETTER' => array( 612.000, 792.000), // = ( 216 x 279 ) mm = ( 8.50 x 11.00 ) in 2248 'LETTER' => array( 612.000, 792.000), // = ( 216 x 279 ) mm = ( 8.50 x 11.00 ) in 2249 'USLEGAL' => array( 612.000, 1008.000), // = ( 216 x 356 ) mm = ( 8.50 x 14.00 ) in 2250 'LEGAL' => array( 612.000, 1008.000), // = ( 216 x 356 ) mm = ( 8.50 x 14.00 ) in 2251 'GOVERNMENTLETTER' => array( 576.000, 756.000), // = ( 203 x 267 ) mm = ( 8.00 x 10.50 ) in 2252 'GLETTER' => array( 576.000, 756.000), // = ( 203 x 267 ) mm = ( 8.00 x 10.50 ) in 2253 'JUNIORLEGAL' => array( 576.000, 360.000), // = ( 203 x 127 ) mm = ( 8.00 x 5.00 ) in 2254 'JLEGAL' => array( 576.000, 360.000), // = ( 203 x 127 ) mm = ( 8.00 x 5.00 ) in 2255 // Other North American Paper Sizes 2256 'QUADDEMY' => array( 2520.000, 3240.000), // = ( 889 x 1143 ) mm = ( 35.00 x 45.00 ) in 2257 'SUPER_B' => array( 936.000, 1368.000), // = ( 330 x 483 ) mm = ( 13.00 x 19.00 ) in 2258 'QUARTO' => array( 648.000, 792.000), // = ( 229 x 279 ) mm = ( 9.00 x 11.00 ) in 2259 'GOVERNMENTLEGAL' => array( 612.000, 936.000), // = ( 216 x 330 ) mm = ( 8.50 x 13.00 ) in 2260 'FOLIO' => array( 612.000, 936.000), // = ( 216 x 330 ) mm = ( 8.50 x 13.00 ) in 2261 'MONARCH' => array( 522.000, 756.000), // = ( 184 x 267 ) mm = ( 7.25 x 10.50 ) in 2262 'EXECUTIVE' => array( 522.000, 756.000), // = ( 184 x 267 ) mm = ( 7.25 x 10.50 ) in 2263 'ORGANIZERL' => array( 396.000, 612.000), // = ( 140 x 216 ) mm = ( 5.50 x 8.50 ) in 2264 'STATEMENT' => array( 396.000, 612.000), // = ( 140 x 216 ) mm = ( 5.50 x 8.50 ) in 2265 'MEMO' => array( 396.000, 612.000), // = ( 140 x 216 ) mm = ( 5.50 x 8.50 ) in 2266 'FOOLSCAP' => array( 595.440, 936.000), // = ( 210 x 330 ) mm = ( 8.27 x 13.00 ) in 2267 'COMPACT' => array( 306.000, 486.000), // = ( 108 x 171 ) mm = ( 4.25 x 6.75 ) in 2268 'ORGANIZERJ' => array( 198.000, 360.000), // = ( 70 x 127 ) mm = ( 2.75 x 5.00 ) in 2269 // Canadian standard CAN 2-9.60M 2270 'P1' => array( 1587.402, 2437.795), // = ( 560 x 860 ) mm = ( 22.05 x 33.86 ) in 2271 'P2' => array( 1218.898, 1587.402), // = ( 430 x 560 ) mm = ( 16.93 x 22.05 ) in 2272 'P3' => array( 793.701, 1218.898), // = ( 280 x 430 ) mm = ( 11.02 x 16.93 ) in 2273 'P4' => array( 609.449, 793.701), // = ( 215 x 280 ) mm = ( 8.46 x 11.02 ) in 2274 'P5' => array( 396.850, 609.449), // = ( 140 x 215 ) mm = ( 5.51 x 8.46 ) in 2275 'P6' => array( 303.307, 396.850), // = ( 107 x 140 ) mm = ( 4.21 x 5.51 ) in 2276 // North American Architectural Sizes 2277 'ARCH_E' => array( 2592.000, 3456.000), // = ( 914 x 1219 ) mm = ( 36.00 x 48.00 ) in 2278 'ARCH_E1' => array( 2160.000, 3024.000), // = ( 762 x 1067 ) mm = ( 30.00 x 42.00 ) in 2279 'ARCH_D' => array( 1728.000, 2592.000), // = ( 610 x 914 ) mm = ( 24.00 x 36.00 ) in 2280 'BROADSHEET' => array( 1296.000, 1728.000), // = ( 457 x 610 ) mm = ( 18.00 x 24.00 ) in 2281 'ARCH_C' => array( 1296.000, 1728.000), // = ( 457 x 610 ) mm = ( 18.00 x 24.00 ) in 2282 'ARCH_B' => array( 864.000, 1296.000), // = ( 305 x 457 ) mm = ( 12.00 x 18.00 ) in 2283 'ARCH_A' => array( 648.000, 864.000), // = ( 229 x 305 ) mm = ( 9.00 x 12.00 ) in 2284 // -- North American Envelope Sizes 2285 // - Announcement Envelopes 2286 'ANNENV_A2' => array( 314.640, 414.000), // = ( 111 x 146 ) mm = ( 4.37 x 5.75 ) in 2287 'ANNENV_A6' => array( 342.000, 468.000), // = ( 121 x 165 ) mm = ( 4.75 x 6.50 ) in 2288 'ANNENV_A7' => array( 378.000, 522.000), // = ( 133 x 184 ) mm = ( 5.25 x 7.25 ) in 2289 'ANNENV_A8' => array( 396.000, 584.640), // = ( 140 x 206 ) mm = ( 5.50 x 8.12 ) in 2290 'ANNENV_A10' => array( 450.000, 692.640), // = ( 159 x 244 ) mm = ( 6.25 x 9.62 ) in 2291 'ANNENV_SLIM' => array( 278.640, 638.640), // = ( 98 x 225 ) mm = ( 3.87 x 8.87 ) in 2292 // - Commercial Envelopes 2293 'COMMENV_N6_1/4' => array( 252.000, 432.000), // = ( 89 x 152 ) mm = ( 3.50 x 6.00 ) in 2294 'COMMENV_N6_3/4' => array( 260.640, 468.000), // = ( 92 x 165 ) mm = ( 3.62 x 6.50 ) in 2295 'COMMENV_N8' => array( 278.640, 540.000), // = ( 98 x 191 ) mm = ( 3.87 x 7.50 ) in 2296 'COMMENV_N9' => array( 278.640, 638.640), // = ( 98 x 225 ) mm = ( 3.87 x 8.87 ) in 2297 'COMMENV_N10' => array( 296.640, 684.000), // = ( 105 x 241 ) mm = ( 4.12 x 9.50 ) in 2298 'COMMENV_N11' => array( 324.000, 746.640), // = ( 114 x 263 ) mm = ( 4.50 x 10.37 ) in 2299 'COMMENV_N12' => array( 342.000, 792.000), // = ( 121 x 279 ) mm = ( 4.75 x 11.00 ) in 2300 'COMMENV_N14' => array( 360.000, 828.000), // = ( 127 x 292 ) mm = ( 5.00 x 11.50 ) in 2301 // - Catalogue Envelopes 2302 'CATENV_N1' => array( 432.000, 648.000), // = ( 152 x 229 ) mm = ( 6.00 x 9.00 ) in 2303 'CATENV_N1_3/4' => array( 468.000, 684.000), // = ( 165 x 241 ) mm = ( 6.50 x 9.50 ) in 2304 'CATENV_N2' => array( 468.000, 720.000), // = ( 165 x 254 ) mm = ( 6.50 x 10.00 ) in 2305 'CATENV_N3' => array( 504.000, 720.000), // = ( 178 x 254 ) mm = ( 7.00 x 10.00 ) in 2306 'CATENV_N6' => array( 540.000, 756.000), // = ( 191 x 267 ) mm = ( 7.50 x 10.50 ) in 2307 'CATENV_N7' => array( 576.000, 792.000), // = ( 203 x 279 ) mm = ( 8.00 x 11.00 ) in 2308 'CATENV_N8' => array( 594.000, 810.000), // = ( 210 x 286 ) mm = ( 8.25 x 11.25 ) in 2309 'CATENV_N9_1/2' => array( 612.000, 756.000), // = ( 216 x 267 ) mm = ( 8.50 x 10.50 ) in 2310 'CATENV_N9_3/4' => array( 630.000, 810.000), // = ( 222 x 286 ) mm = ( 8.75 x 11.25 ) in 2311 'CATENV_N10_1/2' => array( 648.000, 864.000), // = ( 229 x 305 ) mm = ( 9.00 x 12.00 ) in 2312 'CATENV_N12_1/2' => array( 684.000, 900.000), // = ( 241 x 318 ) mm = ( 9.50 x 12.50 ) in 2313 'CATENV_N13_1/2' => array( 720.000, 936.000), // = ( 254 x 330 ) mm = ( 10.00 x 13.00 ) in 2314 'CATENV_N14_1/4' => array( 810.000, 882.000), // = ( 286 x 311 ) mm = ( 11.25 x 12.25 ) in 2315 'CATENV_N14_1/2' => array( 828.000, 1044.000), // = ( 292 x 368 ) mm = ( 11.50 x 14.50 ) in 2316 // Japanese (JIS P 0138-61) Standard B-Series 2317 'JIS_B0' => array( 2919.685, 4127.244), // = ( 1030 x 1456 ) mm = ( 40.55 x 57.32 ) in 2318 'JIS_B1' => array( 2063.622, 2919.685), // = ( 728 x 1030 ) mm = ( 28.66 x 40.55 ) in 2319 'JIS_B2' => array( 1459.843, 2063.622), // = ( 515 x 728 ) mm = ( 20.28 x 28.66 ) in 2320 'JIS_B3' => array( 1031.811, 1459.843), // = ( 364 x 515 ) mm = ( 14.33 x 20.28 ) in 2321 'JIS_B4' => array( 728.504, 1031.811), // = ( 257 x 364 ) mm = ( 10.12 x 14.33 ) in 2322 'JIS_B5' => array( 515.906, 728.504), // = ( 182 x 257 ) mm = ( 7.17 x 10.12 ) in 2323 'JIS_B6' => array( 362.835, 515.906), // = ( 128 x 182 ) mm = ( 5.04 x 7.17 ) in 2324 'JIS_B7' => array( 257.953, 362.835), // = ( 91 x 128 ) mm = ( 3.58 x 5.04 ) in 2325 'JIS_B8' => array( 181.417, 257.953), // = ( 64 x 91 ) mm = ( 2.52 x 3.58 ) in 2326 'JIS_B9' => array( 127.559, 181.417), // = ( 45 x 64 ) mm = ( 1.77 x 2.52 ) in 2327 'JIS_B10' => array( 90.709, 127.559), // = ( 32 x 45 ) mm = ( 1.26 x 1.77 ) in 2328 'JIS_B11' => array( 62.362, 90.709), // = ( 22 x 32 ) mm = ( 0.87 x 1.26 ) in 2329 'JIS_B12' => array( 45.354, 62.362), // = ( 16 x 22 ) mm = ( 0.63 x 0.87 ) in 2330 // PA Series 2331 'PA0' => array( 2381.102, 3174.803), // = ( 840 x 1120 ) mm = ( 33.07 x 44.09 ) in 2332 'PA1' => array( 1587.402, 2381.102), // = ( 560 x 840 ) mm = ( 22.05 x 33.07 ) in 2333 'PA2' => array( 1190.551, 1587.402), // = ( 420 x 560 ) mm = ( 16.54 x 22.05 ) in 2334 'PA3' => array( 793.701, 1190.551), // = ( 280 x 420 ) mm = ( 11.02 x 16.54 ) in 2335 'PA4' => array( 595.276, 793.701), // = ( 210 x 280 ) mm = ( 8.27 x 11.02 ) in 2336 'PA5' => array( 396.850, 595.276), // = ( 140 x 210 ) mm = ( 5.51 x 8.27 ) in 2337 'PA6' => array( 297.638, 396.850), // = ( 105 x 140 ) mm = ( 4.13 x 5.51 ) in 2338 'PA7' => array( 198.425, 297.638), // = ( 70 x 105 ) mm = ( 2.76 x 4.13 ) in 2339 'PA8' => array( 147.402, 198.425), // = ( 52 x 70 ) mm = ( 2.05 x 2.76 ) in 2340 'PA9' => array( 99.213, 147.402), // = ( 35 x 52 ) mm = ( 1.38 x 2.05 ) in 2341 'PA10' => array( 73.701, 99.213), // = ( 26 x 35 ) mm = ( 1.02 x 1.38 ) in 2342 // Standard Photographic Print Sizes 2343 'PASSPORT_PHOTO' => array( 99.213, 127.559), // = ( 35 x 45 ) mm = ( 1.38 x 1.77 ) in 2344 'E' => array( 233.858, 340.157), // = ( 82 x 120 ) mm = ( 3.25 x 4.72 ) in 2345 'L' => array( 252.283, 360.000), // = ( 89 x 127 ) mm = ( 3.50 x 5.00 ) in 2346 '3R' => array( 252.283, 360.000), // = ( 89 x 127 ) mm = ( 3.50 x 5.00 ) in 2347 'KG' => array( 289.134, 430.866), // = ( 102 x 152 ) mm = ( 4.02 x 5.98 ) in 2348 '4R' => array( 289.134, 430.866), // = ( 102 x 152 ) mm = ( 4.02 x 5.98 ) in 2349 '4D' => array( 340.157, 430.866), // = ( 120 x 152 ) mm = ( 4.72 x 5.98 ) in 2350 '2L' => array( 360.000, 504.567), // = ( 127 x 178 ) mm = ( 5.00 x 7.01 ) in 2351 '5R' => array( 360.000, 504.567), // = ( 127 x 178 ) mm = ( 5.00 x 7.01 ) in 2352 '8P' => array( 430.866, 575.433), // = ( 152 x 203 ) mm = ( 5.98 x 7.99 ) in 2353 '6R' => array( 430.866, 575.433), // = ( 152 x 203 ) mm = ( 5.98 x 7.99 ) in 2354 '6P' => array( 575.433, 720.000), // = ( 203 x 254 ) mm = ( 7.99 x 10.00 ) in 2355 '8R' => array( 575.433, 720.000), // = ( 203 x 254 ) mm = ( 7.99 x 10.00 ) in 2356 '6PW' => array( 575.433, 864.567), // = ( 203 x 305 ) mm = ( 7.99 x 12.01 ) in 2357 'S8R' => array( 575.433, 864.567), // = ( 203 x 305 ) mm = ( 7.99 x 12.01 ) in 2358 '4P' => array( 720.000, 864.567), // = ( 254 x 305 ) mm = ( 10.00 x 12.01 ) in 2359 '10R' => array( 720.000, 864.567), // = ( 254 x 305 ) mm = ( 10.00 x 12.01 ) in 2360 '4PW' => array( 720.000, 1080.000), // = ( 254 x 381 ) mm = ( 10.00 x 15.00 ) in 2361 'S10R' => array( 720.000, 1080.000), // = ( 254 x 381 ) mm = ( 10.00 x 15.00 ) in 2362 '11R' => array( 790.866, 1009.134), // = ( 279 x 356 ) mm = ( 10.98 x 14.02 ) in 2363 'S11R' => array( 790.866, 1224.567), // = ( 279 x 432 ) mm = ( 10.98 x 17.01 ) in 2364 '12R' => array( 864.567, 1080.000), // = ( 305 x 381 ) mm = ( 12.01 x 15.00 ) in 2365 'S12R' => array( 864.567, 1292.598), // = ( 305 x 456 ) mm = ( 12.01 x 17.95 ) in 2366 // Common Newspaper Sizes 2367 'NEWSPAPER_BROADSHEET' => array( 2125.984, 1700.787), // = ( 750 x 600 ) mm = ( 29.53 x 23.62 ) in 2368 'NEWSPAPER_BERLINER' => array( 1332.283, 892.913), // = ( 470 x 315 ) mm = ( 18.50 x 12.40 ) in 2369 'NEWSPAPER_TABLOID' => array( 1218.898, 793.701), // = ( 430 x 280 ) mm = ( 16.93 x 11.02 ) in 2370 'NEWSPAPER_COMPACT' => array( 1218.898, 793.701), // = ( 430 x 280 ) mm = ( 16.93 x 11.02 ) in 2371 // Business Cards 2372 'CREDIT_CARD' => array( 153.014, 242.646), // = ( 54 x 86 ) mm = ( 2.13 x 3.37 ) in 2373 'BUSINESS_CARD' => array( 153.014, 242.646), // = ( 54 x 86 ) mm = ( 2.13 x 3.37 ) in 2374 'BUSINESS_CARD_ISO7810' => array( 153.014, 242.646), // = ( 54 x 86 ) mm = ( 2.13 x 3.37 ) in 2375 'BUSINESS_CARD_ISO216' => array( 147.402, 209.764), // = ( 52 x 74 ) mm = ( 2.05 x 2.91 ) in 2376 'BUSINESS_CARD_IT' => array( 155.906, 240.945), // = ( 55 x 85 ) mm = ( 2.17 x 3.35 ) in 2377 'BUSINESS_CARD_UK' => array( 155.906, 240.945), // = ( 55 x 85 ) mm = ( 2.17 x 3.35 ) in 2378 'BUSINESS_CARD_FR' => array( 155.906, 240.945), // = ( 55 x 85 ) mm = ( 2.17 x 3.35 ) in 2379 'BUSINESS_CARD_DE' => array( 155.906, 240.945), // = ( 55 x 85 ) mm = ( 2.17 x 3.35 ) in 2380 'BUSINESS_CARD_ES' => array( 155.906, 240.945), // = ( 55 x 85 ) mm = ( 2.17 x 3.35 ) in 2381 'BUSINESS_CARD_CA' => array( 144.567, 252.283), // = ( 51 x 89 ) mm = ( 2.01 x 3.50 ) in 2382 'BUSINESS_CARD_US' => array( 144.567, 252.283), // = ( 51 x 89 ) mm = ( 2.01 x 3.50 ) in 2383 'BUSINESS_CARD_JP' => array( 155.906, 257.953), // = ( 55 x 91 ) mm = ( 2.17 x 3.58 ) in 2384 'BUSINESS_CARD_HK' => array( 153.071, 255.118), // = ( 54 x 90 ) mm = ( 2.13 x 3.54 ) in 2385 'BUSINESS_CARD_AU' => array( 155.906, 255.118), // = ( 55 x 90 ) mm = ( 2.17 x 3.54 ) in 2386 'BUSINESS_CARD_DK' => array( 155.906, 255.118), // = ( 55 x 90 ) mm = ( 2.17 x 3.54 ) in 2387 'BUSINESS_CARD_SE' => array( 155.906, 255.118), // = ( 55 x 90 ) mm = ( 2.17 x 3.54 ) in 2388 'BUSINESS_CARD_RU' => array( 141.732, 255.118), // = ( 50 x 90 ) mm = ( 1.97 x 3.54 ) in 2389 'BUSINESS_CARD_CZ' => array( 141.732, 255.118), // = ( 50 x 90 ) mm = ( 1.97 x 3.54 ) in 2390 'BUSINESS_CARD_FI' => array( 141.732, 255.118), // = ( 50 x 90 ) mm = ( 1.97 x 3.54 ) in 2391 'BUSINESS_CARD_HU' => array( 141.732, 255.118), // = ( 50 x 90 ) mm = ( 1.97 x 3.54 ) in 2392 'BUSINESS_CARD_IL' => array( 141.732, 255.118), // = ( 50 x 90 ) mm = ( 1.97 x 3.54 ) in 2393 // Billboards 2394 '4SHEET' => array( 2880.000, 4320.000), // = ( 1016 x 1524 ) mm = ( 40.00 x 60.00 ) in 2395 '6SHEET' => array( 3401.575, 5102.362), // = ( 1200 x 1800 ) mm = ( 47.24 x 70.87 ) in 2396 '12SHEET' => array( 8640.000, 4320.000), // = ( 3048 x 1524 ) mm = (120.00 x 60.00 ) in 2397 '16SHEET' => array( 5760.000, 8640.000), // = ( 2032 x 3048 ) mm = ( 80.00 x 120.00) in 2398 '32SHEET' => array(11520.000, 8640.000), // = ( 4064 x 3048 ) mm = (160.00 x 120.00) in 2399 '48SHEET' => array(17280.000, 8640.000), // = ( 6096 x 3048 ) mm = (240.00 x 120.00) in 2400 '64SHEET' => array(23040.000, 8640.000), // = ( 8128 x 3048 ) mm = (320.00 x 120.00) in 2401 '96SHEET' => array(34560.000, 8640.000), // = (12192 x 3048 ) mm = (480.00 x 120.00) in 2402 // -- Old European Sizes 2403 // - Old Imperial English Sizes 2404 'EN_EMPEROR' => array( 3456.000, 5184.000), // = ( 1219 x 1829 ) mm = ( 48.00 x 72.00 ) in 2405 'EN_ANTIQUARIAN' => array( 2232.000, 3816.000), // = ( 787 x 1346 ) mm = ( 31.00 x 53.00 ) in 2406 'EN_GRAND_EAGLE' => array( 2070.000, 3024.000), // = ( 730 x 1067 ) mm = ( 28.75 x 42.00 ) in 2407 'EN_DOUBLE_ELEPHANT' => array( 1926.000, 2880.000), // = ( 679 x 1016 ) mm = ( 26.75 x 40.00 ) in 2408 'EN_ATLAS' => array( 1872.000, 2448.000), // = ( 660 x 864 ) mm = ( 26.00 x 34.00 ) in 2409 'EN_COLOMBIER' => array( 1692.000, 2484.000), // = ( 597 x 876 ) mm = ( 23.50 x 34.50 ) in 2410 'EN_ELEPHANT' => array( 1656.000, 2016.000), // = ( 584 x 711 ) mm = ( 23.00 x 28.00 ) in 2411 'EN_DOUBLE_DEMY' => array( 1620.000, 2556.000), // = ( 572 x 902 ) mm = ( 22.50 x 35.50 ) in 2412 'EN_IMPERIAL' => array( 1584.000, 2160.000), // = ( 559 x 762 ) mm = ( 22.00 x 30.00 ) in 2413 'EN_PRINCESS' => array( 1548.000, 2016.000), // = ( 546 x 711 ) mm = ( 21.50 x 28.00 ) in 2414 'EN_CARTRIDGE' => array( 1512.000, 1872.000), // = ( 533 x 660 ) mm = ( 21.00 x 26.00 ) in 2415 'EN_DOUBLE_LARGE_POST' => array( 1512.000, 2376.000), // = ( 533 x 838 ) mm = ( 21.00 x 33.00 ) in 2416 'EN_ROYAL' => array( 1440.000, 1800.000), // = ( 508 x 635 ) mm = ( 20.00 x 25.00 ) in 2417 'EN_SHEET' => array( 1404.000, 1692.000), // = ( 495 x 597 ) mm = ( 19.50 x 23.50 ) in 2418 'EN_HALF_POST' => array( 1404.000, 1692.000), // = ( 495 x 597 ) mm = ( 19.50 x 23.50 ) in 2419 'EN_SUPER_ROYAL' => array( 1368.000, 1944.000), // = ( 483 x 686 ) mm = ( 19.00 x 27.00 ) in 2420 'EN_DOUBLE_POST' => array( 1368.000, 2196.000), // = ( 483 x 775 ) mm = ( 19.00 x 30.50 ) in 2421 'EN_MEDIUM' => array( 1260.000, 1656.000), // = ( 445 x 584 ) mm = ( 17.50 x 23.00 ) in 2422 'EN_DEMY' => array( 1260.000, 1620.000), // = ( 445 x 572 ) mm = ( 17.50 x 22.50 ) in 2423 'EN_LARGE_POST' => array( 1188.000, 1512.000), // = ( 419 x 533 ) mm = ( 16.50 x 21.00 ) in 2424 'EN_COPY_DRAUGHT' => array( 1152.000, 1440.000), // = ( 406 x 508 ) mm = ( 16.00 x 20.00 ) in 2425 'EN_POST' => array( 1116.000, 1386.000), // = ( 394 x 489 ) mm = ( 15.50 x 19.25 ) in 2426 'EN_CROWN' => array( 1080.000, 1440.000), // = ( 381 x 508 ) mm = ( 15.00 x 20.00 ) in 2427 'EN_PINCHED_POST' => array( 1062.000, 1332.000), // = ( 375 x 470 ) mm = ( 14.75 x 18.50 ) in 2428 'EN_BRIEF' => array( 972.000, 1152.000), // = ( 343 x 406 ) mm = ( 13.50 x 16.00 ) in 2429 'EN_FOOLSCAP' => array( 972.000, 1224.000), // = ( 343 x 432 ) mm = ( 13.50 x 17.00 ) in 2430 'EN_SMALL_FOOLSCAP' => array( 954.000, 1188.000), // = ( 337 x 419 ) mm = ( 13.25 x 16.50 ) in 2431 'EN_POTT' => array( 900.000, 1080.000), // = ( 318 x 381 ) mm = ( 12.50 x 15.00 ) in 2432 // - Old Imperial Belgian Sizes 2433 'BE_GRAND_AIGLE' => array( 1984.252, 2948.031), // = ( 700 x 1040 ) mm = ( 27.56 x 40.94 ) in 2434 'BE_COLOMBIER' => array( 1757.480, 2409.449), // = ( 620 x 850 ) mm = ( 24.41 x 33.46 ) in 2435 'BE_DOUBLE_CARRE' => array( 1757.480, 2607.874), // = ( 620 x 920 ) mm = ( 24.41 x 36.22 ) in 2436 'BE_ELEPHANT' => array( 1746.142, 2182.677), // = ( 616 x 770 ) mm = ( 24.25 x 30.31 ) in 2437 'BE_PETIT_AIGLE' => array( 1700.787, 2381.102), // = ( 600 x 840 ) mm = ( 23.62 x 33.07 ) in 2438 'BE_GRAND_JESUS' => array( 1559.055, 2069.291), // = ( 550 x 730 ) mm = ( 21.65 x 28.74 ) in 2439 'BE_JESUS' => array( 1530.709, 2069.291), // = ( 540 x 730 ) mm = ( 21.26 x 28.74 ) in 2440 'BE_RAISIN' => array( 1417.323, 1842.520), // = ( 500 x 650 ) mm = ( 19.69 x 25.59 ) in 2441 'BE_GRAND_MEDIAN' => array( 1303.937, 1714.961), // = ( 460 x 605 ) mm = ( 18.11 x 23.82 ) in 2442 'BE_DOUBLE_POSTE' => array( 1233.071, 1601.575), // = ( 435 x 565 ) mm = ( 17.13 x 22.24 ) in 2443 'BE_COQUILLE' => array( 1218.898, 1587.402), // = ( 430 x 560 ) mm = ( 16.93 x 22.05 ) in 2444 'BE_PETIT_MEDIAN' => array( 1176.378, 1502.362), // = ( 415 x 530 ) mm = ( 16.34 x 20.87 ) in 2445 'BE_RUCHE' => array( 1020.472, 1303.937), // = ( 360 x 460 ) mm = ( 14.17 x 18.11 ) in 2446 'BE_PROPATRIA' => array( 977.953, 1218.898), // = ( 345 x 430 ) mm = ( 13.58 x 16.93 ) in 2447 'BE_LYS' => array( 898.583, 1125.354), // = ( 317 x 397 ) mm = ( 12.48 x 15.63 ) in 2448 'BE_POT' => array( 870.236, 1088.504), // = ( 307 x 384 ) mm = ( 12.09 x 15.12 ) in 2449 'BE_ROSETTE' => array( 765.354, 983.622), // = ( 270 x 347 ) mm = ( 10.63 x 13.66 ) in 2450 // - Old Imperial French Sizes 2451 'FR_UNIVERS' => array( 2834.646, 3685.039), // = ( 1000 x 1300 ) mm = ( 39.37 x 51.18 ) in 2452 'FR_DOUBLE_COLOMBIER' => array( 2551.181, 3571.654), // = ( 900 x 1260 ) mm = ( 35.43 x 49.61 ) in 2453 'FR_GRANDE_MONDE' => array( 2551.181, 3571.654), // = ( 900 x 1260 ) mm = ( 35.43 x 49.61 ) in 2454 'FR_DOUBLE_SOLEIL' => array( 2267.717, 3401.575), // = ( 800 x 1200 ) mm = ( 31.50 x 47.24 ) in 2455 'FR_DOUBLE_JESUS' => array( 2154.331, 3174.803), // = ( 760 x 1120 ) mm = ( 29.92 x 44.09 ) in 2456 'FR_GRAND_AIGLE' => array( 2125.984, 3004.724), // = ( 750 x 1060 ) mm = ( 29.53 x 41.73 ) in 2457 'FR_PETIT_AIGLE' => array( 1984.252, 2664.567), // = ( 700 x 940 ) mm = ( 27.56 x 37.01 ) in 2458 'FR_DOUBLE_RAISIN' => array( 1842.520, 2834.646), // = ( 650 x 1000 ) mm = ( 25.59 x 39.37 ) in 2459 'FR_JOURNAL' => array( 1842.520, 2664.567), // = ( 650 x 940 ) mm = ( 25.59 x 37.01 ) in 2460 'FR_COLOMBIER_AFFICHE' => array( 1785.827, 2551.181), // = ( 630 x 900 ) mm = ( 24.80 x 35.43 ) in 2461 'FR_DOUBLE_CAVALIER' => array( 1757.480, 2607.874), // = ( 620 x 920 ) mm = ( 24.41 x 36.22 ) in 2462 'FR_CLOCHE' => array( 1700.787, 2267.717), // = ( 600 x 800 ) mm = ( 23.62 x 31.50 ) in 2463 'FR_SOLEIL' => array( 1700.787, 2267.717), // = ( 600 x 800 ) mm = ( 23.62 x 31.50 ) in 2464 'FR_DOUBLE_CARRE' => array( 1587.402, 2551.181), // = ( 560 x 900 ) mm = ( 22.05 x 35.43 ) in 2465 'FR_DOUBLE_COQUILLE' => array( 1587.402, 2494.488), // = ( 560 x 880 ) mm = ( 22.05 x 34.65 ) in 2466 'FR_JESUS' => array( 1587.402, 2154.331), // = ( 560 x 760 ) mm = ( 22.05 x 29.92 ) in 2467 'FR_RAISIN' => array( 1417.323, 1842.520), // = ( 500 x 650 ) mm = ( 19.69 x 25.59 ) in 2468 'FR_CAVALIER' => array( 1303.937, 1757.480), // = ( 460 x 620 ) mm = ( 18.11 x 24.41 ) in 2469 'FR_DOUBLE_COURONNE' => array( 1303.937, 2040.945), // = ( 460 x 720 ) mm = ( 18.11 x 28.35 ) in 2470 'FR_CARRE' => array( 1275.591, 1587.402), // = ( 450 x 560 ) mm = ( 17.72 x 22.05 ) in 2471 'FR_COQUILLE' => array( 1247.244, 1587.402), // = ( 440 x 560 ) mm = ( 17.32 x 22.05 ) in 2472 'FR_DOUBLE_TELLIERE' => array( 1247.244, 1927.559), // = ( 440 x 680 ) mm = ( 17.32 x 26.77 ) in 2473 'FR_DOUBLE_CLOCHE' => array( 1133.858, 1700.787), // = ( 400 x 600 ) mm = ( 15.75 x 23.62 ) in 2474 'FR_DOUBLE_POT' => array( 1133.858, 1757.480), // = ( 400 x 620 ) mm = ( 15.75 x 24.41 ) in 2475 'FR_ECU' => array( 1133.858, 1474.016), // = ( 400 x 520 ) mm = ( 15.75 x 20.47 ) in 2476 'FR_COURONNE' => array( 1020.472, 1303.937), // = ( 360 x 460 ) mm = ( 14.17 x 18.11 ) in 2477 'FR_TELLIERE' => array( 963.780, 1247.244), // = ( 340 x 440 ) mm = ( 13.39 x 17.32 ) in 2478 'FR_POT' => array( 878.740, 1133.858), // = ( 310 x 400 ) mm = ( 12.20 x 15.75 ) in 2479 ); 2480 2481 2482 /** 2483 * Get page dimensions from format name. 2484 * @param mixed $format The format name @see self::$page_format<ul> 2485 * @return array containing page width and height in points 2486 * @since 5.0.010 (2010-05-17) 2487 * @public static 2488 */ 2489 public static function getPageSizeFromFormat($format) { 2490 if (isset(self::$page_formats[$format])) { 2491 return self::$page_formats[$format]; 2492 } 2493 return self::$page_formats['A4']; 2494 } 2495 2496 /** 2497 * Set page boundaries. 2498 * @param int $page page number 2499 * @param string $type valid values are: <ul><li>'MediaBox' : the boundaries of the physical medium on which the page shall be displayed or printed;</li><li>'CropBox' : the visible region of default user space;</li><li>'BleedBox' : the region to which the contents of the page shall be clipped when output in a production environment;</li><li>'TrimBox' : the intended dimensions of the finished page after trimming;</li><li>'ArtBox' : the page's meaningful content (including potential white space).</li></ul> 2500 * @param float $llx lower-left x coordinate in user units. 2501 * @param float $lly lower-left y coordinate in user units. 2502 * @param float $urx upper-right x coordinate in user units. 2503 * @param float $ury upper-right y coordinate in user units. 2504 * @param boolean $points If true uses user units as unit of measure, otherwise uses PDF points. 2505 * @param float $k Scale factor (number of points in user unit). 2506 * @param array $pagedim Array of page dimensions. 2507 * @return array pagedim array of page dimensions. 2508 * @since 5.0.010 (2010-05-17) 2509 * @public static 2510 */ 2511 public static function setPageBoxes($page, $type, $llx, $lly, $urx, $ury, $points, $k, $pagedim=array()) { 2512 if (!isset($pagedim[$page])) { 2513 // initialize array 2514 $pagedim[$page] = array(); 2515 } 2516 if (!in_array($type, self::$pageboxes)) { 2517 return; 2518 } 2519 if ($points) { 2520 $k = 1; 2521 } 2522 $pagedim[$page][$type]['llx'] = ($llx * $k); 2523 $pagedim[$page][$type]['lly'] = ($lly * $k); 2524 $pagedim[$page][$type]['urx'] = ($urx * $k); 2525 $pagedim[$page][$type]['ury'] = ($ury * $k); 2526 return $pagedim; 2527 } 2528 2529 /** 2530 * Swap X and Y coordinates of page boxes (change page boxes orientation). 2531 * @param int $page page number 2532 * @param array $pagedim Array of page dimensions. 2533 * @return array pagedim array of page dimensions. 2534 * @since 5.0.010 (2010-05-17) 2535 * @public static 2536 */ 2537 public static function swapPageBoxCoordinates($page, $pagedim) { 2538 foreach (self::$pageboxes as $type) { 2539 // swap X and Y coordinates 2540 if (isset($pagedim[$page][$type])) { 2541 $tmp = $pagedim[$page][$type]['llx']; 2542 $pagedim[$page][$type]['llx'] = $pagedim[$page][$type]['lly']; 2543 $pagedim[$page][$type]['lly'] = $tmp; 2544 $tmp = $pagedim[$page][$type]['urx']; 2545 $pagedim[$page][$type]['urx'] = $pagedim[$page][$type]['ury']; 2546 $pagedim[$page][$type]['ury'] = $tmp; 2547 } 2548 } 2549 return $pagedim; 2550 } 2551 2552 /** 2553 * Get the canonical page layout mode. 2554 * @param string $layout The page layout. Possible values are:<ul><li>SinglePage Display one page at a time</li><li>OneColumn Display the pages in one column</li><li>TwoColumnLeft Display the pages in two columns, with odd-numbered pages on the left</li><li>TwoColumnRight Display the pages in two columns, with odd-numbered pages on the right</li><li>TwoPageLeft (PDF 1.5) Display the pages two at a time, with odd-numbered pages on the left</li><li>TwoPageRight (PDF 1.5) Display the pages two at a time, with odd-numbered pages on the right</li></ul> 2555 * @return string Canonical page layout name. 2556 * @public static 2557 */ 2558 public static function getPageLayoutMode($layout='SinglePage') { 2559 switch ($layout) { 2560 case 'default': 2561 case 'single': 2562 case 'SinglePage': { 2563 $layout_mode = 'SinglePage'; 2564 break; 2565 } 2566 case 'continuous': 2567 case 'OneColumn': { 2568 $layout_mode = 'OneColumn'; 2569 break; 2570 } 2571 case 'two': 2572 case 'TwoColumnLeft': { 2573 $layout_mode = 'TwoColumnLeft'; 2574 break; 2575 } 2576 case 'TwoColumnRight': { 2577 $layout_mode = 'TwoColumnRight'; 2578 break; 2579 } 2580 case 'TwoPageLeft': { 2581 $layout_mode = 'TwoPageLeft'; 2582 break; 2583 } 2584 case 'TwoPageRight': { 2585 $layout_mode = 'TwoPageRight'; 2586 break; 2587 } 2588 default: { 2589 $layout_mode = 'SinglePage'; 2590 } 2591 } 2592 return $layout_mode; 2593 } 2594 2595 /** 2596 * Get the canonical page layout mode. 2597 * @param string $mode A name object specifying how the document should be displayed when opened:<ul><li>UseNone Neither document outline nor thumbnail images visible</li><li>UseOutlines Document outline visible</li><li>UseThumbs Thumbnail images visible</li><li>FullScreen Full-screen mode, with no menu bar, window controls, or any other window visible</li><li>UseOC (PDF 1.5) Optional content group panel visible</li><li>UseAttachments (PDF 1.6) Attachments panel visible</li></ul> 2598 * @return string Canonical page mode name. 2599 * @public static 2600 */ 2601 public static function getPageMode($mode='UseNone') { 2602 switch ($mode) { 2603 case 'UseNone': { 2604 $page_mode = 'UseNone'; 2605 break; 2606 } 2607 case 'UseOutlines': { 2608 $page_mode = 'UseOutlines'; 2609 break; 2610 } 2611 case 'UseThumbs': { 2612 $page_mode = 'UseThumbs'; 2613 break; 2614 } 2615 case 'FullScreen': { 2616 $page_mode = 'FullScreen'; 2617 break; 2618 } 2619 case 'UseOC': { 2620 $page_mode = 'UseOC'; 2621 break; 2622 } 2623 case '': { 2624 $page_mode = 'UseAttachments'; 2625 break; 2626 } 2627 default: { 2628 $page_mode = 'UseNone'; 2629 } 2630 } 2631 return $page_mode; 2632 } 2633 2634 2635 } // END OF TCPDF_STATIC CLASS 2636 2637 //============================================================+ 2638 // END OF FILE 2639 //============================================================+
title
Description
Body
title
Description
Body
title
Description
Body
title
Body