| /trunk/applications/jrest/lib/zip.php |
|---|
| New file |
| 0,0 → 1,190 |
| <?php |
| /* vim: set expandtab sw=4 ts=4 sts=4: */ |
| /** |
| * |
| * @version $Id: zip.lib.php 10240 2007-04-01 11:02:46Z cybot_tm $ |
| */ |
| /** |
| * Zip file creation class. |
| * Makes zip files. |
| * |
| * Based on : |
| * |
| * http://www.zend.com/codex.php?id=535&single=1 |
| * By Eric Mueller <eric@themepark.com> |
| * |
| * http://www.zend.com/codex.php?id=470&single=1 |
| * by Denis125 <webmaster@atlant.ru> |
| * |
| * a patch from Peter Listiak <mlady@users.sourceforge.net> for last modified |
| * date and time of the compressed file |
| * |
| * Official ZIP file format: http://www.pkware.com/appnote.txt |
| * |
| * @access public |
| */ |
| class zipfile |
| { |
| /** |
| * Array to store compressed data |
| * |
| * @var array $datasec |
| */ |
| var $datasec = array(); |
| /** |
| * Central directory |
| * |
| * @var array $ctrl_dir |
| */ |
| var $ctrl_dir = array(); |
| /** |
| * End of central directory record |
| * |
| * @var string $eof_ctrl_dir |
| */ |
| var $eof_ctrl_dir = "\x50\x4b\x05\x06\x00\x00\x00\x00"; |
| /** |
| * Last offset position |
| * |
| * @var integer $old_offset |
| */ |
| var $old_offset = 0; |
| /** |
| * Converts an Unix timestamp to a four byte DOS date and time format (date |
| * in high two bytes, time in low two bytes allowing magnitude comparison). |
| * |
| * @param integer the current Unix timestamp |
| * |
| * @return integer the current date in a four byte DOS format |
| * |
| * @access private |
| */ |
| function unix2DosTime($unixtime = 0) { |
| $timearray = ($unixtime == 0) ? getdate() : getdate($unixtime); |
| if ($timearray['year'] < 1980) { |
| $timearray['year'] = 1980; |
| $timearray['mon'] = 1; |
| $timearray['mday'] = 1; |
| $timearray['hours'] = 0; |
| $timearray['minutes'] = 0; |
| $timearray['seconds'] = 0; |
| } // end if |
| return (($timearray['year'] - 1980) << 25) | ($timearray['mon'] << 21) | ($timearray['mday'] << 16) | |
| ($timearray['hours'] << 11) | ($timearray['minutes'] << 5) | ($timearray['seconds'] >> 1); |
| } // end of the 'unix2DosTime()' method |
| /** |
| * Adds "file" to archive |
| * |
| * @param string file contents |
| * @param string name of the file in the archive (may contains the path) |
| * @param integer the current timestamp |
| * |
| * @access public |
| */ |
| function addFile($data, $name, $time = 0) |
| { |
| $name = str_replace('\\', '/', $name); |
| $dtime = dechex($this->unix2DosTime($time)); |
| $hexdtime = '\x' . $dtime[6] . $dtime[7] |
| . '\x' . $dtime[4] . $dtime[5] |
| . '\x' . $dtime[2] . $dtime[3] |
| . '\x' . $dtime[0] . $dtime[1]; |
| eval('$hexdtime = "' . $hexdtime . '";'); |
| $fr = "\x50\x4b\x03\x04"; |
| $fr .= "\x14\x00"; // ver needed to extract |
| $fr .= "\x00\x00"; // gen purpose bit flag |
| $fr .= "\x08\x00"; // compression method |
| $fr .= $hexdtime; // last mod time and date |
| // "local file header" segment |
| $unc_len = strlen($data); |
| $crc = crc32($data); |
| $zdata = gzcompress($data); |
| $zdata = substr(substr($zdata, 0, strlen($zdata) - 4), 2); // fix crc bug |
| $c_len = strlen($zdata); |
| $fr .= pack('V', $crc); // crc32 |
| $fr .= pack('V', $c_len); // compressed filesize |
| $fr .= pack('V', $unc_len); // uncompressed filesize |
| $fr .= pack('v', strlen($name)); // length of filename |
| $fr .= pack('v', 0); // extra field length |
| $fr .= $name; |
| // "file data" segment |
| $fr .= $zdata; |
| // "data descriptor" segment (optional but necessary if archive is not |
| // served as file) |
| // nijel(2004-10-19): this seems not to be needed at all and causes |
| // problems in some cases (bug #1037737) |
| //$fr .= pack('V', $crc); // crc32 |
| //$fr .= pack('V', $c_len); // compressed filesize |
| //$fr .= pack('V', $unc_len); // uncompressed filesize |
| // add this entry to array |
| $this -> datasec[] = $fr; |
| // now add to central directory record |
| $cdrec = "\x50\x4b\x01\x02"; |
| $cdrec .= "\x00\x00"; // version made by |
| $cdrec .= "\x14\x00"; // version needed to extract |
| $cdrec .= "\x00\x00"; // gen purpose bit flag |
| $cdrec .= "\x08\x00"; // compression method |
| $cdrec .= $hexdtime; // last mod time & date |
| $cdrec .= pack('V', $crc); // crc32 |
| $cdrec .= pack('V', $c_len); // compressed filesize |
| $cdrec .= pack('V', $unc_len); // uncompressed filesize |
| $cdrec .= pack('v', strlen($name)); // length of filename |
| $cdrec .= pack('v', 0); // extra field length |
| $cdrec .= pack('v', 0); // file comment length |
| $cdrec .= pack('v', 0); // disk number start |
| $cdrec .= pack('v', 0); // internal file attributes |
| $cdrec .= pack('V', 32); // external file attributes - 'archive' bit set |
| $cdrec .= pack('V', $this -> old_offset); // relative offset of local header |
| $this -> old_offset += strlen($fr); |
| $cdrec .= $name; |
| // optional extra field, file comment goes here |
| // save to central directory |
| $this -> ctrl_dir[] = $cdrec; |
| } // end of the 'addFile()' method |
| /** |
| * Dumps out file |
| * |
| * @return string the zipped file |
| * |
| * @access public |
| */ |
| function file() |
| { |
| $data = implode('', $this -> datasec); |
| $ctrldir = implode('', $this -> ctrl_dir); |
| return |
| $data . |
| $ctrldir . |
| $this -> eof_ctrl_dir . |
| pack('v', sizeof($this -> ctrl_dir)) . // total # of entries "on this disk" |
| pack('v', sizeof($this -> ctrl_dir)) . // total # of entries overall |
| pack('V', strlen($ctrldir)) . // size of central dir |
| pack('V', strlen($data)) . // offset to start of central dir |
| "\x00\x00"; // .zip file comment length |
| } // end of the 'file()' method |
| } // end of the 'zipfile' class |
| ?> |
| /trunk/applications/jrest/lib/DBAccessor.php |
|---|
| New file |
| 0,0 → 1,34 |
| <?php |
| require_once 'JrestService.php'; |
| class DBAccessor extends JrestService { |
| public function connectDB($config, $base = 'database') { |
| require_once 'DB.php'; |
| $dsn = $config[$base]; |
| $DB =& DB::connect($dsn); |
| if (DB::isError($DB)) { |
| die($DB->getMessage()); |
| } |
| $DB->query("SET NAMES 'utf8'"); |
| return $DB; |
| } |
| public function connecterPDO($config, $base = 'database') { |
| $cfg = $config[$base]; |
| $dsn = $cfg['phptype'].':dbname='.$cfg['database'].';host='.$cfg['hostspec']; |
| try { |
| $PDO = new PDO($dsn, $cfg['username'], $cfg['password']); |
| } catch (PDOException $e) { |
| echo 'La connexion à la base de donnée via PDO a échouée : ' . $e->getMessage(); |
| } |
| // Passe en UTF-8 la connexion à la BDD |
| $PDO->exec("SET NAMES 'utf8'"); |
| // Affiche les erreurs détectées par PDO (sinon mode silencieux => aucune erreur affiché) |
| $PDO->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); |
| return $PDO; |
| } |
| } |
| ?> |
| /trunk/applications/jrest/lib/JrestService.php |
|---|
| New file |
| 0,0 → 1,128 |
| <?php |
| /** |
| * PHP Version 5 |
| * |
| * @category PHP |
| * @package jrest |
| * @author aurelien <aurelien@tela-botanica.org> |
| * @copyright 2009 Tela-Botanica |
| * @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL |
| * @version $$id$$ |
| * @link /doc/jrest/ |
| */ |
| class JrestService { |
| protected $config; |
| protected $script_time; |
| protected $max_exec_time; |
| public function JrestService($config) { |
| $this->config = config; |
| $this->script_time = microtime(true); |
| $this->max_exec_time = ini_get('max_execution_time'); |
| } |
| public function isAdmin($id) { |
| $admins = $this->config['jrest_admin']['admin']; |
| $admin_tab = split(',',$admins); |
| if (in_array($id,$admin_tab)) { |
| return true; |
| } else { |
| return false; |
| } |
| } |
| public function controleUtilisateur($id) { |
| if ($_SESSION['user']['name'] == '') { |
| //cas de la session temporaire, on ne fait rien de particulier |
| } else { |
| if (!$this->isAdmin($_SESSION['user']['name']) && $_SESSION['user']['name'] != $id) { |
| // cas d'usurpation d'identité |
| print 'Accès interdit'; |
| exit(); |
| } |
| } |
| } |
| public function logger($index,$chaine) { |
| if(!class_exists('Log')) { |
| include_once('Log.php'); |
| Log::getInstance(); |
| } |
| Log::setCheminLog($this->config['log']['cheminlog']); |
| Log::setTimeZone($this->config['log']['timezone']); |
| Log::setTailleMax($this->config['log']['taillemax']); |
| Log::ajouterEntree($index,$chaine); |
| } |
| public function verifierOuRelancerExecution() { |
| if((microtime(true) - $this->script_time) > ($this->max_exec_time - 5)*100) { |
| set_time_limit(2); |
| $this->logger('JRestService','Durée du script augmentée :'.microtime(true).' - '.$this->script_time.'.) > ('.$this->max_exec_time.' - 5)*1000000'); |
| return true; |
| } |
| return false; |
| } |
| /** |
| * Méthode prenant en paramètre un chemin de fichier squelette et un tableau associatif de données, |
| * en extrait les variables, charge le squelette et retourne le résultat des deux combinés. |
| * |
| * @param String $fichier le chemin du fichier du squelette |
| * @param Array $donnees un tableau associatif contenant les variables a injecter dans le squelette. |
| * |
| * @return boolean false si le squelette n'existe pas, sinon la chaine résultat. |
| */ |
| public static function traiterSquelettePhp($fichier, Array $donnees = array()) { |
| $sortie = false; |
| if (file_exists($fichier)) { |
| // Extraction des variables du tableau de données |
| extract($donnees); |
| // Démarage de la bufferisation de sortie |
| ob_start(); |
| // Si les tags courts sont activés |
| if ((bool) @ini_get('short_open_tag') === true) { |
| // Simple inclusion du squelette |
| include $fichier; |
| } else { |
| // Sinon, remplacement des tags courts par la syntaxe classique avec echo |
| $html_et_code_php = self::traiterTagsCourts($fichier); |
| // Pour évaluer du php mélangé dans du html il est nécessaire de fermer la balise php ouverte par eval |
| $html_et_code_php = '?>'.$html_et_code_php; |
| // Interprétation du html et du php dans le buffer |
| echo eval($html_et_code_php); |
| } |
| // Récupèration du contenu du buffer |
| $sortie = ob_get_contents(); |
| // Suppression du buffer |
| @ob_end_clean(); |
| } else { |
| $msg = "Le fichier du squelette '$fichier' n'existe pas."; |
| trigger_error($msg, E_USER_WARNING); |
| } |
| // Retourne le contenu |
| return $sortie; |
| } |
| /** |
| * Fonction chargeant le contenu du squelette et remplaçant les tags court php (<?= ...) par un tag long avec echo. |
| * |
| * @param String $chemin_squelette le chemin du fichier du squelette |
| * |
| * @return string le contenu du fichier du squelette php avec les tags courts remplacés. |
| */ |
| private static function traiterTagsCourts($chemin_squelette) { |
| $contenu = file_get_contents($chemin_squelette); |
| // Remplacement de tags courts par un tag long avec echo |
| $contenu = str_replace('<?=', '<?php echo ', $contenu); |
| // Ajout systématique d'un point virgule avant la fermeture php |
| $contenu = preg_replace("/;*\s*\?>/", "; ?>", $contenu); |
| return $contenu; |
| } |
| } |
| ?> |
| /trunk/applications/jrest/lib/JSON.php |
|---|
| New file |
| 0,0 → 1,806 |
| <?php |
| /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
| /** |
| * Converts to and from JSON format. |
| * |
| * JSON (JavaScript Object Notation) is a lightweight data-interchange |
| * format. It is easy for humans to read and write. It is easy for machines |
| * to parse and generate. It is based on a subset of the JavaScript |
| * Programming Language, Standard ECMA-262 3rd Edition - December 1999. |
| * This feature can also be found in Python. JSON is a text format that is |
| * completely language independent but uses conventions that are familiar |
| * to programmers of the C-family of languages, including C, C++, C#, Java, |
| * JavaScript, Perl, TCL, and many others. These properties make JSON an |
| * ideal data-interchange language. |
| * |
| * This package provides a simple encoder and decoder for JSON notation. It |
| * is intended for use with client-side Javascript applications that make |
| * use of HTTPRequest to perform server communication functions - data can |
| * be encoded into JSON notation for use in a client-side javascript, or |
| * decoded from incoming Javascript requests. JSON format is native to |
| * Javascript, and can be directly eval()'ed with no further parsing |
| * overhead |
| * |
| * All strings should be in ASCII or UTF-8 format! |
| * |
| * LICENSE: Redistribution and use in source and binary forms, with or |
| * without modification, are permitted provided that the following |
| * conditions are met: Redistributions of source code must retain the |
| * above copyright notice, this list of conditions and the following |
| * disclaimer. Redistributions in binary form must reproduce the above |
| * copyright notice, this list of conditions and the following disclaimer |
| * in the documentation and/or other materials provided with the |
| * distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN |
| * NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
| * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
| * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS |
| * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR |
| * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE |
| * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
| * DAMAGE. |
| * |
| * @category |
| * @package Services_JSON |
| * @author Michal Migurski <mike-json@teczno.com> |
| * @author Matt Knapp <mdknapp[at]gmail[dot]com> |
| * @author Brett Stimmerman <brettstimmerman[at]gmail[dot]com> |
| * @copyright 2005 Michal Migurski |
| * @version CVS: $Id$ |
| * @license http://www.opensource.org/licenses/bsd-license.php |
| * @link http://pear.php.net/pepr/pepr-proposal-show.php?id=198 |
| */ |
| /** |
| * Marker constant for Services_JSON::decode(), used to flag stack state |
| */ |
| define('SERVICES_JSON_SLICE', 1); |
| /** |
| * Marker constant for Services_JSON::decode(), used to flag stack state |
| */ |
| define('SERVICES_JSON_IN_STR', 2); |
| /** |
| * Marker constant for Services_JSON::decode(), used to flag stack state |
| */ |
| define('SERVICES_JSON_IN_ARR', 3); |
| /** |
| * Marker constant for Services_JSON::decode(), used to flag stack state |
| */ |
| define('SERVICES_JSON_IN_OBJ', 4); |
| /** |
| * Marker constant for Services_JSON::decode(), used to flag stack state |
| */ |
| define('SERVICES_JSON_IN_CMT', 5); |
| /** |
| * Behavior switch for Services_JSON::decode() |
| */ |
| define('SERVICES_JSON_LOOSE_TYPE', 16); |
| /** |
| * Behavior switch for Services_JSON::decode() |
| */ |
| define('SERVICES_JSON_SUPPRESS_ERRORS', 32); |
| /** |
| * Converts to and from JSON format. |
| * |
| * Brief example of use: |
| * |
| * <code> |
| * // create a new instance of Services_JSON |
| * $json = new Services_JSON(); |
| * |
| * // convert a complexe value to JSON notation, and send it to the browser |
| * $value = array('foo', 'bar', array(1, 2, 'baz'), array(3, array(4))); |
| * $output = $json->encode($value); |
| * |
| * print($output); |
| * // prints: ["foo","bar",[1,2,"baz"],[3,[4]]] |
| * |
| * // accept incoming POST data, assumed to be in JSON notation |
| * $input = file_get_contents('php://input', 1000000); |
| * $value = $json->decode($input); |
| * </code> |
| */ |
| class Services_JSON |
| { |
| /** |
| * constructs a new JSON instance |
| * |
| * @param int $use object behavior flags; combine with boolean-OR |
| * |
| * possible values: |
| * - SERVICES_JSON_LOOSE_TYPE: loose typing. |
| * "{...}" syntax creates associative arrays |
| * instead of objects in decode(). |
| * - SERVICES_JSON_SUPPRESS_ERRORS: error suppression. |
| * Values which can't be encoded (e.g. resources) |
| * appear as NULL instead of throwing errors. |
| * By default, a deeply-nested resource will |
| * bubble up with an error, so all return values |
| * from encode() should be checked with isError() |
| */ |
| function Services_JSON($use = 0) |
| { |
| $this->use = $use; |
| } |
| /** |
| * convert a string from one UTF-16 char to one UTF-8 char |
| * |
| * Normally should be handled by mb_convert_encoding, but |
| * provides a slower PHP-only method for installations |
| * that lack the multibye string extension. |
| * |
| * @param string $utf16 UTF-16 character |
| * @return string UTF-8 character |
| * @access private |
| */ |
| function utf162utf8($utf16) |
| { |
| // oh please oh please oh please oh please oh please |
| if(function_exists('mb_convert_encoding')) { |
| return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16'); |
| } |
| $bytes = (ord($utf16{0}) << 8) | ord($utf16{1}); |
| switch(true) { |
| case ((0x7F & $bytes) == $bytes): |
| // this case should never be reached, because we are in ASCII range |
| // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 |
| return chr(0x7F & $bytes); |
| case (0x07FF & $bytes) == $bytes: |
| // return a 2-byte UTF-8 character |
| // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 |
| return chr(0xC0 | (($bytes >> 6) & 0x1F)) |
| . chr(0x80 | ($bytes & 0x3F)); |
| case (0xFFFF & $bytes) == $bytes: |
| // return a 3-byte UTF-8 character |
| // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 |
| return chr(0xE0 | (($bytes >> 12) & 0x0F)) |
| . chr(0x80 | (($bytes >> 6) & 0x3F)) |
| . chr(0x80 | ($bytes & 0x3F)); |
| } |
| // ignoring UTF-32 for now, sorry |
| return ''; |
| } |
| /** |
| * convert a string from one UTF-8 char to one UTF-16 char |
| * |
| * Normally should be handled by mb_convert_encoding, but |
| * provides a slower PHP-only method for installations |
| * that lack the multibye string extension. |
| * |
| * @param string $utf8 UTF-8 character |
| * @return string UTF-16 character |
| * @access private |
| */ |
| function utf82utf16($utf8) |
| { |
| // oh please oh please oh please oh please oh please |
| if(function_exists('mb_convert_encoding')) { |
| return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8'); |
| } |
| switch(strlen($utf8)) { |
| case 1: |
| // this case should never be reached, because we are in ASCII range |
| // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 |
| return $utf8; |
| case 2: |
| // return a UTF-16 character from a 2-byte UTF-8 char |
| // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 |
| return chr(0x07 & (ord($utf8{0}) >> 2)) |
| . chr((0xC0 & (ord($utf8{0}) << 6)) |
| | (0x3F & ord($utf8{1}))); |
| case 3: |
| // return a UTF-16 character from a 3-byte UTF-8 char |
| // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 |
| return chr((0xF0 & (ord($utf8{0}) << 4)) |
| | (0x0F & (ord($utf8{1}) >> 2))) |
| . chr((0xC0 & (ord($utf8{1}) << 6)) |
| | (0x7F & ord($utf8{2}))); |
| } |
| // ignoring UTF-32 for now, sorry |
| return ''; |
| } |
| /** |
| * encodes an arbitrary variable into JSON format |
| * |
| * @param mixed $var any number, boolean, string, array, or object to be encoded. |
| * see argument 1 to Services_JSON() above for array-parsing behavior. |
| * if var is a strng, note that encode() always expects it |
| * to be in ASCII or UTF-8 format! |
| * |
| * @return mixed JSON string representation of input var or an error if a problem occurs |
| * @access public |
| */ |
| function encode($var) |
| { |
| switch (gettype($var)) { |
| case 'boolean': |
| return $var ? 'true' : 'false'; |
| case 'NULL': |
| return 'null'; |
| case 'integer': |
| return (int) $var; |
| case 'double': |
| case 'float': |
| return (float) $var; |
| case 'string': |
| // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT |
| $ascii = ''; |
| $strlen_var = strlen($var); |
| /* |
| * Iterate over every character in the string, |
| * escaping with a slash or encoding to UTF-8 where necessary |
| */ |
| for ($c = 0; $c < $strlen_var; ++$c) { |
| $ord_var_c = ord($var{$c}); |
| switch (true) { |
| case $ord_var_c == 0x08: |
| $ascii .= '\b'; |
| break; |
| case $ord_var_c == 0x09: |
| $ascii .= '\t'; |
| break; |
| case $ord_var_c == 0x0A: |
| $ascii .= '\n'; |
| break; |
| case $ord_var_c == 0x0C: |
| $ascii .= '\f'; |
| break; |
| case $ord_var_c == 0x0D: |
| $ascii .= '\r'; |
| break; |
| case $ord_var_c == 0x22: |
| case $ord_var_c == 0x2F: |
| case $ord_var_c == 0x5C: |
| // double quote, slash, slosh |
| $ascii .= '\\'.$var{$c}; |
| break; |
| case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)): |
| // characters U-00000000 - U-0000007F (same as ASCII) |
| $ascii .= $var{$c}; |
| break; |
| case (($ord_var_c & 0xE0) == 0xC0): |
| // characters U-00000080 - U-000007FF, mask 110XXXXX |
| // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 |
| $char = pack('C*', $ord_var_c, ord($var{$c + 1})); |
| $c += 1; |
| $utf16 = $this->utf82utf16($char); |
| $ascii .= sprintf('\u%04s', bin2hex($utf16)); |
| break; |
| case (($ord_var_c & 0xF0) == 0xE0): |
| // characters U-00000800 - U-0000FFFF, mask 1110XXXX |
| // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 |
| $char = pack('C*', $ord_var_c, |
| ord($var{$c + 1}), |
| ord($var{$c + 2})); |
| $c += 2; |
| $utf16 = $this->utf82utf16($char); |
| $ascii .= sprintf('\u%04s', bin2hex($utf16)); |
| break; |
| case (($ord_var_c & 0xF8) == 0xF0): |
| // characters U-00010000 - U-001FFFFF, mask 11110XXX |
| // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 |
| $char = pack('C*', $ord_var_c, |
| ord($var{$c + 1}), |
| ord($var{$c + 2}), |
| ord($var{$c + 3})); |
| $c += 3; |
| $utf16 = $this->utf82utf16($char); |
| $ascii .= sprintf('\u%04s', bin2hex($utf16)); |
| break; |
| case (($ord_var_c & 0xFC) == 0xF8): |
| // characters U-00200000 - U-03FFFFFF, mask 111110XX |
| // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 |
| $char = pack('C*', $ord_var_c, |
| ord($var{$c + 1}), |
| ord($var{$c + 2}), |
| ord($var{$c + 3}), |
| ord($var{$c + 4})); |
| $c += 4; |
| $utf16 = $this->utf82utf16($char); |
| $ascii .= sprintf('\u%04s', bin2hex($utf16)); |
| break; |
| case (($ord_var_c & 0xFE) == 0xFC): |
| // characters U-04000000 - U-7FFFFFFF, mask 1111110X |
| // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 |
| $char = pack('C*', $ord_var_c, |
| ord($var{$c + 1}), |
| ord($var{$c + 2}), |
| ord($var{$c + 3}), |
| ord($var{$c + 4}), |
| ord($var{$c + 5})); |
| $c += 5; |
| $utf16 = $this->utf82utf16($char); |
| $ascii .= sprintf('\u%04s', bin2hex($utf16)); |
| break; |
| } |
| } |
| return '"'.$ascii.'"'; |
| case 'array': |
| /* |
| * As per JSON spec if any array key is not an integer |
| * we must treat the the whole array as an object. We |
| * also try to catch a sparsely populated associative |
| * array with numeric keys here because some JS engines |
| * will create an array with empty indexes up to |
| * max_index which can cause memory issues and because |
| * the keys, which may be relevant, will be remapped |
| * otherwise. |
| * |
| * As per the ECMA and JSON specification an object may |
| * have any string as a property. Unfortunately due to |
| * a hole in the ECMA specification if the key is a |
| * ECMA reserved word or starts with a digit the |
| * parameter is only accessible using ECMAScript's |
| * bracket notation. |
| */ |
| // treat as a JSON object |
| if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) { |
| $properties = array_map(array($this, 'name_value'), |
| array_keys($var), |
| array_values($var)); |
| foreach($properties as $property) { |
| if(Services_JSON::isError($property)) { |
| return $property; |
| } |
| } |
| return '{' . join(',', $properties) . '}'; |
| } |
| // treat it like a regular array |
| $elements = array_map(array($this, 'encode'), $var); |
| foreach($elements as $element) { |
| if(Services_JSON::isError($element)) { |
| return $element; |
| } |
| } |
| return '[' . join(',', $elements) . ']'; |
| case 'object': |
| $vars = get_object_vars($var); |
| $properties = array_map(array($this, 'name_value'), |
| array_keys($vars), |
| array_values($vars)); |
| foreach($properties as $property) { |
| if(Services_JSON::isError($property)) { |
| return $property; |
| } |
| } |
| return '{' . join(',', $properties) . '}'; |
| default: |
| return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS) |
| ? 'null' |
| : new Services_JSON_Error(gettype($var)." can not be encoded as JSON string"); |
| } |
| } |
| /** |
| * array-walking function for use in generating JSON-formatted name-value pairs |
| * |
| * @param string $name name of key to use |
| * @param mixed $value reference to an array element to be encoded |
| * |
| * @return string JSON-formatted name-value pair, like '"name":value' |
| * @access private |
| */ |
| function name_value($name, $value) |
| { |
| $encoded_value = $this->encode($value); |
| if(Services_JSON::isError($encoded_value)) { |
| return $encoded_value; |
| } |
| return $this->encode(strval($name)) . ':' . $encoded_value; |
| } |
| /** |
| * reduce a string by removing leading and trailing comments and whitespace |
| * |
| * @param $str string string value to strip of comments and whitespace |
| * |
| * @return string string value stripped of comments and whitespace |
| * @access private |
| */ |
| function reduce_string($str) |
| { |
| $str = preg_replace(array( |
| // eliminate single line comments in '// ...' form |
| '#^\s*//(.+)$#m', |
| // eliminate multi-line comments in '/* ... */' form, at start of string |
| '#^\s*/\*(.+)\*/#Us', |
| // eliminate multi-line comments in '/* ... */' form, at end of string |
| '#/\*(.+)\*/\s*$#Us' |
| ), '', $str); |
| // eliminate extraneous space |
| return trim($str); |
| } |
| /** |
| * decodes a JSON string into appropriate variable |
| * |
| * @param string $str JSON-formatted string |
| * |
| * @return mixed number, boolean, string, array, or object |
| * corresponding to given JSON input string. |
| * See argument 1 to Services_JSON() above for object-output behavior. |
| * Note that decode() always returns strings |
| * in ASCII or UTF-8 format! |
| * @access public |
| */ |
| function decode($str) |
| { |
| $str = $this->reduce_string($str); |
| switch (strtolower($str)) { |
| case 'true': |
| return true; |
| case 'false': |
| return false; |
| case 'null': |
| return null; |
| default: |
| $m = array(); |
| if (is_numeric($str)) { |
| // Lookie-loo, it's a number |
| // This would work on its own, but I'm trying to be |
| // good about returning integers where appropriate: |
| // return (float)$str; |
| // Return float or int, as appropriate |
| return ((float)$str == (integer)$str) |
| ? (integer)$str |
| : (float)$str; |
| } elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) { |
| // STRINGS RETURNED IN UTF-8 FORMAT |
| $delim = substr($str, 0, 1); |
| $chrs = substr($str, 1, -1); |
| $utf8 = ''; |
| $strlen_chrs = strlen($chrs); |
| for ($c = 0; $c < $strlen_chrs; ++$c) { |
| $substr_chrs_c_2 = substr($chrs, $c, 2); |
| $ord_chrs_c = ord($chrs{$c}); |
| switch (true) { |
| case $substr_chrs_c_2 == '\b': |
| $utf8 .= chr(0x08); |
| ++$c; |
| break; |
| case $substr_chrs_c_2 == '\t': |
| $utf8 .= chr(0x09); |
| ++$c; |
| break; |
| case $substr_chrs_c_2 == '\n': |
| $utf8 .= chr(0x0A); |
| ++$c; |
| break; |
| case $substr_chrs_c_2 == '\f': |
| $utf8 .= chr(0x0C); |
| ++$c; |
| break; |
| case $substr_chrs_c_2 == '\r': |
| $utf8 .= chr(0x0D); |
| ++$c; |
| break; |
| case $substr_chrs_c_2 == '\\"': |
| case $substr_chrs_c_2 == '\\\'': |
| case $substr_chrs_c_2 == '\\\\': |
| case $substr_chrs_c_2 == '\\/': |
| if (($delim == '"' && $substr_chrs_c_2 != '\\\'') || |
| ($delim == "'" && $substr_chrs_c_2 != '\\"')) { |
| $utf8 .= $chrs{++$c}; |
| } |
| break; |
| case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)): |
| // single, escaped unicode character |
| $utf16 = chr(hexdec(substr($chrs, ($c + 2), 2))) |
| . chr(hexdec(substr($chrs, ($c + 4), 2))); |
| $utf8 .= $this->utf162utf8($utf16); |
| $c += 5; |
| break; |
| case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F): |
| $utf8 .= $chrs{$c}; |
| break; |
| case ($ord_chrs_c & 0xE0) == 0xC0: |
| // characters U-00000080 - U-000007FF, mask 110XXXXX |
| //see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 |
| $utf8 .= substr($chrs, $c, 2); |
| ++$c; |
| break; |
| case ($ord_chrs_c & 0xF0) == 0xE0: |
| // characters U-00000800 - U-0000FFFF, mask 1110XXXX |
| // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 |
| $utf8 .= substr($chrs, $c, 3); |
| $c += 2; |
| break; |
| case ($ord_chrs_c & 0xF8) == 0xF0: |
| // characters U-00010000 - U-001FFFFF, mask 11110XXX |
| // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 |
| $utf8 .= substr($chrs, $c, 4); |
| $c += 3; |
| break; |
| case ($ord_chrs_c & 0xFC) == 0xF8: |
| // characters U-00200000 - U-03FFFFFF, mask 111110XX |
| // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 |
| $utf8 .= substr($chrs, $c, 5); |
| $c += 4; |
| break; |
| case ($ord_chrs_c & 0xFE) == 0xFC: |
| // characters U-04000000 - U-7FFFFFFF, mask 1111110X |
| // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 |
| $utf8 .= substr($chrs, $c, 6); |
| $c += 5; |
| break; |
| } |
| } |
| return $utf8; |
| } elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) { |
| // array, or object notation |
| if ($str{0} == '[') { |
| $stk = array(SERVICES_JSON_IN_ARR); |
| $arr = array(); |
| } else { |
| if ($this->use & SERVICES_JSON_LOOSE_TYPE) { |
| $stk = array(SERVICES_JSON_IN_OBJ); |
| $obj = array(); |
| } else { |
| $stk = array(SERVICES_JSON_IN_OBJ); |
| $obj = new stdClass(); |
| } |
| } |
| array_push($stk, array('what' => SERVICES_JSON_SLICE, |
| 'where' => 0, |
| 'delim' => false)); |
| $chrs = substr($str, 1, -1); |
| $chrs = $this->reduce_string($chrs); |
| if ($chrs == '') { |
| if (reset($stk) == SERVICES_JSON_IN_ARR) { |
| return $arr; |
| } else { |
| return $obj; |
| } |
| } |
| //print("\nparsing {$chrs}\n"); |
| $strlen_chrs = strlen($chrs); |
| for ($c = 0; $c <= $strlen_chrs; ++$c) { |
| $top = end($stk); |
| $substr_chrs_c_2 = substr($chrs, $c, 2); |
| if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == SERVICES_JSON_SLICE))) { |
| // found a comma that is not inside a string, array, etc., |
| // OR we've reached the end of the character list |
| $slice = substr($chrs, $top['where'], ($c - $top['where'])); |
| array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false)); |
| //print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); |
| if (reset($stk) == SERVICES_JSON_IN_ARR) { |
| // we are in an array, so just push an element onto the stack |
| array_push($arr, $this->decode($slice)); |
| } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) { |
| // we are in an object, so figure |
| // out the property name and set an |
| // element in an associative array, |
| // for now |
| $parts = array(); |
| if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) { |
| // "name":value pair |
| $key = $this->decode($parts[1]); |
| $val = $this->decode($parts[2]); |
| if ($this->use & SERVICES_JSON_LOOSE_TYPE) { |
| $obj[$key] = $val; |
| } else { |
| $obj->$key = $val; |
| } |
| } elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) { |
| // name:value pair, where name is unquoted |
| $key = $parts[1]; |
| $val = $this->decode($parts[2]); |
| if ($this->use & SERVICES_JSON_LOOSE_TYPE) { |
| $obj[$key] = $val; |
| } else { |
| $obj->$key = $val; |
| } |
| } |
| } |
| } elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) { |
| // found a quote, and we are not inside a string |
| array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c})); |
| //print("Found start of string at {$c}\n"); |
| } elseif (($chrs{$c} == $top['delim']) && |
| ($top['what'] == SERVICES_JSON_IN_STR) && |
| ((strlen(substr($chrs, 0, $c)) - strlen(rtrim(substr($chrs, 0, $c), '\\'))) % 2 != 1)) { |
| // found a quote, we're in a string, and it's not escaped |
| // we know that it's not escaped becase there is _not_ an |
| // odd number of backslashes at the end of the string so far |
| array_pop($stk); |
| //print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n"); |
| } elseif (($chrs{$c} == '[') && |
| in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { |
| // found a left-bracket, and we are in an array, object, or slice |
| array_push($stk, array('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false)); |
| //print("Found start of array at {$c}\n"); |
| } elseif (($chrs{$c} == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) { |
| // found a right-bracket, and we're in an array |
| array_pop($stk); |
| //print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); |
| } elseif (($chrs{$c} == '{') && |
| in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { |
| // found a left-brace, and we are in an array, object, or slice |
| array_push($stk, array('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false)); |
| //print("Found start of object at {$c}\n"); |
| } elseif (($chrs{$c} == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) { |
| // found a right-brace, and we're in an object |
| array_pop($stk); |
| //print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); |
| } elseif (($substr_chrs_c_2 == '/*') && |
| in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { |
| // found a comment start, and we are in an array, object, or slice |
| array_push($stk, array('what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false)); |
| $c++; |
| //print("Found start of comment at {$c}\n"); |
| } elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == SERVICES_JSON_IN_CMT)) { |
| // found a comment end, and we're in one now |
| array_pop($stk); |
| $c++; |
| for ($i = $top['where']; $i <= $c; ++$i) |
| $chrs = substr_replace($chrs, ' ', $i, 1); |
| //print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); |
| } |
| } |
| if (reset($stk) == SERVICES_JSON_IN_ARR) { |
| return $arr; |
| } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) { |
| return $obj; |
| } |
| } |
| } |
| } |
| /** |
| * @todo Ultimately, this should just call PEAR::isError() |
| */ |
| function isError($data, $code = null) |
| { |
| if (class_exists('pear')) { |
| return PEAR::isError($data, $code); |
| } elseif (is_object($data) && (get_class($data) == 'services_json_error' || |
| is_subclass_of($data, 'services_json_error'))) { |
| return true; |
| } |
| return false; |
| } |
| } |
| if (class_exists('PEAR_Error')) { |
| class Services_JSON_Error extends PEAR_Error |
| { |
| function Services_JSON_Error($message = 'unknown error', $code = null, |
| $mode = null, $options = null, $userinfo = null) |
| { |
| parent::PEAR_Error($message, $code, $mode, $options, $userinfo); |
| } |
| } |
| } else { |
| /** |
| * @todo Ultimately, this class shall be descended from PEAR_Error |
| */ |
| class Services_JSON_Error |
| { |
| function Services_JSON_Error($message = 'unknown error', $code = null, |
| $mode = null, $options = null, $userinfo = null) |
| { |
| } |
| } |
| } |
| ?> |
| /trunk/applications/jrest/lib/PDF.php |
|---|
| New file |
| 0,0 → 1,3001 |
| <?php |
| /** |
| * File_PDF:: |
| * |
| * The File_PDF:: class provides a PHP-only implementation of a PDF library. |
| * No external libs or PHP extensions are required. |
| * |
| * Based on the FPDF class by Olivier Plathey (http://www.fpdf.org). |
| * |
| * Copyright 2001-2003 Olivier Plathey <olivier@fpdf.org> |
| * Copyright 2003-2007 The Horde Project (http://www.horde.org/) |
| * |
| * See the enclosed file COPYING for license information (LGPL). If you |
| * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. |
| * |
| * $Horde: framework/File_PDF/PDF.php,v 1.48 2007/01/05 13:12:21 jan Exp $ |
| * |
| * @author Olivier Plathey <olivier@fpdf.org> |
| * @author Marko Djukic <marko@oblo.com> |
| * @author Jan Schneider <jan@horde.org> |
| * @package File_PDF |
| * @category Fileformats |
| */ |
| class File_PDF { |
| /** |
| * Current page number. |
| * |
| * @var integer |
| */ |
| var $_page = 0; |
| /** |
| * Current object number. |
| * |
| * @var integer |
| */ |
| var $_n = 2; |
| /** |
| * Array of object offsets. |
| * |
| * @var array |
| */ |
| var $_offsets = array(); |
| /** |
| * Buffer holding in-memory PDF. |
| * |
| * @var string |
| */ |
| var $_buffer = ''; |
| /** |
| * Array containing the pages. |
| * |
| * @var array |
| */ |
| var $_pages = array(); |
| /** |
| * Current document state. |
| * 0 - initial state |
| * 1 - document opened |
| * 2 - page opened |
| * 3 - document closed |
| * |
| * @var integer |
| */ |
| var $_state = 0; |
| /** |
| * Flag indicating if PDF file is to be compressed or not. |
| * |
| * @var boolean |
| */ |
| var $_compress; |
| /** |
| * The default page orientation. |
| * |
| * @var string |
| */ |
| var $_default_orientation; |
| /** |
| * The current page orientation. |
| * |
| * @var string |
| */ |
| var $_current_orientation; |
| /** |
| * Array indicating orientation changes. |
| * |
| * @var array |
| */ |
| var $_orientation_changes = array(); |
| /** |
| * Current width of page format in points. |
| * |
| * @var float |
| */ |
| var $fwPt; |
| /** |
| * Current height of page format in points. |
| * |
| * @var float |
| */ |
| var $fhPt; |
| /** |
| * Current width of page format in user units. |
| * |
| * @var float |
| */ |
| var $fw; |
| /** |
| * Current height of page format in user units. |
| * |
| * @var float |
| */ |
| var $fh; |
| /** |
| * Current width of page in points. |
| * |
| * @var float |
| */ |
| var $wPt; |
| /** |
| * Current height of page in points. |
| * |
| * @var float |
| */ |
| var $hPt; |
| /** |
| * Current width of page in user units |
| * |
| * @var float |
| */ |
| var $w; |
| /** |
| * Current height of page in user units |
| * |
| * @var float |
| */ |
| var $h; |
| /** |
| * Scale factor (number of points in user units). |
| * |
| * @var float |
| */ |
| var $_scale; |
| /** |
| * Left page margin size. |
| * |
| * @var float |
| */ |
| var $_left_margin; |
| /** |
| * Top page margin size. |
| * |
| * @var float |
| */ |
| var $_top_margin; |
| /** |
| * Right page margin size. |
| * |
| * @var float |
| */ |
| var $_right_margin; |
| /** |
| * Break page margin size, the bottom margin which triggers a page break. |
| * |
| * @var float |
| */ |
| var $_break_margin; |
| /** |
| * Cell margin size. |
| * |
| * @var float |
| */ |
| var $_cell_margin; |
| /** |
| * The current horizontal position for cell positioning. |
| * Value is set in user units and is calculated from the top left corner |
| * as origin. |
| * |
| * @var float |
| */ |
| var $x; |
| /** |
| * The current vertical position for cell positioning. |
| * Value is set in user units and is calculated from the top left corner |
| * as origin. |
| * |
| * @var float |
| */ |
| var $y; |
| /** |
| * The height of the last cell printed. |
| * |
| * @var float |
| */ |
| var $_last_height; |
| /** |
| * Line width in user units. |
| * |
| * @var float |
| */ |
| var $_line_width; |
| /** |
| * An array of standard font names. |
| * |
| * @var array |
| */ |
| var $_core_fonts = array('courier' => 'Courier', |
| 'courierB' => 'Courier-Bold', |
| 'courierI' => 'Courier-Oblique', |
| 'courierBI' => 'Courier-BoldOblique', |
| 'helvetica' => 'Helvetica', |
| 'helveticaB' => 'Helvetica-Bold', |
| 'helveticaI' => 'Helvetica-Oblique', |
| 'helveticaBI' => 'Helvetica-BoldOblique', |
| 'times' => 'Times-Roman', |
| 'timesB' => 'Times-Bold', |
| 'timesI' => 'Times-Italic', |
| 'timesBI' => 'Times-BoldItalic', |
| 'symbol' => 'Symbol', |
| 'zapfdingbats' => 'ZapfDingbats'); |
| /** |
| * An array of used fonts. |
| * |
| * @var array |
| */ |
| var $_fonts = array(); |
| /** |
| * An array of font files. |
| * |
| * @var array |
| */ |
| var $_font_files = array(); |
| /** |
| * An array of encoding differences. |
| * |
| * @var array |
| */ |
| var $_diffs = array(); |
| /** |
| * An array of used images. |
| * |
| * @var array |
| */ |
| var $_images = array(); |
| /** |
| * An array of links in pages. |
| * |
| * @var array |
| */ |
| var $_page_links; |
| /** |
| * An array of internal links. |
| * |
| * @var array |
| */ |
| var $_links = array(); |
| /** |
| * Current font family. |
| * |
| * @var string |
| */ |
| var $_font_family = ''; |
| /** |
| * Current font style. |
| * |
| * @var string |
| */ |
| var $_font_style = ''; |
| /** |
| * Underlining flag. |
| * |
| * @var boolean |
| */ |
| var $_underline = false; |
| /** |
| * An array containing current font info. |
| * |
| * @var array |
| */ |
| var $_current_font; |
| /** |
| * Current font size in points. |
| * |
| * @var float |
| */ |
| var $_font_size_pt = 12; |
| /** |
| * Current font size in user units. |
| * |
| * @var float |
| */ |
| var $_font_size; |
| /** |
| * Commands for filling color. |
| * |
| * @var string |
| */ |
| var $_fill_color = '0 g'; |
| /** |
| * Commands for text color. |
| * |
| * @var string |
| */ |
| var $_text_color = '0 g'; |
| /** |
| * Whether text color is different from fill color. |
| * |
| * @var boolean |
| */ |
| var $_color_flag = false; |
| /** |
| * Commands for drawing color. |
| * |
| * @var string |
| */ |
| var $_draw_color = '0 G'; |
| /** |
| * Word spacing. |
| * |
| * @var integer |
| */ |
| var $_word_spacing = 0; |
| /** |
| * Automatic page breaking. |
| * |
| * @var boolean |
| */ |
| var $_auto_page_break; |
| /** |
| * Threshold used to trigger page breaks. |
| * |
| * @var float |
| */ |
| var $_page_break_trigger; |
| /** |
| * Flag set when processing footer. |
| * |
| * @var boolean |
| */ |
| var $_in_footer = false; |
| /** |
| * Zoom display mode. |
| * |
| * @var string |
| */ |
| var $_zoom_mode; |
| /** |
| * Layout display mode. |
| * |
| * @var string |
| */ |
| var $_layout_mode; |
| /** |
| * An array containing the document info, consisting of: |
| * - title |
| * - subject |
| * - author |
| * - keywords |
| * - creator |
| * |
| * @var array |
| */ |
| var $_info = array(); |
| /** |
| * Alias for total number of pages. |
| * |
| * @var string |
| */ |
| var $_alias_nb_pages = '{nb}'; |
| /** |
| * Attempts to return a conrete PDF instance. It allows to set up the page |
| * format, the orientation and the units of measurement used in all the |
| * methods (except for the font sizes). |
| * |
| * Example:<pre> |
| * $pdf = &File_PDF::factory(array('orientation' => 'P', |
| * 'unit' => 'mm', |
| * 'format' => 'A4'));</pre> |
| * |
| * @param array $params A hash with parameters for the created PDF object. |
| * Possible parameters are: |
| * orientation - Default page orientation. Possible |
| * values are (case insensitive): |
| * <pre> |
| * - P or Portrait (default) |
| * - L or Landscape |
| * </pre> |
| * unit - User measure units. Possible values values |
| * are: |
| * <pre> |
| * - pt: point |
| * - mm: millimeter (default) |
| * - cm: centimeter |
| * - in: inch |
| * </pre> |
| * A point equals 1/72 of inch, that is to say about |
| * 0.35 mm (an inch being 2.54 cm). This is a very |
| * common unit in typography; font sizes are |
| * expressed in that unit. |
| * format - The format used for pages. It can be |
| * either one of the following values (case |
| * insensitive): |
| * <pre> |
| * - A3 |
| * - A4 (default) |
| * - A5 |
| * - Letter |
| * - Legal |
| * </pre> |
| * or a custom format in the form of a two-element |
| * array containing the width and the height |
| * (expressed in the unit given by the unit |
| * parameter). |
| * @param string $class The concrete class name to return an instance of. |
| * Defaults to File_PDF. |
| */ |
| function &factory($params = array(), $class = 'File_PDF') |
| { |
| /* Check for PHP locale-related bug. */ |
| if (1.1 == 1) { |
| $error = File_PDF::raiseError('Do not alter the locale before including the class file.'); |
| return $error; |
| } |
| /* Default parameters. */ |
| $defaults = array('orientation' => 'P', 'unit' => 'mm', 'format' => 'A4'); |
| /* Backward compatibility with old method signature. */ |
| /* Should be removed a few versions later. */ |
| if (!is_array($params)) { |
| $class = 'File_PDF'; |
| $params = $defaults; |
| $names = array_keys($defaults); |
| for ($i = 0; $i < func_num_args(); $i++) { |
| $params[$names[$i]] = func_get_arg($i); |
| } |
| } else { |
| $params = array_merge($defaults, $params); |
| } |
| /* Create the PDF object. */ |
| $pdf = &new $class(); |
| /* Scale factor. */ |
| if ($params['unit'] == 'pt') { |
| $pdf->_scale = 1; |
| } elseif ($params['unit'] == 'mm') { |
| $pdf->_scale = 72 / 25.4; |
| } elseif ($params['unit'] == 'cm') { |
| $pdf->_scale = 72 / 2.54; |
| } elseif ($params['unit'] == 'in') { |
| $pdf->_scale = 72; |
| } else { |
| $error = File_PDF::raiseError(sprintf('Incorrect units: %s', $params['unit'])); |
| return $error; |
| } |
| /* Page format. */ |
| if (is_string($params['format'])) { |
| $params['format'] = strtolower($params['format']); |
| if ($params['format'] == 'a3') { |
| $params['format'] = array(841.89, 1190.55); |
| } elseif ($params['format'] == 'a4') { |
| $params['format'] = array(595.28, 841.89); |
| } elseif ($params['format'] == 'a5') { |
| $params['format'] = array(420.94, 595.28); |
| } elseif ($params['format'] == 'letter') { |
| $params['format'] = array(612, 792); |
| } elseif ($params['format'] == 'legal') { |
| $params['format'] = array(612, 1008); |
| } else { |
| $error = File_PDF::raiseError(sprintf('Unknown page format: %s', $params['format'])); |
| return $error; |
| } |
| $pdf->fwPt = $params['format'][0]; |
| $pdf->fhPt = $params['format'][1]; |
| } else { |
| $pdf->fwPt = $params['format'][0] * $pdf->_scale; |
| $pdf->fhPt = $params['format'][1] * $pdf->_scale; |
| } |
| $pdf->fw = $pdf->fwPt / $pdf->_scale; |
| $pdf->fh = $pdf->fhPt / $pdf->_scale; |
| /* Page orientation. */ |
| $params['orientation'] = strtolower($params['orientation']); |
| if ($params['orientation'] == 'p' || $params['orientation'] == 'portrait') { |
| $pdf->_default_orientation = 'P'; |
| $pdf->wPt = $pdf->fwPt; |
| $pdf->hPt = $pdf->fhPt; |
| } elseif ($params['orientation'] == 'l' || $params['orientation'] == 'landscape') { |
| $pdf->_default_orientation = 'L'; |
| $pdf->wPt = $pdf->fhPt; |
| $pdf->hPt = $pdf->fwPt; |
| } else { |
| $error = File_PDF::raiseError(sprintf('Incorrect orientation: %s', $params['orientation'])); |
| return $error; |
| } |
| $pdf->_current_orientation = $pdf->_default_orientation; |
| $pdf->w = $pdf->wPt / $pdf->_scale; |
| $pdf->h = $pdf->hPt / $pdf->_scale; |
| /* Page margins (1 cm) */ |
| $margin = 28.35 / $pdf->_scale; |
| $pdf->setMargins($margin, $margin); |
| /* Interior cell margin (1 mm) */ |
| $pdf->_cell_margin = $margin / 10; |
| /* Line width (0.2 mm) */ |
| $pdf->_line_width = .567 / $pdf->_scale; |
| /* Automatic page break */ |
| $pdf->setAutoPageBreak(true, 2 * $margin); |
| /* Full width display mode */ |
| $pdf->setDisplayMode('fullwidth'); |
| /* Compression */ |
| $pdf->setCompression(true); |
| return $pdf; |
| } |
| /** |
| * Returns a PEAR_Error object. Wraps around PEAR::raiseError() to |
| * avoid having to include PEAR.php unless an error occurs. |
| * |
| * @param mixed $error The error message. |
| * |
| * @return object PEAR_Error |
| */ |
| function raiseError($error) |
| { |
| require_once 'PEAR.php'; |
| return PEAR::raiseError($error); |
| } |
| /** |
| * Defines the left, top and right margins. By default, they equal 1 cm. |
| * Call this method to change them. |
| * |
| * @param float $left Left margin. |
| * @param float $top Top margin. |
| * @param float $right Right margin. If not specified default to the value |
| * of the left one. |
| * |
| * @see File_PDF::setAutoPageBreak |
| * @see File_PDF::setLeftMargin |
| * @see File_PDF::setRightMargin |
| * @see File_PDF::setTopMargin |
| */ |
| function setMargins($left, $top, $right = null) |
| { |
| /* Set left and top margins. */ |
| $this->_left_margin = $left; |
| $this->_top_margin = $top; |
| /* If no right margin set default to same as left. */ |
| $this->_right_margin = (is_null($right) ? $left : $right); |
| } |
| /** |
| * Defines the left margin. The method can be called before creating the |
| * first page. |
| * If the current abscissa gets out of page, it is brought back to the |
| * margin. |
| * |
| * @param float $margin The margin. |
| * |
| * @see File_PDF::setAutoPageBreak |
| * @see File_PDF::setMargins |
| * @see File_PDF::setRightMargin |
| * @see File_PDF::setTopMargin |
| */ |
| function setLeftMargin($margin) |
| { |
| $this->_left_margin = $margin; |
| /* If there is a current page and the current X position is less than |
| * margin set the X position to the margin value. */ |
| if ($this->_page > 0 && $this->x < $margin) { |
| $this->x = $margin; |
| } |
| } |
| /** |
| * Defines the top margin. The method can be called before creating the |
| * first page. |
| * |
| * @param float $margin The margin. |
| */ |
| function setTopMargin($margin) |
| { |
| $this->_top_margin = $margin; |
| } |
| /** |
| * Defines the right margin. The method can be called before creating the |
| * first page. |
| * |
| * @param float $margin The margin. |
| */ |
| function setRightMargin($margin) |
| { |
| $this->_right_margin = $margin; |
| } |
| /** |
| * Returns the actual page width. |
| * |
| * @since File_PDF 0.2.0 |
| * @since Horde 3.2 |
| * |
| * @return float The page width. |
| */ |
| function getPageWidth() |
| { |
| return ($this->w - $this->_right_margin - $this->_left_margin); |
| } |
| /** |
| * Returns the actual page height. |
| * |
| * @since File_PDF 0.2.0 |
| * @since Horde 3.2 |
| * |
| * @return float The page height. |
| */ |
| function getPageHeight() |
| { |
| return ($this->h - $this->_top_margin - $this->_break_margin); |
| } |
| /** |
| * Enables or disables the automatic page breaking mode. When enabling, |
| * the second parameter is the distance from the bottom of the page that |
| * defines the triggering limit. By default, the mode is on and the margin |
| * is 2 cm. |
| * |
| * @param boolean auto Boolean indicating if mode should be on or off. |
| * @param float $margin Distance from the bottom of the page. |
| */ |
| function setAutoPageBreak($auto, $margin = 0) |
| { |
| $this->_auto_page_break = $auto; |
| $this->_break_margin = $margin; |
| $this->_page_break_trigger = $this->h - $margin; |
| } |
| /** |
| * Defines the way the document is to be displayed by the viewer. The zoom |
| * level can be set: pages can be displayed entirely on screen, occupy the |
| * full width of the window, use real size, be scaled by a specific |
| * zooming factor or use viewer default (configured in the Preferences |
| * menu of Acrobat). The page layout can be specified too: single at once, |
| * continuous display, two columns or viewer default. |
| * By default, documents use the full width mode with continuous display. |
| * |
| * @param mixed $zoom The zoom to use. It can be one of the |
| * following string values: |
| * - fullpage: entire page on screen |
| * - fullwidth: maximum width of window |
| * - real: uses real size (100% zoom) |
| * - default: uses viewer default mode |
| * or a number indicating the zooming factor. |
| * @param string layout The page layout. Possible values are: |
| * - single: one page at once |
| * - continuous: pages in continuously |
| * - two: two pages on two columns |
| * - default: uses viewer default mode |
| * Default value is continuous. |
| */ |
| function setDisplayMode($zoom, $layout = 'continuous') |
| { |
| $zoom = strtolower($zoom); |
| if ($zoom == 'fullpage' || $zoom == 'fullwidth' || $zoom == 'real' |
| || $zoom == 'default' || !is_string($zoom)) { |
| $this->_zoom_mode = $zoom; |
| } elseif ($zoom == 'zoom') { |
| $this->_zoom_mode = $layout; |
| } else { |
| return $this->raiseError(sprintf('Incorrect zoom display mode: %s', $zoom)); |
| } |
| $layout = strtolower($layout); |
| if ($layout == 'single' || $layout == 'continuous' || $layout == 'two' |
| || $layout == 'default') { |
| $this->_layout_mode = $layout; |
| } elseif ($zoom != 'zoom') { |
| return $this->raiseError(sprintf('Incorrect layout display mode: %s', $layout)); |
| } |
| } |
| /** |
| * Activates or deactivates page compression. When activated, the internal |
| * representation of each page is compressed, which leads to a compression |
| * ratio of about 2 for the resulting document. |
| * Compression is on by default. |
| * Note: the Zlib extension is required for this feature. If not present, |
| * compression will be turned off. |
| * |
| * @param boolean $compress Boolean indicating if compression must be |
| * enabled or not. |
| */ |
| function setCompression($compress) |
| { |
| /* If no gzcompress function is available then default to false. */ |
| $this->_compress = (function_exists('gzcompress') ? $compress : false); |
| } |
| /** |
| * Set the info to a document. Possible info settings are: |
| * - title |
| * - subject |
| * - author |
| * - keywords |
| * - creator |
| * |
| * @param mixed $info If passed as an array then the complete hash |
| * containing the info to be inserted into the |
| * document. Otherwise the name of setting to be set. |
| * @param string $value The value of the setting. |
| */ |
| function setInfo($info, $value = '') |
| { |
| if (is_array($info)) { |
| $this->_info = $info; |
| } else { |
| $this->_info[$info] = $value; |
| } |
| } |
| /** |
| * Defines an alias for the total number of pages. It will be substituted |
| * as the document is closed. |
| * |
| * Example: |
| * class My_File_PDF extends File_PDF { |
| * function footer() |
| * { |
| * // Go to 1.5 cm from bottom |
| * $this->setY(-15); |
| * // Select Arial italic 8 |
| * $this->setFont('Arial', 'I', 8); |
| * // Print current and total page numbers |
| * $this->cell(0, 10, 'Page ' . $this->getPageNo() . '/{nb}', 0, |
| * 0, 'C'); |
| * } |
| * } |
| * $pdf = &My_File_PDF::factory(); |
| * $pdf->aliasNbPages(); |
| * |
| * @param string $alias The alias. Default value: {nb}. |
| * |
| * @see File_PDF::getPageNo |
| * @see File_PDF::footer |
| */ |
| function aliasNbPages($alias = '{nb}') |
| { |
| $this->_alias_nb_pages = $alias; |
| } |
| /** |
| * This method begins the generation of the PDF document; it must be |
| * called before any output commands. No page is created by this method, |
| * therefore it is necessary to call File_PDF::addPage. |
| * |
| * @see File_PDF::addPage |
| * @see File_PDF::close |
| */ |
| function open() |
| { |
| $this->_beginDoc(); |
| } |
| /** |
| * Terminates the PDF document. It is not necessary to call this method |
| * explicitly because File_PDF::output does it automatically. |
| * If the document contains no page, File_PDF::addPage is called to prevent |
| * from getting an invalid document. |
| * |
| * @see File_PDF::open |
| * @see File_PDF::output |
| */ |
| function close() |
| { |
| /* Terminate document */ |
| if ($this->_page == 0) { |
| $this->addPage(); |
| } |
| /* Page footer */ |
| $this->_in_footer = true; |
| $this->footer(); |
| $this->_in_footer = false; |
| /* Close page */ |
| $this->_endPage(); |
| /* Close document */ |
| $this->_endDoc(); |
| } |
| /** |
| * Adds a new page to the document. If a page is already present, the |
| * File_PDF::footer method is called first to output the footer. Then the |
| * page is added, the current position set to the top-left corner according |
| * to the left and top margins, and File_PDF::header is called to display |
| * the header. |
| * The font which was set before calling is automatically restored. There |
| * is no need to call File_PDF::setFont again if you want to continue with |
| * the same font. The same is true for colors and line width. |
| * The origin of the coordinate system is at the top-left corner and |
| * increasing ordinates go downwards. |
| * |
| * @param string $orientation Page orientation. Possible values |
| * are (case insensitive): |
| * - P or Portrait |
| * - L or Landscape |
| * The default value is the one passed to the |
| * constructor. |
| * |
| * @see File_PDF::PDF |
| * @see File_PDF::header |
| * @see File_PDF::footer |
| * @see File_PDF::setMargins |
| */ |
| function addPage($orientation = '') |
| { |
| /* For good measure make sure this is called. */ |
| $this->_beginDoc(); |
| /* Save style settings so that they are not overridden by footer(). */ |
| $lw = $this->_line_width; |
| $dc = $this->_draw_color; |
| $fc = $this->_fill_color; |
| $tc = $this->_text_color; |
| $cf = $this->_color_flag; |
| if ($this->_page > 0) { |
| /* Page footer. */ |
| $this->_in_footer = true; |
| $this->footer(); |
| $this->_in_footer = false; |
| /* Close page. */ |
| $this->_endPage(); |
| } |
| /* Start new page. */ |
| $this->_beginPage($orientation); |
| /* Set line cap style to square. */ |
| $this->_out('2 J'); |
| /* Set line width. */ |
| $this->_line_width = $lw; |
| $this->_out(sprintf('%.2f w', $lw * $this->_scale)); |
| /* Set font for the beginning of the page. */ |
| $font_family = null; |
| if ($this->_font_family) { |
| $font_family = $this->_font_family; |
| $font_style = $this->_font_style . ($this->_underline ? 'U' : ''); |
| $font_size = $this->_font_size_pt; |
| $this->setFont($font_family, $font_style, $font_size); |
| } |
| /* Set colors. */ |
| $this->_fill_color = $fc; |
| /* Check if fill color has been set before this page. */ |
| if ($this->_fill_color != '0 g') { |
| $this->_out($this->_fill_color); |
| } |
| $this->_draw_color = $dc; |
| /* Check if draw color has been set before this page. */ |
| if ($this->_draw_color != '0 G') { |
| $this->_out($this->_draw_color); |
| } |
| $this->_text_color = $tc; |
| $this->_color_flag = $cf; |
| /* Page header. */ |
| $this->header(); |
| /* Restore line width. */ |
| if ($this->_line_width != $lw) { |
| $this->_line_width = $lw; |
| $this->_out(sprintf('%.2f w', $lw * $this->_scale)); |
| } |
| /* Make sure the font is set for this page as it was before the |
| * header. */ |
| if ($font_family) { |
| $this->setFont($font_family, $font_style, $font_size, true); |
| } |
| /* Restore colors. */ |
| if ($this->_draw_color != $dc) { |
| $this->_draw_color = $dc; |
| $this->_out($dc); |
| } |
| if ($this->_fill_color != $fc) { |
| $this->_fill_color = $fc; |
| $this->_out($fc); |
| } |
| $this->_text_color = $tc; |
| $this->_color_flag = $cf; |
| } |
| /** |
| * This method is used to render the page header. It is automatically |
| * called by File_PDF::addPage and should not be called directly by the |
| * application. The implementation in File_PDF:: is empty, so you have to |
| * subclass it and override the method if you want a specific processing. |
| * |
| * Example: |
| * |
| * class My_File_PDF extends File_PDF { |
| * function header() |
| * { |
| * // Select Arial bold 15 |
| * $this->setFont('Arial', 'B', 15); |
| * // Move to the right |
| * $this->cell(80); |
| * // Framed title |
| * $this->cell(30, 10, 'Title', 1, 0, 'C'); |
| * // Line break |
| * $this->newLine(20); |
| * } |
| * } |
| * |
| * @see File_PDF::footer |
| */ |
| function header() |
| { |
| /* To be implemented in your own inherited class. */ |
| } |
| /** |
| * This method is used to render the page footer. It is automatically |
| * called by File_PDF::addPage and File_PDF::close and should not be called |
| * directly by the application. The implementation in File_PDF:: is empty, |
| * so you have to subclass it and override the method if you want a specific |
| * processing. |
| * |
| * Example: |
| * |
| * class My_File_PDF extends File_PDF { |
| * function footer() |
| * { |
| * // Go to 1.5 cm from bottom |
| * $this->setY(-15); |
| * // Select Arial italic 8 |
| * $this->setFont('Arial', 'I', 8); |
| * // Print centered page number |
| * $this->cell(0, 10, 'Page ' . $this->getPageNo(), 0, 0, 'C'); |
| * } |
| * } |
| * |
| * @see File_PDF::header |
| */ |
| function footer() |
| { |
| /* To be implemented in your own inherited class. */ |
| } |
| /** |
| * Returns the current page number. |
| * |
| * @return integer |
| * |
| * @see File_PDF::aliasNbPages |
| */ |
| function getPageNo() |
| { |
| return $this->_page; |
| } |
| /** |
| * Sets the fill color. |
| * |
| * Depending on the colorspace called, the number of color component |
| * parameters required can be either 1, 3 or 4. The method can be called |
| * before the first page is created and the color is retained from page to |
| * page. |
| * |
| * @param string $cs Indicates the colorspace which can be either 'rgb', |
| * 'cmyk' or 'gray'. Defaults to 'rgb'. |
| * @param float $c1 First color component, floating point value between 0 |
| * and 1. Required for gray, rgb and cmyk. |
| * @param float $c2 Second color component, floating point value between |
| * 0 and 1. Required for rgb and cmyk. |
| * @param float $c3 Third color component, floating point value between |
| * 0 and 1. Required for rgb and cmyk. |
| * @param float $c4 Fourth color component, floating point value between |
| * 0 and 1. Required for cmyk. |
| * |
| * @see File_PDF::setTextColor |
| * @see File_PDF::setDrawColor |
| * @see File_PDF::rect |
| * @see File_PDF::cell |
| * @see File_PDF::multiCell |
| */ |
| function setFillColor($cs = 'rgb', $c1, $c2 = 0, $c3 = 0, $c4 = 0) |
| { |
| $cs = strtolower($cs); |
| if ($cs == 'rgb') { |
| $this->_fill_color = sprintf('%.3f %.3f %.3f rg', $c1, $c2, $c3); |
| } elseif ($cs == 'cmyk') { |
| $this->_fill_color = sprintf('%.3f %.3f %.3f %.3f k', $c1, $c2, $c3, $c4); |
| } else { |
| $this->_fill_color = sprintf('%.3f g', $c1); |
| } |
| if ($this->_page > 0) { |
| $this->_out($this->_fill_color); |
| } |
| $this->_color_flag = $this->_fill_color != $this->_text_color; |
| } |
| /** |
| * Sets the text color. |
| * |
| * Depending on the colorspace called, the number of color component |
| * parameters required can be either 1, 3 or 4. The method can be called |
| * before the first page is created and the color is retained from page to |
| * page. |
| * |
| * @param string $cs Indicates the colorspace which can be either 'rgb', |
| * 'cmyk' or 'gray'. Defaults to 'rgb'. |
| * @param float $c1 First color component, floating point value between 0 |
| * and 1. Required for gray, rgb and cmyk. |
| * @param float $c2 Second color component, floating point value between |
| * 0 and 1. Required for rgb and cmyk. |
| * @param float $c3 Third color component, floating point value between |
| * 0 and 1. Required for rgb and cmyk. |
| * @param float $c4 Fourth color component, floating point value between |
| * 0 and 1. Required for cmyk. |
| * |
| * @since File_PDF 0.2.0 |
| * @since Horde 3.2 |
| * @see File_PDF::setFillColor |
| * @see File_PDF::setDrawColor |
| * @see File_PDF::rect |
| * @see File_PDF::cell |
| * @see File_PDF::multiCell |
| */ |
| function setTextColor($cs = 'rgb', $c1, $c2 = 0, $c3 = 0, $c4 = 0) |
| { |
| $cs = strtolower($cs); |
| if ($cs == 'rgb') { |
| $this->_text_color = sprintf('%.3f %.3f %.3f rg', $c1, $c2, $c3); |
| } elseif ($cs == 'cmyk') { |
| $this->_text_color = sprintf('%.3f %.3f %.3f %.3f k', $c1, $c2, $c3, $c4); |
| } else { |
| $this->_text_color = sprintf('%.3f g', $c1); |
| } |
| if ($this->_page > 0) { |
| $this->_out($this->_text_color); |
| } |
| $this->_color_flag = $this->_fill_color != $this->_text_color; |
| } |
| /** |
| * Sets the draw color, used when drawing lines. Depending on the |
| * colorspace called, the number of color component parameters required |
| * can be either 1, 3 or 4. The method can be called before the first page |
| * is created and the color is retained from page to page. |
| * |
| * @param string $cs Indicates the colorspace which can be either 'rgb', |
| * 'cmyk' or 'gray'. Defaults to 'rgb'. |
| * @param float $c1 First color component, floating point value between 0 |
| * and 1. Required for gray, rgb and cmyk. |
| * @param float $c2 Second color component, floating point value between |
| * 0 and 1. Required for rgb and cmyk. |
| * @param float $c3 Third color component, floating point value between 0 |
| * and 1. Required for rgb and cmyk. |
| * @param float $c4 Fourth color component, floating point value between |
| * 0 and 1. Required for cmyk. |
| * |
| * @see File_PDF::setFillColor |
| * @see File_PDF::line |
| * @see File_PDF::rect |
| * @see File_PDF::cell |
| * @see File_PDF::multiCell |
| */ |
| function setDrawColor($cs = 'rgb', $c1, $c2 = 0, $c3 = 0, $c4 = 0) |
| { |
| $cs = strtolower($cs); |
| if ($cs == 'rgb') { |
| $this->_draw_color = sprintf('%.3f %.3f %.3f RG', $c1, $c2, $c3); |
| } elseif ($cs == 'cmyk') { |
| $this->_draw_color = sprintf('%.3f %.3f %.3f %.3f K', $c1, $c2, $c3, $c4); |
| } else { |
| $this->_draw_color = sprintf('%.3f G', $c1); |
| } |
| if ($this->_page > 0) { |
| $this->_out($this->_draw_color); |
| } |
| } |
| /** |
| * Returns the length of a text string. A font must be selected. |
| * |
| * @param string $text The text whose length is to be computed. |
| * @param boolean $pt Boolean to indicate if the width should be returned |
| * in points or user units. Default is 'false'. |
| * |
| * @return float |
| */ |
| function getStringWidth($text, $pt = false) |
| { |
| $text = (string)$text; |
| $width = 0; |
| $length = strlen($text); |
| for ($i = 0; $i < $length; $i++) { |
| $width += $this->_current_font['cw'][$text{$i}]; |
| } |
| /* Adjust for word spacing. */ |
| $width += $this->_word_spacing * substr_count($text, ' ') * $this->_current_font['cw'][' ']; |
| if ($pt) { |
| return $width * $this->_font_size_pt / 1000; |
| } else { |
| return $width * $this->_font_size / 1000; |
| } |
| } |
| /** |
| * Defines the line width. By default, the value equals 0.2 mm. The method |
| * can be called before the first page is created and the value is |
| * retained from page to page. |
| * |
| * @param float $width The width. |
| * |
| * @see File_PDF::line |
| * @see File_PDF::rect |
| * @see File_PDF::cell |
| * @see File_PDF::multiCell |
| */ |
| function setLineWidth($width) |
| { |
| $this->_line_width = $width; |
| if ($this->_page > 0) { |
| $this->_out(sprintf('%.2f w', $width * $this->_scale)); |
| } |
| } |
| /** |
| * Draws a line between two points. |
| * |
| * All coordinates can be negative to provide values from the right or |
| * bottom edge of the page (since File_PDF 0.2.0, Horde 3.2). |
| * |
| * @param float $x1 Abscissa of first point. |
| * @param float $y1 Ordinate of first point. |
| * @param float $x2 Abscissa of second point. |
| * @param float $y2 Ordinate of second point. |
| * |
| * @see File_PDF::setLineWidth |
| * @see File_PDF::setDrawColor. |
| */ |
| function line($x1, $y1, $x2, $y2) |
| { |
| if ($x1 < 0) { |
| $x1 += $this->w; |
| } |
| if ($y1 < 0) { |
| $y1 += $this->h; |
| } |
| if ($x2 < 0) { |
| $x2 += $this->w; |
| } |
| if ($y2 < 0) { |
| $y2 += $this->h; |
| } |
| $this->_out(sprintf('%.2f %.2f m %.2f %.2f l S', $x1 * $this->_scale, ($this->h - $y1) * $this->_scale, $x2 * $this->_scale, ($this->h - $y2) * $this->_scale)); |
| } |
| /** |
| * Outputs a rectangle. It can be drawn (border only), filled (with no |
| * border) or both. |
| * |
| * All coordinates can be negative to provide values from the right or |
| * bottom edge of the page (since File_PDF 0.2.0, Horde 3.2). |
| * |
| * @param float $x Abscissa of upper-left corner. |
| * @param float $y Ordinate of upper-left corner. |
| * @param float $width Width. |
| * @param float $height Height. |
| * @param float $style Style of rendering. Possible values are: |
| * - D or empty string: draw (default) |
| * - F: fill |
| * - DF or FD: draw and fill |
| * |
| * @see File_PDF::setLineWidth |
| * @see File_PDF::setDrawColor |
| * @see File_PDF::setFillColor |
| */ |
| function rect($x, $y, $width, $height, $style = '') |
| { |
| if ($x < 0) { |
| $x += $this->w; |
| } |
| if ($y < 0) { |
| $y += $this->h; |
| } |
| $style = strtoupper($style); |
| if ($style == 'F') { |
| $op = 'f'; |
| } elseif ($style == 'FD' || $style == 'DF') { |
| $op = 'B'; |
| } else { |
| $op = 'S'; |
| } |
| $x = $this->_toPt($x); |
| $y = $this->_toPt($y); |
| $width = $this->_toPt($width); |
| $height = $this->_toPt($height); |
| $this->_out(sprintf('%.2f %.2f %.2f %.2f re %s', $x, $this->hPt - $y, $width, -$height, $op)); |
| } |
| /** |
| * Outputs a circle. It can be drawn (border only), filled (with no |
| * border) or both. |
| * |
| * All coordinates can be negative to provide values from the right or |
| * bottom edge of the page (since File_PDF 0.2.0, Horde 3.2). |
| * |
| * @param float $x Abscissa of the center of the circle. |
| * @param float $y Ordinate of the center of the circle. |
| * @param float $r Circle radius. |
| * @param string $style Style of rendering. Possible values are: |
| * - D or empty string: draw (default) |
| * - F: fill |
| * - DF or FD: draw and fill |
| */ |
| function circle($x, $y, $r, $style = '') |
| { |
| if ($x < 0) { |
| $x += $this->w; |
| } |
| if ($y < 0) { |
| $y += $this->h; |
| } |
| $style = strtolower($style); |
| if ($style == 'f') { |
| $op = 'f'; // Style is fill only. |
| } elseif ($style == 'fd' || $style == 'df') { |
| $op = 'B'; // Style is fill and stroke. |
| } else { |
| $op = 'S'; // Style is stroke only. |
| } |
| $x = $this->_toPt($x); |
| $y = $this->_toPt($y); |
| $r = $this->_toPt($r); |
| /* Invert the y scale. */ |
| $y = $this->hPt - $y; |
| /* Length of the Bezier control. */ |
| $b = $r * 0.552; |
| /* Move from the given origin and set the current point |
| * to the start of the first Bezier curve. */ |
| $c = sprintf('%.2f %.2f m', $x - $r, $y); |
| $x = $x - $r; |
| /* First circle quarter. */ |
| $c .= sprintf(' %.2f %.2f %.2f %.2f %.2f %.2f c', |
| $x, $y + $b, // First control point. |
| $x + $r - $b, $y + $r, // Second control point. |
| $x + $r, $y + $r); // Final point. |
| /* Set x/y to the final point. */ |
| $x = $x + $r; |
| $y = $y + $r; |
| /* Second circle quarter. */ |
| $c .= sprintf(' %.2f %.2f %.2f %.2f %.2f %.2f c', |
| $x + $b, $y, |
| $x + $r, $y - $r + $b, |
| $x + $r, $y - $r); |
| /* Set x/y to the final point. */ |
| $x = $x + $r; |
| $y = $y - $r; |
| /* Third circle quarter. */ |
| $c .= sprintf(' %.2f %.2f %.2f %.2f %.2f %.2f c', |
| $x, $y - $b, |
| $x - $r + $b, $y - $r, |
| $x - $r, $y - $r); |
| /* Set x/y to the final point. */ |
| $x = $x - $r; |
| $y = $y - $r; |
| /* Fourth circle quarter. */ |
| $c .= sprintf(' %.2f %.2f %.2f %.2f %.2f %.2f c %s', |
| $x - $b, $y, |
| $x - $r, $y + $r - $b, |
| $x - $r, $y + $r, |
| $op); |
| /* Output the whole string. */ |
| $this->_out($c); |
| } |
| /** |
| * Imports a TrueType or Type1 font and makes it available. It is |
| * necessary to generate a font definition file first with the |
| * makefont.php utility. |
| * The location of the definition file (and the font file itself when |
| * embedding) must be found at the full path name included. |
| * |
| * Example: |
| * $pdf->addFont('Comic', 'I'); |
| * is equivalent to: |
| * $pdf->addFont('Comic', 'I', 'comici.php'); |
| * |
| * @param string $family Font family. The name can be chosen arbitrarily. |
| * If it is a standard family name, it will |
| * override the corresponding font. |
| * @param string $style Font style. Possible values are (case |
| * insensitive): |
| * - empty string: regular (default) |
| * - B: bold |
| * - I: italic |
| * - BI or IB: bold italic |
| * @param string $file The font definition file. By default, the name is |
| * built from the family and style, in lower case |
| * with no space. |
| * |
| * @see File_PDF::setFont |
| */ |
| function addFont($family, $style = '', $file = '') |
| { |
| $family = strtolower($family); |
| if ($family == 'arial') { |
| $family = 'helvetica'; |
| } |
| $style = strtoupper($style); |
| if ($style == 'IB') { |
| $style = 'BI'; |
| } |
| if (isset($this->_fonts[$family . $style])) { |
| return $this->raiseError(sprintf('Font already added: %s %s', $family, $style)); |
| } |
| if ($file == '') { |
| $file = str_replace(' ', '', $family) . strtolower($style) . '.php'; |
| } |
| include($file); |
| if (!isset($name)) { |
| return $this->raiseError('Could not include font definition file.'); |
| } |
| $i = count($this->_fonts) + 1; |
| $this->_fonts[$family . $style] = array('i' => $i, 'type' => $type, 'name' => $name, 'desc' => $desc, 'up' => $up, 'ut' => $ut, 'cw' => $cw, 'enc' => $enc, 'file' => $file); |
| if ($diff) { |
| /* Search existing encodings. */ |
| $d = 0; |
| $nb = count($this->_diffs); |
| for ($i = 1; $i <= $nb; $i++) { |
| if ($this->_diffs[$i] == $diff) { |
| $d = $i; |
| break; |
| } |
| } |
| if ($d == 0) { |
| $d = $nb + 1; |
| $this->_diffs[$d] = $diff; |
| } |
| $this->_fonts[$family.$style]['diff'] = $d; |
| } |
| if ($file) { |
| if ($type == 'TrueType') { |
| $this->_font_files[$file] = array('length1' => $originalsize); |
| } else { |
| $this->_font_files[$file] = array('length1' => $size1, 'length2' => $size2); |
| } |
| } |
| } |
| /** |
| * Sets the font used to print character strings. It is mandatory to call |
| * this method at least once before printing text or the resulting |
| * document would not be valid. The font can be either a standard one or a |
| * font added via the File_PDF::addFont method. Standard fonts use Windows |
| * encoding cp1252 (Western Europe). |
| * The method can be called before the first page is created and the font |
| * is retained from page to page. |
| * If you just wish to change the current font size, it is simpler to call |
| * File_PDF::setFontSize. |
| * |
| * @param string $family Family font. It can be either a name defined by |
| * File_PDF::addFont or one of the standard families |
| * (case insensitive): |
| * - Courier (fixed-width) |
| * - Helvetica or Arial (sans serif) |
| * - Times (serif) |
| * - Symbol (symbolic) |
| * - ZapfDingbats (symbolic) |
| * It is also possible to pass an empty string. In |
| * that case, the current family is retained. |
| * @param string $style Font style. Possible values are (case |
| * insensitive): |
| * - empty string: regular |
| * - B: bold |
| * - I: italic |
| * - U: underline |
| * or any combination. The default value is regular. |
| * Bold and italic styles do not apply to Symbol and |
| * ZapfDingbats. |
| * @param integer $size Font size in points. The default value is the |
| * current size. If no size has been specified since |
| * the beginning of the document, the value taken |
| * is 12. |
| * @param boolean $force Force the setting of the font. Each new page will |
| * require a new call to File_PDF::setFont and |
| * settings this to true will make sure that the |
| * checks for same font calls will be skipped. |
| * |
| * @see File_PDF::addFont |
| * @see File_PDF::setFontSize |
| * @see File_PDF::cell |
| * @see File_PDF::multiCell |
| * @see File_PDF::Write |
| */ |
| function setFont($family, $style = '', $size = null, $force = false) |
| { |
| $family = strtolower($family); |
| if ($family == 'arial') { |
| /* Use helvetica instead of arial. */ |
| $family = 'helvetica'; |
| } elseif ($family == 'symbol' || $family == 'zapfdingbats') { |
| /* These two fonts do not have styles available. */ |
| $style = ''; |
| } |
| $style = strtoupper($style); |
| /* Underline is handled separately, if specified in the style var |
| * remove it from the style and set the underline flag. */ |
| if (strpos($style, 'U') !== false) { |
| $this->_underline = true; |
| $style = str_replace('U', '', $style); |
| } else { |
| $this->_underline = false; |
| } |
| if ($style == 'IB') { |
| $style = 'BI'; |
| } |
| /* If no size specified, use current size. */ |
| if (is_null($size)) { |
| $size = $this->_font_size_pt; |
| } |
| /* If font requested is already the current font and no force setting |
| * of the font is requested (eg. when adding a new page) don't bother |
| * with the rest of the function and simply return. */ |
| if ($this->_font_family == $family && $this->_font_style == $style && |
| $this->_font_size_pt == $size && !$force) { |
| return; |
| } |
| /* Set the font key. */ |
| $fontkey = $family . $style; |
| /* Test if already cached. */ |
| if (!isset($this->_fonts[$fontkey])) { |
| /* Get the character width definition file. */ |
| $font_widths = &File_PDF::_getFontFile($fontkey); |
| if (is_a($font_widths, 'PEAR_Error')) { |
| return $font_widths; |
| } |
| $i = count($this->_fonts) + 1; |
| $this->_fonts[$fontkey] = array( |
| 'i' => $i, |
| 'type' => 'core', |
| 'name' => $this->_core_fonts[$fontkey], |
| 'up' => -100, |
| 'ut' => 50, |
| 'cw' => $font_widths[$fontkey]); |
| } |
| /* Store font information as current font. */ |
| $this->_font_family = $family; |
| $this->_font_style = $style; |
| $this->_font_size_pt = $size; |
| $this->_font_size = $size / $this->_scale; |
| $this->_current_font = &$this->_fonts[$fontkey]; |
| /* Output font information if at least one page has been defined. */ |
| if ($this->_page > 0) { |
| $this->_out(sprintf('BT /F%d %.2f Tf ET', $this->_current_font['i'], $this->_font_size_pt)); |
| } |
| } |
| /** |
| * Defines the size of the current font. |
| * |
| * @param float $size The size (in points). |
| * |
| * @see File_PDF::setFont |
| */ |
| function setFontSize($size) |
| { |
| /* If the font size is already the current font size, just return. */ |
| if ($this->_font_size_pt == $size) { |
| return; |
| } |
| /* Set the current font size, both in points and scaled to user |
| * units. */ |
| $this->_font_size_pt = $size; |
| $this->_font_size = $size / $this->_scale; |
| /* Output font information if at least one page has been defined. */ |
| if ($this->_page > 0) { |
| $this->_out(sprintf('BT /F%d %.2f Tf ET', $this->_current_font['i'], $this->_font_size_pt)); |
| } |
| } |
| /** |
| * Defines the style of the current font. |
| * |
| * @param string $style The font style. |
| * |
| * @see File_PDF::setFont |
| * @since File_PDF 0.2.0 |
| * @since Horde 3.2 |
| */ |
| function setFontStyle($style) |
| { |
| $this->setFont($this->_font_family, $style); |
| } |
| /** |
| * Creates a new internal link and returns its identifier. An internal |
| * link is a clickable area which directs to another place within the |
| * document. |
| * The identifier can then be passed to File_PDF::cell, File_PDF::write, |
| * File_PDF::image or File_PDF::link. The destination is defined with |
| * File_PDF::setLink. |
| * |
| * @see File_PDF::cell |
| * @see File_PDF::Write |
| * @see File_PDF::image |
| * @see File_PDF::Link |
| * @see File_PDF::SetLink |
| */ |
| function addLink() |
| { |
| $n = count($this->_links) + 1; |
| $this->_links[$n] = array(0, 0); |
| return $n; |
| } |
| /** |
| * Defines the page and position a link points to. |
| * |
| * @param integer $link The link identifier returned by File_PDF::addLink. |
| * @param float $y Ordinate of target position; -1 indicates the |
| * current position. The default value is 0 (top of |
| * page). |
| * @param integer $page Number of target page; -1 indicates the current |
| * page. This is the default value. |
| * |
| * @see File_PDF::addLink |
| */ |
| function setLink($link, $y = 0, $page = -1) |
| { |
| if ($y == -1) { |
| $y = $this->y; |
| } |
| if ($page == -1) { |
| $page = $this->_page; |
| } |
| $this->_links[$link] = array($page, $y); |
| } |
| /** |
| * Puts a link on a rectangular area of the page. Text or image links are |
| * generally put via File_PDF::cell, File_PDF::Write or File_PDF::image, |
| * but this method can be useful for instance to define a clickable area |
| * inside an image. |
| * |
| * All coordinates can be negative to provide values from the right or |
| * bottom edge of the page (since File_PDF 0.2.0, Horde 3.2). |
| * |
| * @param float $x Abscissa of the upper-left corner of the rectangle. |
| * @param float $y Ordinate of the upper-left corner of the rectangle. |
| * @param float $width Width of the rectangle. |
| * @param float $height Height of the rectangle. |
| * @param mixed $link URL or identifier returned by File_PDF::addLink. |
| * |
| * @see File_PDF::addLink |
| * @see File_PDF::cell |
| * @see File_PDF::Write |
| * @see File_PDF::image |
| */ |
| function link($x, $y, $width, $height, $link) |
| { |
| if ($x < 0) { |
| $x += $this->w; |
| } |
| if ($y < 0) { |
| $y += $this->h; |
| } |
| /* Set up the coordinates with correct scaling in pt. */ |
| $x = $this->_toPt($x); |
| $y = $this->hPt - $this->_toPt($y); |
| $width = $this->_toPt($width); |
| $height = $this->_toPt($height); |
| /* Save link to page links array. */ |
| $this->_link($x, $y, $width, $height, $link); |
| } |
| /** |
| * Prints a character string. The origin is on the left of the first |
| * character, on the baseline. This method allows to place a string |
| * precisely on the page, but it is usually easier to use File_PDF::cell, |
| * File_PDF::multiCell or File_PDF::Write which are the standard methods to |
| * print text. |
| * |
| * All coordinates can be negative to provide values from the right or |
| * bottom edge of the page (since File_PDF 0.2.0, Horde 3.2). |
| * |
| * @param float $x Abscissa of the origin. |
| * @param float $y Ordinate of the origin. |
| * @param string $text String to print. |
| * |
| * @see File_PDF::setFont |
| * @see File_PDF::cell |
| * @see File_PDF::multiCell |
| * @see File_PDF::Write |
| */ |
| function text($x, $y, $text) |
| { |
| if ($x < 0) { |
| $x += $this->w; |
| } |
| if ($y < 0) { |
| $y += $this->h; |
| } |
| /* Scale coordinates into points and set correct Y position. */ |
| $x = $this->_toPt($x); |
| $y = $this->hPt - $this->_toPt($y); |
| /* Escape any potentially harmful characters. */ |
| $text = $this->_escape($text); |
| $out = sprintf('BT %.2f %.2f Td (%s) Tj ET', $x, $y, $text); |
| if ($this->_underline && $text != '') { |
| $out .= ' ' . $this->_doUnderline($x, $y, $text); |
| } |
| if ($this->_color_flag) { |
| $out = sprintf('q %s %s Q', $this->_text_color, $out); |
| } |
| $this->_out($out); |
| } |
| /** |
| * Whenever a page break condition is met, the method is called, and the |
| * break is issued or not depending on the returned value. The default |
| * implementation returns a value according to the mode selected by |
| * File_PDF:setAutoPageBreak. |
| * This method is called automatically and should not be called directly |
| * by the application. |
| * |
| * @return boolean |
| * |
| * @see File_PDF::setAutoPageBreak. |
| */ |
| function acceptPageBreak() |
| { |
| return $this->_auto_page_break; |
| } |
| /** |
| * Prints a cell (rectangular area) with optional borders, background |
| * color and character string. The upper-left corner of the cell |
| * corresponds to the current position. The text can be aligned or |
| * centered. After the call, the current position moves to the right or to |
| * the next line. It is possible to put a link on the text. |
| * If automatic page breaking is enabled and the cell goes beyond the |
| * limit, a page break is done before outputting. |
| * |
| * @param float $width Cell width. If 0, the cell extends up to the right |
| * margin. |
| * @param float $height Cell height. Default value: 0. |
| * @param string $text String to print. Default value: empty. |
| * @param mixed $border Indicates if borders must be drawn around the |
| * cell. The value can be either a number: |
| * - 0: no border (default) |
| * - 1: frame |
| * or a string containing some or all of the |
| * following characters (in any order): |
| * - L: left |
| * - T: top |
| * - R: right |
| * - B: bottom |
| * @param integer $ln Indicates where the current position should go |
| * after the call. Possible values are: |
| * - 0: to the right (default) |
| * - 1: to the beginning of the next line |
| * - 2: below |
| * Putting 1 is equivalent to putting 0 and calling |
| * File_PDF::newLine just after. |
| * @param string $align Allows to center or align the text. Possible |
| * values are: |
| * - L or empty string: left (default) |
| * - C: center |
| * - R: right |
| * @param integer $fill Indicates if the cell fill type. Possible values |
| * are: |
| * - 0: transparent (default) |
| * - 1: painted |
| * @param string $link URL or identifier returned by |
| * File_PDF:addLink. |
| * |
| * @see File_PDF::setFont |
| * @see File_PDF::setDrawColor |
| * @see File_PDF::setFillColor |
| * @see File_PDF::setLineWidth |
| * @see File_PDF::addLink |
| * @see File_PDF::newLine |
| * @see File_PDF::multiCell |
| * @see File_PDF::Write |
| * @see File_PDF::setAutoPageBreak |
| */ |
| function cell($width, $height = 0, $text = '', $border = 0, $ln = 0, |
| $align = '', $fill = 0, $link = '') |
| { |
| $k = $this->_scale; |
| if ($this->y + $height > $this->_page_break_trigger && |
| !$this->_in_footer && $this->AcceptPageBreak()) { |
| $x = $this->x; |
| $ws = $this->_word_spacing; |
| if ($ws > 0) { |
| $this->_word_spacing = 0; |
| $this->_out('0 Tw'); |
| } |
| $this->addPage($this->_current_orientation); |
| $this->x = $x; |
| if ($ws > 0) { |
| $this->_word_spacing = $ws; |
| $this->_out(sprintf('%.3f Tw', $ws * $k)); |
| } |
| } |
| if ($width == 0) { |
| $width = $this->w - $this->_right_margin - $this->x; |
| } |
| $s = ''; |
| if ($fill == 1 || $border == 1) { |
| if ($fill == 1) { |
| $op = ($border == 1) ? 'B' : 'f'; |
| } else { |
| $op = 'S'; |
| } |
| $s = sprintf('%.2f %.2f %.2f %.2f re %s ', $this->x * $k, ($this->h - $this->y) * $k, $width * $k, -$height * $k, $op); |
| } |
| if (is_string($border)) { |
| if (strpos($border, 'L') !== false) { |
| $s .= sprintf('%.2f %.2f m %.2f %.2f l S ', $this->x * $k, ($this->h - $this->y) * $k, $this->x * $k, ($this->h - ($this->y + $height)) * $k); |
| } |
| if (strpos($border, 'T') !== false) { |
| $s .= sprintf('%.2f %.2f m %.2f %.2f l S ', $this->x * $k, ($this->h - $this->y) * $k, ($this->x + $width) * $k, ($this->h - $this->y) * $k); |
| } |
| if (strpos($border, 'R') !== false) { |
| $s .= sprintf('%.2f %.2f m %.2f %.2f l S ', ($this->x + $width) * $k, ($this->h - $this->y) * $k, ($this->x + $width) * $k, ($this->h - ($this->y + $height)) * $k); |
| } |
| if (strpos($border, 'B') !== false) { |
| $s .= sprintf('%.2f %.2f m %.2f %.2f l S ', $this->x * $k, ($this->h - ($this->y + $height)) * $k, ($this->x + $width) * $k, ($this->h - ($this->y + $height)) * $k); |
| } |
| } |
| if ($text != '') { |
| if ($align == 'R') { |
| $dx = $width - $this->_cell_margin - $this->getStringWidth($text); |
| } elseif ($align == 'C') { |
| $dx = ($width - $this->getStringWidth($text)) / 2; |
| } else { |
| $dx = $this->_cell_margin; |
| } |
| if ($this->_color_flag) { |
| $s .= 'q ' . $this->_text_color . ' '; |
| } |
| $text = str_replace(')', '\\)', str_replace('(', '\\(', str_replace('\\', '\\\\', $text))); |
| $test2 = ((.5 * $height) + (.3 * $this->_font_size)); |
| $test1 = $this->fhPt - (($this->y + $test2) * $k); |
| $s .= sprintf('BT %.2f %.2f Td (%s) Tj ET', ($this->x + $dx) * $k, ($this->h - ($this->y + .5 * $height + .3 * $this->_font_size)) * $k, $text); |
| if ($this->_underline) { |
| $s .= ' ' . $this->_doUnderline($this->x + $dx, $this->y + .5 * $height + .3 * $this->_font_size, $text); |
| } |
| if ($this->_color_flag) { |
| $s .= ' Q'; |
| } |
| if ($link) { |
| $this->link($this->x + $dx, $this->y + .5 * $height-.5 * $this->_font_size, $this->getStringWidth($text), $this->_font_size, $link); |
| } |
| } |
| if ($s) { |
| $this->_out($s); |
| } |
| $this->_last_height = $height; |
| if ($ln > 0) { |
| /* Go to next line. */ |
| $this->y += $height; |
| if ($ln == 1) { |
| $this->x = $this->_left_margin; |
| } |
| } else { |
| $this->x += $width; |
| } |
| } |
| /** |
| * This method allows printing text with line breaks. They can be |
| * automatic (as soon as the text reaches the right border of the cell) or |
| * explicit (via the \n character). As many cells as necessary are output, |
| * one below the other. |
| * Text can be aligned, centered or justified. The cell block can be |
| * framed and the background painted. |
| * |
| * @param float $width Width of cells. If 0, they extend up to the right |
| * margin of the page. |
| * @param float $height Height of cells. |
| * @param string $text String to print. |
| * @param mixed $border Indicates if borders must be drawn around the cell |
| * block. The value can be either a number: |
| * - 0: no border (default) |
| * - 1: frame |
| * or a string containing some or all of the |
| * following characters (in any order): |
| * - L: left |
| * - T: top |
| * - R: right |
| * - B: bottom |
| * @param string $align Sets the text alignment. Possible values are: |
| * - L: left alignment |
| * - C: center |
| * - R: right alignment |
| * - J: justification (default value) |
| * @param integer $fill Indicates if the cell background must: |
| * - 0: transparent (default) |
| * - 1: painted |
| * |
| * @see File_PDF::setFont |
| * @see File_PDF::setDrawColor |
| * @see File_PDF::setFillColor |
| * @see File_PDF::setLineWidth |
| * @see File_PDF::cell |
| * @see File_PDF::write |
| * @see File_PDF::setAutoPageBreak |
| */ |
| function multiCell($width, $height, $text, $border = 0, $align = 'J', |
| $fill = 0) |
| { |
| $cw = &$this->_current_font['cw']; |
| if ($width == 0) { |
| $width = $this->w - $this->_right_margin - $this->x; |
| } |
| $wmax = ($width-2 * $this->_cell_margin) * 1000 / $this->_font_size; |
| $s = str_replace("\r", '', $text); |
| $nb = strlen($s); |
| if ($nb > 0 && $s[$nb-1] == "\n") { |
| $nb--; |
| } |
| $b = 0; |
| if ($border) { |
| if ($border == 1) { |
| $border = 'LTRB'; |
| $b = 'LRT'; |
| $b2 = 'LR'; |
| } else { |
| $b2 = ''; |
| if (strpos($border, 'L') !== false) { |
| $b2 .= 'L'; |
| } |
| if (strpos($border, 'R') !== false) { |
| $b2 .= 'R'; |
| } |
| $b = (strpos($border, 'T') !== false) ? $b2 . 'T' : $b2; |
| } |
| } |
| $sep = -1; |
| $i = 0; |
| $j = 0; |
| $l = 0; |
| $ns = 0; |
| $nl = 1; |
| while ($i < $nb) { |
| /* Get next character. */ |
| $c = $s[$i]; |
| if ($c == "\n") { |
| /* Explicit line break. */ |
| if ($this->_word_spacing > 0) { |
| $this->_word_spacing = 0; |
| $this->_out('0 Tw'); |
| } |
| $this->cell($width, $height, substr($s, $j, $i-$j), $b, 2, $align, $fill); |
| $i++; |
| $sep = -1; |
| $j = $i; |
| $l = 0; |
| $ns = 0; |
| $nl++; |
| if ($border && $nl == 2) { |
| $b = $b2; |
| } |
| continue; |
| } |
| if ($c == ' ') { |
| $sep = $i; |
| $ls = $l; |
| $ns++; |
| } |
| $l += $cw[$c]; |
| if ($l > $wmax) { |
| /* Automatic line break. */ |
| if ($sep == -1) { |
| if ($i == $j) { |
| $i++; |
| } |
| if ($this->_word_spacing > 0) { |
| $this->_word_spacing = 0; |
| $this->_out('0 Tw'); |
| } |
| $this->cell($width, $height, substr($s, $j, $i - $j), $b, 2, $align, $fill); |
| } else { |
| if ($align == 'J') { |
| $this->_word_spacing = ($ns>1) ? ($wmax - $ls)/1000 * $this->_font_size / ($ns - 1) : 0; |
| $this->_out(sprintf('%.3f Tw', $this->_word_spacing * $this->_scale)); |
| } |
| $this->cell($width, $height, substr($s, $j, $sep - $j), $b, 2, $align, $fill); |
| $i = $sep + 1; |
| } |
| $sep = -1; |
| $j = $i; |
| $l = 0; |
| $ns = 0; |
| $nl++; |
| if ($border && $nl == 2) { |
| $b = $b2; |
| } |
| } else { |
| $i++; |
| } |
| } |
| /* Last chunk. */ |
| if ($this->_word_spacing > 0) { |
| $this->_word_spacing = 0; |
| $this->_out('0 Tw'); |
| } |
| if ($border && strpos($border, 'B') !== false) { |
| $b .= 'B'; |
| } |
| $this->cell($width, $height, substr($s, $j, $i), $b, 2, $align, $fill); |
| $this->x = $this->_left_margin; |
| } |
| /** |
| * This method prints text from the current position. When the right |
| * margin is reached (or the \n character is met) a line break occurs and |
| * text continues from the left margin. Upon method exit, the current |
| * position is left just at the end of the text. |
| * It is possible to put a link on the text. |
| * |
| * Example: |
| * //Begin with regular font |
| * $pdf->setFont('Arial','',14); |
| * $pdf->write(5,'Visit '); |
| * //Then put a blue underlined link |
| * $pdf->setTextColor(0,0,255); |
| * $pdf->setFont('','U'); |
| * $pdf->write(5,'www.fpdf.org','http://www.fpdf.org'); |
| * |
| * @param float $height Line height. |
| * @param string $text String to print. |
| * @param mixed $link URL or identifier returned by AddLink(). |
| * |
| * @see File_PDF::setFont |
| * @see File_PDF::addLink |
| * @see File_PDF::multiCell |
| * @see File_PDF::setAutoPageBreak |
| */ |
| function write($height, $text, $link = '') |
| { |
| $cw = &$this->_current_font['cw']; |
| $width = $this->w - $this->_right_margin - $this->x; |
| $wmax = ($width - 2 * $this->_cell_margin) * 1000 / $this->_font_size; |
| $s = str_replace("\r", '', $text); |
| $nb = strlen($s); |
| $sep = -1; |
| $i = 0; |
| $j = 0; |
| $l = 0; |
| $nl = 1; |
| while ($i < $nb) { |
| /* Get next character. */ |
| $c = $s{$i}; |
| if ($c == "\n") { |
| /* Explicit line break. */ |
| $this->cell($width, $height, substr($s, $j, $i - $j), 0, 2, '', 0, $link); |
| $i++; |
| $sep = -1; |
| $j = $i; |
| $l = 0; |
| if ($nl == 1) { |
| $this->x = $this->_left_margin; |
| $width = $this->w - $this->_right_margin - $this->x; |
| $wmax = ($width - 2 * $this->_cell_margin) * 1000 / $this->_font_size; |
| } |
| $nl++; |
| continue; |
| } |
| if ($c == ' ') { |
| $sep = $i; |
| $ls = $l; |
| } |
| $l += (isset($cw[$c]) ? $cw[$c] : 0); |
| if ($l > $wmax) { |
| /* Automatic line break. */ |
| if ($sep == -1) { |
| if ($this->x > $this->_left_margin) { |
| /* Move to next line. */ |
| $this->x = $this->_left_margin; |
| $this->y += $height; |
| $width = $this->w - $this->_right_margin - $this->x; |
| $wmax = ($width - 2 * $this->_cell_margin) * 1000 / $this->_font_size; |
| $i++; |
| $nl++; |
| continue; |
| } |
| if ($i == $j) { |
| $i++; |
| } |
| $this->cell($width, $height, substr($s, $j, $i - $j), 0, 2, '', 0, $link); |
| } else { |
| $this->cell($width, $height, substr($s, $j, $sep - $j), 0, 2, '', 0, $link); |
| $i = $sep + 1; |
| } |
| $sep = -1; |
| $j = $i; |
| $l = 0; |
| if ($nl == 1) { |
| $this->x = $this->_left_margin; |
| $width = $this->w - $this->_right_margin - $this->x; |
| $wmax = ($width - 2 * $this->_cell_margin) * 1000 / $this->_font_size; |
| } |
| $nl++; |
| } else { |
| $i++; |
| } |
| } |
| /* Last chunk. */ |
| if ($i != $j) { |
| $this->cell($l / 1000 * $this->_font_size, $height, substr($s, $j, $i), 0, 0, '', 0, $link); |
| } |
| } |
| /** |
| * Writes text at an angle. |
| * |
| * All coordinates can be negative to provide values from the right or |
| * bottom edge of the page (since File_PDF 0.2.0, Horde 3.2). |
| * |
| * @param integer $x X coordinate. |
| * @param integer $y Y coordinate. |
| * @param string $text Text to write. |
| * @param float $text_angle Angle to rotate (Eg. 90 = bottom to top). |
| * @param float $font_angle Rotate characters as well as text. |
| * |
| * @see File_PDF::setFont |
| */ |
| function writeRotated($x, $y, $text, $text_angle, $font_angle = 0) |
| { |
| if ($x < 0) { |
| $x += $this->w; |
| } |
| if ($y < 0) { |
| $y += $this->h; |
| } |
| /* Escape text. */ |
| $text = $this->_escape($text); |
| $font_angle += 90 + $text_angle; |
| $text_angle *= M_PI / 180; |
| $font_angle *= M_PI / 180; |
| $text_dx = cos($text_angle); |
| $text_dy = sin($text_angle); |
| $font_dx = cos($font_angle); |
| $font_dy = sin($font_angle); |
| $s= sprintf('BT %.2f %.2f %.2f %.2f %.2f %.2f Tm (%s) Tj ET', |
| $text_dx, $text_dy, $font_dx, $font_dy, |
| $x * $this->_scale, ($this->h-$y) * $this->_scale, $text); |
| if ($this->_draw_color) { |
| $s = 'q ' . $this->_draw_color . ' ' . $s . ' Q'; |
| } |
| $this->_out($s); |
| } |
| /** |
| * Prints an image in the page. The upper-left corner and at least one of |
| * the dimensions must be specified; the height or the width can be |
| * calculated automatically in order to keep the image proportions. |
| * Supported formats are JPEG and PNG. |
| * |
| * All coordinates can be negative to provide values from the right or |
| * bottom edge of the page (since File_PDF 0.2.0, Horde 3.2). |
| * |
| * For JPEG, all flavors are allowed: |
| * - gray scales |
| * - true colors (24 bits) |
| * - CMYK (32 bits) |
| * |
| * For PNG, are allowed: |
| * - gray scales on at most 8 bits (256 levels) |
| * - indexed colors |
| * - true colors (24 bits) |
| * but are not supported: |
| * - Interlacing |
| * - Alpha channel |
| * |
| * If a transparent color is defined, it will be taken into account (but |
| * will be only interpreted by Acrobat 4 and above). |
| * The format can be specified explicitly or inferred from the file |
| * extension. |
| * It is possible to put a link on the image. |
| * |
| * Remark: if an image is used several times, only one copy will be |
| * embedded in the file. |
| * |
| * @param string $file Name of the file containing the image. |
| * @param float $x Abscissa of the upper-left corner. |
| * @param float $y Ordinate of the upper-left corner. |
| * @param float $width Width of the image in the page. If equal to zero, |
| * it is automatically calculated to keep the |
| * original proportions. |
| * @param float $height Height of the image in the page. If not specified |
| * or equal to zero, it is automatically calculated |
| * to keep the original proportions. |
| * @param string $type Image format. Possible values are (case |
| * insensitive) : JPG, JPEG, PNG. If not specified, |
| * the type is inferred from the file extension. |
| * @param mixed $link URL or identifier returned by File_PDF::addLink. |
| * |
| * @see File_PDF::addLink |
| */ |
| function image($file, $x, $y, $width = 0, $height = 0, $type = '', |
| $link = '') |
| { |
| if ($x < 0) { |
| $x += $this->w; |
| } |
| if ($y < 0) { |
| $y += $this->h; |
| } |
| if (!isset($this->_images[$file])) { |
| /* First use of image, get some file info. */ |
| if ($type == '') { |
| $pos = strrpos($file, '.'); |
| if ($pos === false) { |
| return $this->raiseError(sprintf('Image file has no extension and no type was specified: %s', $file)); |
| } |
| $type = substr($file, $pos + 1); |
| } |
| $type = strtolower($type); |
| $mqr = get_magic_quotes_runtime(); |
| set_magic_quotes_runtime(0); |
| if ($type == 'jpg' || $type == 'jpeg') { |
| $info = $this->_parseJPG($file); |
| } elseif ($type == 'png') { |
| $info = $this->_parsePNG($file); |
| } else { |
| return $this->raiseError(sprintf('Unsupported image file type: %s', $type)); |
| } |
| if (is_a($info, 'PEAR_Error')) { |
| return $info; |
| } |
| set_magic_quotes_runtime($mqr); |
| $info['i'] = count($this->_images) + 1; |
| $this->_images[$file] = $info; |
| } else { |
| $info = $this->_images[$file]; |
| } |
| /* Make sure all vars are converted to pt scale. */ |
| $x = $this->_toPt($x); |
| $y = $this->_toPt($y); |
| $width = $this->_toPt($width); |
| $height = $this->_toPt($height); |
| /* If not specified do automatic width and height calculations. */ |
| if (empty($width) && empty($height)) { |
| $width = $info['w']; |
| $height = $info['h']; |
| } elseif (empty($width)) { |
| $width = $height * $info['w'] / $info['h']; |
| } elseif (empty($height)) { |
| $height = $width * $info['h'] / $info['w']; |
| } |
| $this->_out(sprintf('q %.2f 0 0 %.2f %.2f %.2f cm /I%d Do Q', $width, $height, $x, $this->hPt - ($y + $height), $info['i'])); |
| /* Set any link if requested. */ |
| if ($link) { |
| $this->_link($x, $y, $width, $height, $link); |
| } |
| } |
| /** |
| * Performs a line break. The current abscissa goes back to the left |
| * margin and the ordinate increases by the amount passed in parameter. |
| * |
| * @param float $height The height of the break. By default, the value |
| * equals the height of the last printed cell. |
| * |
| * @see File_PDF::cell |
| */ |
| function newLine($height = '') |
| { |
| $this->x = $this->_left_margin; |
| if (is_string($height)) { |
| $this->y += $this->_last_height; |
| } else { |
| $this->y += $height; |
| } |
| } |
| /** |
| * Returns the abscissa of the current position in user units. |
| * |
| * @return float |
| * |
| * @see File_PDF::setX |
| * @see File_PDF::getY |
| * @see File_PDF::setY |
| */ |
| function getX() |
| { |
| return $this->x; |
| } |
| /** |
| * Defines the abscissa of the current position. If the passed value is |
| * negative, it is relative to the right of the page. |
| * |
| * @param float $x The value of the abscissa. |
| * |
| * @see File_PDF::getX |
| * @see File_PDF::getY |
| * @see File_PDF::setY |
| * @see File_PDF::setXY |
| */ |
| function setX($x) |
| { |
| if ($x >= 0) { |
| /* Absolute value. */ |
| $this->x = $x; |
| } else { |
| /* Negative, so relative to right edge of the page. */ |
| $this->x = $this->w + $x; |
| } |
| } |
| /** |
| * Returns the ordinate of the current position in user units. |
| * |
| * @return float |
| * |
| * @see File_PDF::setY |
| * @see File_PDF::getX |
| * @see File_PDF::setX |
| */ |
| function getY() |
| { |
| return $this->y; |
| } |
| /** |
| * Defines the ordinate of the current position. If the passed value is |
| * negative, it is relative to the bottom of the page. |
| * |
| * @param float $y The value of the ordinate. |
| * |
| * @see File_PDF::getX |
| * @see File_PDF::getY |
| * @see File_PDF::setY |
| * @see File_PDF::setXY |
| */ |
| function setY($y) |
| { |
| if ($y >= 0) { |
| /* Absolute value. */ |
| $this->y = $y; |
| } else { |
| /* Negative, so relative to bottom edge of the page. */ |
| $this->y = $this->h + $y; |
| } |
| } |
| /** |
| * Defines the abscissa and ordinate of the current position. If the |
| * passed values are negative, they are relative respectively to the right |
| * and bottom of the page. |
| * |
| * @param float $x The value of the abscissa. |
| * @param float $y The value of the ordinate. |
| * |
| * @see File_PDF::setX |
| * @see File_PDF::setY |
| */ |
| function setXY($x, $y) |
| { |
| $this->setY($y); |
| $this->setX($x); |
| } |
| /** |
| * Returns the raw PDF file. |
| * |
| * @see File_PDF::output |
| */ |
| function getOutput() |
| { |
| /* Check whether file has been closed. */ |
| if ($this->_state < 3) { |
| $this->close(); |
| } |
| return $this->_buffer; |
| } |
| /** |
| * Function to output the buffered data to the browser. |
| * |
| * @param string $filename The filename for the output file. |
| * @param boolean $inline True if inline, false if attachment. |
| */ |
| function output($filename = 'unknown.pdf', $inline = false) |
| { |
| /* Check whether file has been closed. */ |
| if ($this->_state < 3) { |
| $this->close(); |
| } |
| /* Check if headers have been sent. */ |
| if (headers_sent()) { |
| return $this->raiseError('Unable to send PDF file, some data has already been output to browser.'); |
| } |
| /* If HTTP_Download is not available return a PEAR_Error. */ |
| if (!include_once 'HTTP/Download.php') { |
| return $this->raiseError('Missing PEAR package HTTP_Download.'); |
| } |
| /* Params for the output. */ |
| $disposition = !$inline ? HTTP_DOWNLOAD_ATTACHMENT : HTTP_DOWNLOAD_INLINE; |
| $params = array('data' => $this->_buffer, |
| 'contenttype' => 'application/pdf', |
| 'contentdisposition' => array($disposition, $filename)); |
| /* Output the file. */ |
| return HTTP_Download::staticSend($params); |
| } |
| /** |
| * Function to save the PDF file somewhere local to the server. |
| * |
| * @param string $filename The filename for the output file. |
| */ |
| function save($filename = 'unknown.pdf') |
| { |
| /* Check whether file has been closed. */ |
| if ($this->_state < 3) { |
| $this->close(); |
| } |
| $f = fopen($filename, 'wb'); |
| if (!$f) { |
| return $this->raiseError(sprintf('Unable to save PDF file: %s', $filename)); |
| } |
| fwrite($f, $this->_buffer, strlen($this->_buffer)); |
| fclose($f); |
| } |
| function _toPt($val) |
| { |
| return $val * $this->_scale; |
| } |
| function &_getFontFile($fontkey, $path = '') |
| { |
| static $font_widths; |
| if (!isset($font_widths[$fontkey])) { |
| if (!empty($path)) { |
| $file = $path . strtolower($fontkey) . '.php'; |
| } else { |
| $file = 'File/PDF/fonts/' . strtolower($fontkey) . '.php'; |
| } |
| include $file; |
| if (!isset($font_widths[$fontkey])) { |
| return $this->raiseError(sprintf('Could not include font metric file: %s', $file)); |
| } |
| } |
| return $font_widths; |
| } |
| function _link($x, $y, $width, $height, $link) |
| { |
| /* Save link to page links array. */ |
| $this->_page_links[$this->_page][] = array($x, $y, $width, $height, $link); |
| } |
| function _beginDoc() |
| { |
| /* Start document, but only if not yet started. */ |
| if ($this->_state < 1) { |
| $this->_state = 1; |
| $this->_out('%PDF-1.3'); |
| } |
| } |
| function _putPages() |
| { |
| $nb = $this->_page; |
| if (!empty($this->_alias_nb_pages)) { |
| /* Replace number of pages. */ |
| for ($n = 1; $n <= $nb; $n++) { |
| $this->_pages[$n] = str_replace($this->_alias_nb_pages, $nb, $this->_pages[$n]); |
| } |
| } |
| if ($this->_default_orientation == 'P') { |
| $wPt = $this->fwPt; |
| $hPt = $this->fhPt; |
| } else { |
| $wPt = $this->fhPt; |
| $hPt = $this->fwPt; |
| } |
| $filter = ($this->_compress) ? '/Filter /FlateDecode ' : ''; |
| for ($n = 1; $n <= $nb; $n++) { |
| /* Page */ |
| $this->_newobj(); |
| $this->_out('<</Type /Page'); |
| $this->_out('/Parent 1 0 R'); |
| if (isset($this->_orientation_changes[$n])) { |
| $this->_out(sprintf('/MediaBox [0 0 %.2f %.2f]', $hPt, $wPt)); |
| } |
| $this->_out('/Resources 2 0 R'); |
| if (isset($this->_page_links[$n])) { |
| /* Links */ |
| $annots = '/Annots ['; |
| foreach ($this->_page_links[$n] as $pl) { |
| $rect = sprintf('%.2f %.2f %.2f %.2f', $pl[0], $pl[1], $pl[0] + $pl[2], $pl[1] - $pl[3]); |
| $annots .= '<</Type /Annot /Subtype /Link /Rect [' . $rect . '] /Border [0 0 0] '; |
| if (is_string($pl[4])) { |
| $annots .= '/A <</S /URI /URI ' . $this->_textString($pl[4]) . '>>>>'; |
| } else { |
| $l = $this->_links[$pl[4]]; |
| $height = isset($this->_orientation_changes[$l[0]]) ? $wPt : $hPt; |
| $annots .= sprintf('/Dest [%d 0 R /XYZ 0 %.2f null]>>', 1 + 2 * $l[0], $height - $l[1] * $this->_scale); |
| } |
| } |
| $this->_out($annots.']'); |
| } |
| $this->_out('/Contents ' . ($this->_n + 1) . ' 0 R>>'); |
| $this->_out('endobj'); |
| /* Page content */ |
| $p = ($this->_compress) ? gzcompress($this->_pages[$n]) : $this->_pages[$n]; |
| $this->_newobj(); |
| $this->_out('<<' . $filter . '/Length ' . strlen($p) . '>>'); |
| $this->_putStream($p); |
| $this->_out('endobj'); |
| } |
| /* Pages root */ |
| $this->_offsets[1] = strlen($this->_buffer); |
| $this->_out('1 0 obj'); |
| $this->_out('<</Type /Pages'); |
| $kids = '/Kids ['; |
| for ($i = 0; $i < $nb; $i++) { |
| $kids .= (3 + 2 * $i) . ' 0 R '; |
| } |
| $this->_out($kids . ']'); |
| $this->_out('/Count ' . $nb); |
| $this->_out(sprintf('/MediaBox [0 0 %.2f %.2f]', $wPt, $hPt)); |
| $this->_out('>>'); |
| $this->_out('endobj'); |
| } |
| function _putFonts() |
| { |
| $nf = $this->_n; |
| foreach ($this->_diffs as $diff) { |
| /* Encodings */ |
| $this->_newobj(); |
| $this->_out('<</Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences [' . $diff . ']>>'); |
| $this->_out('endobj'); |
| } |
| $mqr = get_magic_quotes_runtime(); |
| set_magic_quotes_runtime(0); |
| foreach ($this->_font_files as $file => $info) { |
| /* Font file embedding. */ |
| $this->_newobj(); |
| $this->_font_files[$file]['n'] = $this->_n; |
| $size = filesize($file); |
| if (!$size) { |
| return $this->raiseError('Font file not found.'); |
| } |
| $this->_out('<</Length ' . $size); |
| if (substr($file, -2) == '.z') { |
| $this->_out('/Filter /FlateDecode'); |
| } |
| $this->_out('/Length1 ' . $info['length1']); |
| if (isset($info['length2'])) { |
| $this->_out('/Length2 ' . $info['length2'] . ' /Length3 0'); |
| } |
| $this->_out('>>'); |
| $f = fopen($file, 'rb'); |
| $this->_putStream(fread($f, $size)); |
| fclose($f); |
| $this->_out('endobj'); |
| } |
| set_magic_quotes_runtime($mqr); |
| foreach ($this->_fonts as $k => $font) { |
| /* Font objects */ |
| $this->_newobj(); |
| $this->_fonts[$k]['n'] = $this->_n; |
| $name = $font['name']; |
| $this->_out('<</Type /Font'); |
| $this->_out('/BaseFont /' . $name); |
| if ($font['type'] == 'core') { |
| /* Standard font. */ |
| $this->_out('/Subtype /Type1'); |
| if ($name != 'Symbol' && $name != 'ZapfDingbats') { |
| $this->_out('/Encoding /WinAnsiEncoding'); |
| } |
| } else { |
| /* Additional font. */ |
| $this->_out('/Subtype /' . $font['type']); |
| $this->_out('/FirstChar 32'); |
| $this->_out('/LastChar 255'); |
| $this->_out('/Widths ' . ($this->_n + 1) . ' 0 R'); |
| $this->_out('/FontDescriptor ' . ($this->_n + 2) . ' 0 R'); |
| if ($font['enc']) { |
| if (isset($font['diff'])) { |
| $this->_out('/Encoding ' . ($nf + $font['diff']).' 0 R'); |
| } else { |
| $this->_out('/Encoding /WinAnsiEncoding'); |
| } |
| } |
| } |
| $this->_out('>>'); |
| $this->_out('endobj'); |
| if ($font['type'] != 'core') { |
| /* Widths. */ |
| $this->_newobj(); |
| $cw = &$font['cw']; |
| $s = '['; |
| for ($i = 32; $i <= 255; $i++) { |
| $s .= $cw[chr($i)] . ' '; |
| } |
| $this->_out($s . ']'); |
| $this->_out('endobj'); |
| /* Descriptor. */ |
| $this->_newobj(); |
| $s = '<</Type /FontDescriptor /FontName /' . $name; |
| foreach ($font['desc'] as $k => $v) { |
| $s .= ' /' . $k . ' ' . $v; |
| } |
| $file = $font['file']; |
| if ($file) { |
| $s .= ' /FontFile' . ($font['type'] == 'Type1' ? '' : '2') . ' ' . $this->_font_files[$file]['n'] . ' 0 R'; |
| } |
| $this->_out($s . '>>'); |
| $this->_out('endobj'); |
| } |
| } |
| } |
| function _putImages() |
| { |
| $filter = ($this->_compress) ? '/Filter /FlateDecode ' : ''; |
| foreach ($this->_images as $file => $info) { |
| $this->_newobj(); |
| $this->_images[$file]['n'] = $this->_n; |
| $this->_out('<</Type /XObject'); |
| $this->_out('/Subtype /Image'); |
| $this->_out('/Width ' . $info['w']); |
| $this->_out('/Height ' . $info['h']); |
| if ($info['cs'] == 'Indexed') { |
| $this->_out('/ColorSpace [/Indexed /DeviceRGB ' . (strlen($info['pal'])/3 - 1) . ' ' . ($this->_n + 1).' 0 R]'); |
| } else { |
| $this->_out('/ColorSpace /' . $info['cs']); |
| if ($info['cs'] == 'DeviceCMYK') { |
| $this->_out('/Decode [1 0 1 0 1 0 1 0]'); |
| } |
| } |
| $this->_out('/BitsPerComponent ' . $info['bpc']); |
| $this->_out('/Filter /' . $info['f']); |
| if (isset($info['parms'])) { |
| $this->_out($info['parms']); |
| } |
| if (isset($info['trns']) && is_array($info['trns'])) { |
| $trns = ''; |
| $i_max = count($info['trns']); |
| for ($i = 0; $i < $i_max; $i++) { |
| $trns .= $info['trns'][$i] . ' ' . $info['trns'][$i].' '; |
| } |
| $this->_out('/Mask [' . $trns . ']'); |
| } |
| $this->_out('/Length ' . strlen($info['data']) . '>>'); |
| $this->_putStream($info['data']); |
| $this->_out('endobj'); |
| /* Palette. */ |
| if ($info['cs'] == 'Indexed') { |
| $this->_newobj(); |
| $pal = ($this->_compress) ? gzcompress($info['pal']) : $info['pal']; |
| $this->_out('<<' . $filter . '/Length ' . strlen($pal) . '>>'); |
| $this->_putStream($pal); |
| $this->_out('endobj'); |
| } |
| } |
| } |
| function _putResources() |
| { |
| $this->_putFonts(); |
| $this->_putImages(); |
| /* Resource dictionary */ |
| $this->_offsets[2] = strlen($this->_buffer); |
| $this->_out('2 0 obj'); |
| $this->_out('<</ProcSet [/PDF /Text /ImageB /ImageC /ImageI]'); |
| $this->_out('/Font <<'); |
| foreach ($this->_fonts as $font) { |
| $this->_out('/F' . $font['i'] . ' ' . $font['n'] . ' 0 R'); |
| } |
| $this->_out('>>'); |
| if (count($this->_images)) { |
| $this->_out('/XObject <<'); |
| foreach ($this->_images as $image) { |
| $this->_out('/I' . $image['i'] . ' ' . $image['n'] . ' 0 R'); |
| } |
| $this->_out('>>'); |
| } |
| $this->_out('>>'); |
| $this->_out('endobj'); |
| } |
| function _putInfo() |
| { |
| $this->_out('/Producer ' . $this->_textString('Horde PDF')); |
| if (!empty($this->_info['title'])) { |
| $this->_out('/Title ' . $this->_textString($this->_info['title'])); |
| } |
| if (!empty($this->_info['subject'])) { |
| $this->_out('/Subject ' . $this->_textString($this->_info['subject'])); |
| } |
| if (!empty($this->_info['author'])) { |
| $this->_out('/Author ' . $this->_textString($this->_info['author'])); |
| } |
| if (!empty($this->keywords)) { |
| $this->_out('/Keywords ' . $this->_textString($this->keywords)); |
| } |
| if (!empty($this->creator)) { |
| $this->_out('/Creator ' . $this->_textString($this->creator)); |
| } |
| $this->_out('/CreationDate ' . $this->_textString('D:' . date('YmdHis'))); |
| } |
| function _putCatalog() |
| { |
| $this->_out('/Type /Catalog'); |
| $this->_out('/Pages 1 0 R'); |
| if ($this->_zoom_mode == 'fullpage') { |
| $this->_out('/OpenAction [3 0 R /Fit]'); |
| } elseif ($this->_zoom_mode == 'fullwidth') { |
| $this->_out('/OpenAction [3 0 R /FitH null]'); |
| } elseif ($this->_zoom_mode == 'real') { |
| $this->_out('/OpenAction [3 0 R /XYZ null null 1]'); |
| } elseif (!is_string($this->_zoom_mode)) { |
| $this->_out('/OpenAction [3 0 R /XYZ null null ' . ($this->_zoom_mode / 100).']'); |
| } |
| if ($this->_layout_mode == 'single') { |
| $this->_out('/PageLayout /SinglePage'); |
| } elseif ($this->_layout_mode == 'continuous') { |
| $this->_out('/PageLayout /OneColumn'); |
| } elseif ($this->_layout_mode == 'two') { |
| $this->_out('/PageLayout /TwoColumnLeft'); |
| } |
| } |
| function _putTrailer() |
| { |
| $this->_out('/Size ' . ($this->_n + 1)); |
| $this->_out('/Root ' . $this->_n . ' 0 R'); |
| $this->_out('/Info ' . ($this->_n - 1) . ' 0 R'); |
| } |
| function _endDoc() |
| { |
| $this->_putPages(); |
| $this->_putResources(); |
| /* Info */ |
| $this->_newobj(); |
| $this->_out('<<'); |
| $this->_putInfo(); |
| $this->_out('>>'); |
| $this->_out('endobj'); |
| /* Catalog */ |
| $this->_newobj(); |
| $this->_out('<<'); |
| $this->_putCatalog(); |
| $this->_out('>>'); |
| $this->_out('endobj'); |
| /* Cross-ref */ |
| $o = strlen($this->_buffer); |
| $this->_out('xref'); |
| $this->_out('0 ' . ($this->_n + 1)); |
| $this->_out('0000000000 65535 f '); |
| for ($i = 1; $i <= $this->_n; $i++) { |
| $this->_out(sprintf('%010d 00000 n ', $this->_offsets[$i])); |
| } |
| /* Trailer */ |
| $this->_out('trailer'); |
| $this->_out('<<'); |
| $this->_putTrailer(); |
| $this->_out('>>'); |
| $this->_out('startxref'); |
| $this->_out($o); |
| $this->_out('%%EOF'); |
| $this->_state = 3; |
| } |
| function _beginPage($orientation) |
| { |
| $this->_page++; |
| $this->_pages[$this->_page] = ''; |
| $this->_state = 2; |
| $this->x = $this->_left_margin; |
| $this->y = $this->_top_margin; |
| $this->_last_height = 0; |
| /* Page orientation */ |
| if (!$orientation) { |
| $orientation = $this->_default_orientation; |
| } else { |
| $orientation = strtoupper($orientation[0]); |
| if ($orientation != $this->_default_orientation) { |
| $this->_orientation_changes[$this->_page] = true; |
| } |
| } |
| if ($orientation != $this->_current_orientation) { |
| /* Change orientation */ |
| if ($orientation == 'P') { |
| $this->wPt = $this->fwPt; |
| $this->hPt = $this->fhPt; |
| $this->w = $this->fw; |
| $this->h = $this->fh; |
| } else { |
| $this->wPt = $this->fhPt; |
| $this->hPt = $this->fwPt; |
| $this->w = $this->fh; |
| $this->h = $this->fw; |
| } |
| $this->_page_break_trigger = $this->h - $this->_break_margin; |
| $this->_current_orientation = $orientation; |
| } |
| } |
| function _endPage() |
| { |
| /* End of page contents */ |
| $this->_state = 1; |
| } |
| function _newobj() |
| { |
| /* Begin a new object */ |
| $this->_n++; |
| $this->_offsets[$this->_n] = strlen($this->_buffer); |
| $this->_out($this->_n . ' 0 obj'); |
| } |
| function _doUnderline($x, $y, $text) |
| { |
| /* Set the rectangle width according to text width. */ |
| $width = $this->getStringWidth($text, true); |
| /* Set rectangle position and height, using underline position and |
| * thickness settings scaled by the font size. */ |
| $y = $y + ($this->_current_font['up'] * $this->_font_size_pt / 1000); |
| $height = -$this->_current_font['ut'] * $this->_font_size_pt / 1000; |
| return sprintf('%.2f %.2f %.2f %.2f re f', $x, $y, $width, $height); |
| } |
| function _parseJPG($file) |
| { |
| /* Extract info from a JPEG file. */ |
| $img = @getimagesize($file); |
| if (!$img) { |
| return $this->raiseError(sprintf('Missing or incorrect image file: %s', $file)); |
| } |
| if ($img[2] != 2) { |
| return $this->raiseError(sprintf('Not a JPEG file: %s', $file)); |
| } |
| if (!isset($img['channels']) || $img['channels'] == 3) { |
| $colspace = 'DeviceRGB'; |
| } elseif ($img['channels'] == 4) { |
| $colspace = 'DeviceCMYK'; |
| } else { |
| $colspace = 'DeviceGray'; |
| } |
| $bpc = isset($img['bits']) ? $img['bits'] : 8; |
| /* Read whole file. */ |
| $f = fopen($file, 'rb'); |
| $data = fread($f, filesize($file)); |
| fclose($f); |
| return array('w' => $img[0], 'h' => $img[1], 'cs' => $colspace, 'bpc' => $bpc, 'f' => 'DCTDecode', 'data' => $data); |
| } |
| function _parsePNG($file) |
| { |
| /* Extract info from a PNG file. */ |
| $f = fopen($file, 'rb'); |
| if (!$f) { |
| return $this->raiseError(sprintf('Unable to open image file: %s', $file)); |
| } |
| /* Check signature. */ |
| if (fread($f, 8) != chr(137) . 'PNG' . chr(13) . chr(10) . chr(26) . chr(10)) { |
| return $this->raiseError(sprintf('Not a PNG file: %s', $file)); |
| } |
| /* Read header chunk. */ |
| fread($f, 4); |
| if (fread($f, 4) != 'IHDR') { |
| return $this->raiseError(sprintf('Incorrect PNG file: %s', $file)); |
| } |
| $width = $this->_freadInt($f); |
| $height = $this->_freadInt($f); |
| $bpc = ord(fread($f, 1)); |
| if ($bpc > 8) { |
| return $this->raiseError(sprintf('16-bit depth not supported: %s', $file)); |
| } |
| $ct = ord(fread($f, 1)); |
| if ($ct == 0) { |
| $colspace = 'DeviceGray'; |
| } elseif ($ct == 2) { |
| $colspace = 'DeviceRGB'; |
| } elseif ($ct == 3) { |
| $colspace = 'Indexed'; |
| } else { |
| return $this->raiseError(sprintf('Alpha channel not supported: %s', $file)); |
| } |
| if (ord(fread($f, 1)) != 0) { |
| return $this->raiseError(sprintf('Unknown compression method: %s', $file)); |
| } |
| if (ord(fread($f, 1)) != 0) { |
| return $this->raiseError(sprintf('Unknown filter method: %s', $file)); |
| } |
| if (ord(fread($f, 1)) != 0) { |
| return $this->raiseError(sprintf('Interlacing not supported: %s', $file)); |
| } |
| fread($f, 4); |
| $parms = '/DecodeParms <</Predictor 15 /Colors ' . ($ct == 2 ? 3 : 1).' /BitsPerComponent ' . $bpc . ' /Columns ' . $width.'>>'; |
| /* Scan chunks looking for palette, transparency and image data. */ |
| $pal = ''; |
| $trns = ''; |
| $data = ''; |
| do { |
| $n = $this->_freadInt($f); |
| $type = fread($f, 4); |
| if ($type == 'PLTE') { |
| /* Read palette */ |
| $pal = fread($f, $n); |
| fread($f, 4); |
| } elseif ($type == 'tRNS') { |
| /* Read transparency info */ |
| $t = fread($f, $n); |
| if ($ct == 0) { |
| $trns = array(ord(substr($t, 1, 1))); |
| } elseif ($ct == 2) { |
| $trns = array(ord(substr($t, 1, 1)), ord(substr($t, 3, 1)), ord(substr($t, 5, 1))); |
| } else { |
| $pos = strpos($t, chr(0)); |
| if (is_int($pos)) { |
| $trns = array($pos); |
| } |
| } |
| fread($f, 4); |
| } elseif ($type == 'IDAT') { |
| /* Read image data block */ |
| $data .= fread($f, $n); |
| fread($f, 4); |
| } elseif ($type == 'IEND') { |
| break; |
| } else { |
| fread($f, $n + 4); |
| } |
| } while ($n); |
| if ($colspace == 'Indexed' && empty($pal)) { |
| return $this->raiseError(sprintf('Missing palette in: %s', $file)); |
| } |
| fclose($f); |
| return array('w' => $width, 'h' => $height, 'cs' => $colspace, 'bpc' => $bpc, 'f' => 'FlateDecode', 'parms' => $parms, 'pal' => $pal, 'trns' => $trns, 'data' => $data); |
| } |
| function _freadInt($f) |
| { |
| /* Read a 4-byte integer from file. */ |
| $i = ord(fread($f, 1)) << 24; |
| $i += ord(fread($f, 1)) << 16; |
| $i += ord(fread($f, 1)) << 8; |
| $i += ord(fread($f, 1)); |
| return $i; |
| } |
| function _textString($s) |
| { |
| /* Format a text string */ |
| return '(' . $this->_escape($s) . ')'; |
| } |
| function _escape($s) |
| { |
| /* Add \ before \, ( and ) */ |
| return str_replace(array(')','(','\\'), |
| array('\\)','\\(','\\\\'), |
| $s); |
| } |
| function _putStream($s) |
| { |
| $this->_out('stream'); |
| $this->_out($s); |
| $this->_out('endstream'); |
| } |
| function _out($s) |
| { |
| /* Add a line to the document. */ |
| if ($this->_state == 2) { |
| $this->_pages[$this->_page] .= $s . "\n"; |
| } else { |
| $this->_buffer .= $s . "\n"; |
| } |
| } |
| } |
| /trunk/applications/jrest/lib/SpreadsheetProductor.php |
|---|
| New file |
| 0,0 → 1,15 |
| <?php |
| Class SpreadsheetProductor { |
| function initSpreadsheet() { |
| require_once("Spreadsheet/Excel/Writer.php"); |
| } |
| } |
| ?> |
| /trunk/applications/jrest/lib/PDFProductor.php |
|---|
| New file |
| 0,0 → 1,14 |
| <?php |
| Class PDFProductor { |
| function initPDF() { |
| require_once("PDF.php"); |
| } |
| } |
| ?> |
| /trunk/applications/jrest/lib/Writer.php |
|---|
| New file |
| 0,0 → 1,104 |
| <?php |
| /* |
| * Module written/ported by Xavier Noguer <xnoguer@rezebra.com> |
| * |
| * PERL Spreadsheet::WriteExcel module. |
| * |
| * The author of the Spreadsheet::WriteExcel module is John McNamara |
| * <jmcnamara@cpan.org> |
| * |
| * I _DO_ maintain this code, and John McNamara has nothing to do with the |
| * porting of this code to PHP. Any questions directly related to this |
| * class library should be directed to me. |
| * |
| * License Information: |
| * |
| * Spreadsheet_Excel_Writer: A library for generating Excel Spreadsheets |
| * Copyright (c) 2002-2003 Xavier Noguer xnoguer@rezebra.com |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| */ |
| require_once 'PEAR.php'; |
| require_once 'Spreadsheet/Excel/Writer/Workbook.php'; |
| /** |
| * Class for writing Excel Spreadsheets. This class should change COMPLETELY. |
| * |
| * @author Xavier Noguer <xnoguer@rezebra.com> |
| * @category FileFormats |
| * @package Spreadsheet_Excel_Writer |
| */ |
| class Spreadsheet_Excel_Writer extends Spreadsheet_Excel_Writer_Workbook |
| { |
| /** |
| * The constructor. It just creates a Workbook |
| * |
| * @param string $filename The optional filename for the Workbook. |
| * @return Spreadsheet_Excel_Writer_Workbook The Workbook created |
| */ |
| function Spreadsheet_Excel_Writer($filename = '') |
| { |
| $this->_filename = $filename; |
| $this->Spreadsheet_Excel_Writer_Workbook($filename); |
| } |
| /** |
| * Send HTTP headers for the Excel file. |
| * |
| * @param string $filename The filename to use for HTTP headers |
| * @access public |
| */ |
| function send($filename) |
| { |
| header("Content-type: application/vnd.ms-excel"); |
| header("Content-Disposition: attachment; filename=\"$filename\""); |
| header("Expires: 0"); |
| header("Cache-Control: must-revalidate, post-check=0,pre-check=0"); |
| header("Pragma: public"); |
| } |
| /** |
| * Utility function for writing formulas |
| * Converts a cell's coordinates to the A1 format. |
| * |
| * @access public |
| * @static |
| * @param integer $row Row for the cell to convert (0-indexed). |
| * @param integer $col Column for the cell to convert (0-indexed). |
| * @return string The cell identifier in A1 format |
| */ |
| function rowcolToCell($row, $col) |
| { |
| if ($col > 255) { //maximum column value exceeded |
| return new PEAR_Error("Maximum column value exceeded: $col"); |
| } |
| $int = (int)($col / 26); |
| $frac = $col % 26; |
| $chr1 = ''; |
| if ($int > 0) { |
| $chr1 = chr(ord('A') + $int - 1); |
| } |
| $chr2 = chr(ord('A') + $frac); |
| $row++; |
| return $chr1 . $chr2 . $row; |
| } |
| } |
| ?> |
| /trunk/applications/jrest/lib/WdHTMLParser.php |
|---|
| New file |
| 0,0 → 1,144 |
| <?php |
| /** |
| * |
| * @author Olivier Laviale |
| * @see http://www.weirdog.com/blog/php/un-parser-html-des-plus-leger.html |
| * |
| */ |
| class WdHTMLParser { |
| private $encoding; |
| private $matches; |
| private $escaped; |
| private $opened = array(); |
| public $malformed; |
| public function parse($html, $namespace=NULL, $encoding='utf-8') { |
| $this->malformed = false; |
| $this->encoding = $encoding; |
| // we take care of escaping comments and processing options. they will not be parsed |
| // and will end as text nodes |
| $html = $this->escapeSpecials($html); |
| // in order to create a tree, we first need to split the HTML using the markups, |
| // creating a nice flat array of texts and opening and closing markups. |
| // |
| // the array can be read as follows : |
| // |
| // i+0 => some text |
| // i+1 => '/' for closing markups, nothing otherwise |
| // i+2 => the markup it self, without the '<' '>' |
| // |
| // note that i+2 might end with a '/' indicating an auto-closing markup |
| $this->matches = preg_split('#<(/?)' . $namespace . '([^>]*)>#', $html, -1, PREG_SPLIT_DELIM_CAPTURE); |
| // the flat representation is now ready, we can create our tree |
| $tree = $this->buildTree(); |
| // if comments or processing options where escaped, we can |
| // safely unescape them now |
| if ($this->escaped) { |
| $tree = $this->unescapeSpecials($tree); |
| } |
| return $tree; |
| } |
| private function escapeSpecials($html) { |
| // here we escape comments |
| $html = preg_replace_callback('#<\!--.+-->#sU', array($this, 'escapeSpecials_callback'), $html); |
| // and processing options |
| $html = preg_replace_callback('#<\?.+\?>#sU', array($this, 'escapeSpecials_callback'), $html); |
| return $html; |
| } |
| private function escapeSpecials_callback($m) { |
| $this->escaped = true; |
| $text = $m[0]; |
| $text = str_replace(array('<', '>'), array("\x01", "\x02"), $text); |
| return $text; |
| } |
| private function unescapeSpecials($tree) { |
| return is_array($tree) ? array_map(array($this, 'unescapeSpecials'), $tree) : str_replace(array("\x01", "\x02"), array('<', '>'), $tree); |
| } |
| private function buildTree() { |
| $nodes = array(); |
| $i = 0; |
| $text = NULL; |
| while (($value = array_shift($this->matches)) !== NULL) { |
| switch ($i++ % 3) { |
| case 0: |
| // if the trimed value is not empty we preserve the value, |
| // otherwise we discard it. |
| if (trim($value)){ |
| $nodes[] = $value; |
| } |
| break; |
| case 1: |
| $closing = ($value == '/'); |
| break; |
| case 2: |
| if (substr($value, -1, 1) == '/') { |
| // auto closing |
| $nodes[] = $this->parseMarkup(substr($value, 0, -1)); |
| } else if ($closing) { |
| // closing markup |
| $open = array_pop($this->opened); |
| if ($value != $open) { |
| $this->error($value, $open); |
| } |
| return $nodes; |
| } else { |
| // this is an open markup with possible children |
| $node = $this->parseMarkup($value); |
| // push the markup name into the opened markups |
| $this->opened[] = $node['name']; |
| // create the node and parse its children |
| $node['children'] = $this->buildTree($this->matches); |
| $nodes[] = $node; |
| } |
| break; |
| } |
| } |
| return $nodes; |
| } |
| public function parseMarkup($markup) { |
| // get markup's name |
| preg_match('#^[^\s]+#', $markup, $matches); |
| $name = $matches[0]; |
| // get markup's arguments |
| preg_match_all('#\s+([^=]+)\s*=\s*"([^"]+)"#', $markup, $matches, PREG_SET_ORDER); |
| // transform the matches into a nice key/value array |
| $args = array(); |
| foreach ($matches as $m) { |
| // we unescape the html entities of the argument's value |
| $args[$m[1]] = html_entity_decode($m[2], ENT_QUOTES, $this->encoding); |
| } |
| return array('name' => $name, 'args' => $args); |
| } |
| public function error($markup, $expected) { |
| $this->malformed = true; |
| printf('unexpected closing markup "%s", should be "%s"', $markup, $expected); |
| } |
| } |
| ?> |
| /trunk/applications/jrest/lib/Log.php |
|---|
| New file |
| 0,0 → 1,195 |
| <?php |
| //declare(encoding='UTF-8'); |
| /** |
| * Classe permettant de logger des messages dans les fichier situés dans le dossier de log |
| * |
| * PHP Version 5 |
| * |
| * @category PHP |
| * @package Framework |
| * @author aurelien <aurelien@tela-botanica.org> |
| * @copyright 2009 Tela-Botanica |
| * @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL |
| * @version SVN: <svn_id> |
| * @link /doc/framework/ |
| */ |
| class Log { |
| /** |
| * Tableau associatif stockant les descripteurs de fichiers |
| */ |
| private static $fichiersLog = array(); |
| /** |
| * Chemin de base du dossier log de l'application |
| */ |
| private static $cheminLogs = ''; |
| /** |
| * Booleen indiquant si l'on peut correctement écrire dans les fichiers de logs |
| */ |
| private static $droitLogger = true; |
| /** |
| * Zone horaire (pour éviter des avertissements dans les dates) |
| */ |
| private static $timeZone = ''; |
| /** |
| * Taille maximum d'un fichier de log avant que celui ne soit archivé (en octets) |
| */ |
| private static $tailleMax = 10000; |
| /** |
| * séparateur de chemin |
| */ |
| private static $sd = DIRECTORY_SEPARATOR; |
| /** |
| * Extension des fichiers de log |
| */ |
| private static $ext = '.log'; |
| /** |
| * La classe registre se contient elle-même, (pour le pattern singleton) |
| */ |
| private static $log; |
| /** |
| * Constructeur par défaut, privé, car on accède à la classe par le getInstance |
| */ |
| private function __construct() { |
| self::$sd = $sd; |
| // gestion de la timezone pour éviter des erreurs |
| if(function_exists("date_default_timezone_set") and function_exists("date_default_timezone_get")) { |
| date_default_timezone_set(self::$timeZone); |
| } |
| if(!is_dir(self::$cheminLogs) || !is_writable(self::$cheminLogs)) { |
| self::desactiverEcriture(); |
| } |
| } |
| public static function setCheminLog($nouveauCheminLogs) { |
| self::$cheminLogs = $nouveauCheminLogs; |
| } |
| public static function getCheminLog() { |
| return self::$cheminLogs; |
| } |
| public static function setTimeZone($NouvelleTimeZone) { |
| self::$timeZone = $NouvelleTimeZone; |
| } |
| public static function setTailleMax($nouvelleTailleMax) { |
| self::$tailleMax = $nouvelleTailleMax; |
| } |
| /** |
| * Fonction qui renvoie l'instance de classe en assurant son unicité, c'est l'unique méthode qui doit être |
| * utilisée pour récupérer l'objet Registre |
| * @return Log le gestionnaire de log en cours |
| */ |
| public static function getInstance() { |
| if (self::$log instanceof Log) { |
| return self::$log; |
| } |
| self::$log = new Log(); |
| return self::$log; |
| } |
| /** |
| * Ajoute une entrée au log spécifié par le paramètre $nomFichier |
| * @param string $nomFichier le nom du fichier dans lequel écrire |
| */ |
| public static function ajouterEntree($nomFichier,$entree,$mode='a+') { |
| if(self::$droitLogger) { |
| $date = "\n"."\n".date('d m Y H:i')."\n" ; |
| // si le fichier est déjà dans le tableau et qu'on peut y écrire |
| if(self::verifierOuvrirFichier($nomFichier,$mode)) { |
| // on y écrit le message de log |
| fwrite(self::$fichiersLog[$nomFichier],$date.$entree); |
| // on vérifie si le fichier ne dépasse pas la taille maximale |
| self::verifierTailleFichierOuArchiver($nomFichier); |
| } else { |
| // sinon on interdit l'écriture |
| self::desactiverEcriture($nomFichier); |
| } |
| } |
| } |
| /** |
| * Vide un fichier log indiqué |
| * @param string $nomFichier le nom du fichier à vider |
| */ |
| public static function viderLog($nomFichier) { |
| ajouterEntree($nomFichier,'','w'); |
| } |
| /** |
| * Vérifie la présence d'un fichier dans le tableau, ses droits d'écriture, |
| * l'ouvre si nécessaire |
| * @param string $nomFichier le nom du fichier dont on doit vérifier la présence |
| * @return boolean true si le fichier est ouvert ou maintenant accessible, false sinon |
| */ |
| public static function verifierOuvrirFichier($nomFichier,$mode) { |
| // le fichier est il déjà ouvert ? |
| if(in_array($nomFichier,self::$fichiersLog)) { |
| // si oui peut on y écrire ? |
| if(is_writable(self::$cheminLogs.$nomFichier.self::$ext)) { |
| // si oui on renvoie le descripteur |
| return true; |
| } |
| return false; |
| } else { |
| // sinon on l'ouvre |
| $fp = @fopen(self::$cheminLogs.$nomFichier.self::$ext,$mode); |
| // si l'ouverture a réussi et si le fichier a les droits d'écriture |
| if($fp && is_writable(self::$cheminLogs.$nomFichier.self::$ext)) { |
| // si oui on renvoie le descripteur qu'on ajoute au tableau |
| self::$fichiersLog[$nomFichier] = $fp; |
| return true; |
| } |
| return false; |
| } |
| } |
| /** |
| * Vérifie la taille d'un fichier donné et si celle ci est trop importante |
| * archive le fichier de log |
| * @param string $nomFichier nom du fichier à vérifier |
| */ |
| private static function verifierTailleFichierOuArchiver($nomFichier) { |
| if(filesize(self::$cheminLogs.$nomFichier.self::$ext) > self::$tailleMax) { |
| rename(self::$cheminLogs.$nomFichier.self::$ext,self::$cheminLogs.$nomFichier.date('d_m_Y_H:i').self::$ext); |
| self::ajouterEntree($nomFichier,''); |
| } |
| } |
| /** |
| * Désactive l'écriture du log et envoie un message au gestionnaire d'erreurs |
| * @param string $nomFichier le nom du fichier qui a causé l'erreur |
| */ |
| private static function desactiverEcriture($nomFichier = '') { |
| self::$droitLogger = false; |
| if($nomFichier != '') { |
| $fichierDossier = 'fichier '.$nomFichier ; |
| } else { |
| $fichierDossier = 'dossier des logs'; |
| } |
| } |
| /** |
| * destructeur de classe, ferme les descripteurs ouverts |
| */ |
| public function __destruct() { |
| foreach(self::$fichiersLog as $nomFichier => $fp) { |
| fclose($fp); |
| } |
| } |
| } |
| ?> |
| /trunk/applications/jrest/lib/Spreadsheet/Excel/Writer/Workbook.php |
|---|
| New file |
| 0,0 → 1,1042 |
| <?php |
| /* |
| * Module written/ported by Xavier Noguer <xnoguer@rezebra.com> |
| * |
| * The majority of this is _NOT_ my code. I simply ported it from the |
| * PERL Spreadsheet::WriteExcel module. |
| * |
| * The author of the Spreadsheet::WriteExcel module is John McNamara |
| * <jmcnamara@cpan.org> |
| * |
| * I _DO_ maintain this code, and John McNamara has nothing to do with the |
| * porting of this code to PHP. Any questions directly related to this |
| * class library should be directed to me. |
| * |
| * License Information: |
| * |
| * Spreadsheet_Excel_Writer: A library for generating Excel Spreadsheets |
| * Copyright (c) 2002-2003 Xavier Noguer xnoguer@rezebra.com |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| */ |
| require_once('Format.php'); |
| require_once('OLEwriter.php'); |
| require_once('BIFFwriter.php'); |
| require_once('Worksheet.php'); |
| require_once('Parser.php'); |
| /** |
| * Class for generating Excel Spreadsheets |
| * |
| * @author Xavier Noguer <xnoguer@rezebra.com> |
| * @category FileFormats |
| * @package Spreadsheet_Excel_Writer |
| */ |
| class Spreadsheet_Excel_Writer_Workbook extends Spreadsheet_Excel_Writer_BIFFwriter |
| { |
| /** |
| * Filename for the Workbook |
| * @var string |
| */ |
| var $_filename; |
| /** |
| * Formula parser |
| * @var object Parser |
| */ |
| var $_parser; |
| /** |
| * Flag for 1904 date system |
| * @var integer |
| */ |
| var $_1904; |
| /** |
| * The active worksheet of the workbook (0 indexed) |
| * @var integer |
| */ |
| var $_activesheet; |
| /** |
| * 1st displayed worksheet in the workbook (0 indexed) |
| * @var integer |
| */ |
| var $_firstsheet; |
| /** |
| * Number of workbook tabs selected |
| * @var integer |
| */ |
| var $_selected; |
| /** |
| * Index for creating adding new formats to the workbook |
| * @var integer |
| */ |
| var $_xf_index; |
| /** |
| * Flag for preventing close from being called twice. |
| * @var integer |
| * @see close() |
| */ |
| var $_fileclosed; |
| /** |
| * The BIFF file size for the workbook. |
| * @var integer |
| * @see _calcSheetOffsets() |
| */ |
| var $_biffsize; |
| /** |
| * The default sheetname for all sheets created. |
| * @var string |
| */ |
| var $_sheetname; |
| /** |
| * The default XF format. |
| * @var object Format |
| */ |
| var $_tmp_format; |
| /** |
| * Array containing references to all of this workbook's worksheets |
| * @var array |
| */ |
| var $_worksheets; |
| /** |
| * Array of sheetnames for creating the EXTERNSHEET records |
| * @var array |
| */ |
| var $_sheetnames; |
| /** |
| * Array containing references to all of this workbook's formats |
| * @var array |
| */ |
| var $_formats; |
| /** |
| * Array containing the colour palette |
| * @var array |
| */ |
| var $_palette; |
| /** |
| * The default format for URLs. |
| * @var object Format |
| */ |
| var $_url_format; |
| /** |
| * Class constructor |
| * |
| * @param string filename for storing the workbook. "-" for writing to stdout. |
| * @access public |
| */ |
| function Spreadsheet_Excel_Writer_Workbook($filename) |
| { |
| // It needs to call its parent's constructor explicitly |
| $this->Spreadsheet_Excel_Writer_BIFFwriter(); |
| $this->_filename = $filename; |
| $this->_parser =& new Spreadsheet_Excel_Writer_Parser($this->_byte_order); |
| $this->_1904 = 0; |
| $this->_activesheet = 0; |
| $this->_firstsheet = 0; |
| $this->_selected = 0; |
| $this->_xf_index = 16; // 15 style XF's and 1 cell XF. |
| $this->_fileclosed = 0; |
| $this->_biffsize = 0; |
| $this->_sheetname = "Sheet"; |
| $this->_tmp_format =& new Spreadsheet_Excel_Writer_Format(); |
| $this->_worksheets = array(); |
| $this->_sheetnames = array(); |
| $this->_formats = array(); |
| $this->_palette = array(); |
| // Add the default format for hyperlinks |
| $this->_url_format =& $this->addFormat(array('color' => 'blue', 'underline' => 1)); |
| $this->_setPaletteXl97(); |
| } |
| /** |
| * Calls finalization methods. |
| * This method should always be the last one to be called on every workbook |
| * |
| * @access public |
| */ |
| function close() |
| { |
| if ($this->_fileclosed) { // Prevent close() from being called twice. |
| return; |
| } |
| $this->_storeWorkbook(); |
| $this->_fileclosed = 1; |
| } |
| /** |
| * An accessor for the _worksheets[] array |
| * Returns an array of the worksheet objects in a workbook |
| * It actually calls to worksheets() |
| * |
| * @access public |
| * @see worksheets() |
| * @return array |
| */ |
| function sheets() |
| { |
| return $this->worksheets(); |
| } |
| /** |
| * An accessor for the _worksheets[] array. |
| * Returns an array of the worksheet objects in a workbook |
| * |
| * @access public |
| * @return array |
| */ |
| function worksheets() |
| { |
| return($this->_worksheets); |
| } |
| /** |
| * Add a new worksheet to the Excel workbook. |
| * If no name is given the name of the worksheet will be Sheeti$i, with |
| * $i in [1..]. |
| * |
| * @access public |
| * @param string $name the optional name of the worksheet |
| * @return &Spreadsheet_Excel_Writer_Worksheet reference to a worksheet object |
| */ |
| function &addWorksheet($name = '') |
| { |
| $index = count($this->_worksheets); |
| $sheetname = $this->_sheetname; |
| if($name == '') { |
| $name = $sheetname.($index+1); |
| } |
| // Check that sheetname is <= 31 chars (Excel limit). |
| if(strlen($name) > 31) { |
| $this->raiseError("Sheetname $name must be <= 31 chars"); |
| } |
| // Check that the worksheet name doesn't already exist: a fatal Excel error. |
| for($i=0; $i < count($this->_worksheets); $i++) |
| { |
| if($name == $this->_worksheets[$i]->getName()) { |
| $this->raiseError("Worksheet '$name' already exists"); |
| } |
| } |
| $worksheet = new Spreadsheet_Excel_Writer_Worksheet($name,$index,$this->_activesheet, |
| $this->_firstsheet,$this->_url_format, |
| $this->_parser); |
| $this->_worksheets[$index] = &$worksheet; // Store ref for iterator |
| $this->_sheetnames[$index] = $name; // Store EXTERNSHEET names |
| $this->_parser->setExtSheet($name, $index); // Register worksheet name with parser |
| return($worksheet); |
| } |
| /** |
| * Add a new format to the Excel workbook. |
| * Also, pass any properties to the Format constructor. |
| * |
| * @access public |
| * @param array $properties array with properties for initializing the format. |
| * @return &Spreadsheet_Excel_Writer_Format reference to an Excel Format |
| */ |
| function &addFormat($properties = array()) |
| { |
| $format = new Spreadsheet_Excel_Writer_Format($this->_xf_index,$properties); |
| $this->_xf_index += 1; |
| $this->_formats[] = &$format; |
| return($format); |
| } |
| /** |
| * Change the RGB components of the elements in the colour palette. |
| * |
| * @access public |
| * @param integer $index colour index |
| * @param integer $red red RGB value [0-255] |
| * @param integer $green green RGB value [0-255] |
| * @param integer $blue blue RGB value [0-255] |
| * @return integer The palette index for the custom color |
| */ |
| function setCustomColor($index,$red,$green,$blue) |
| { |
| // Match a HTML #xxyyzz style parameter |
| /*if (defined $_[1] and $_[1] =~ /^#(\w\w)(\w\w)(\w\w)/ ) { |
| @_ = ($_[0], hex $1, hex $2, hex $3); |
| }*/ |
| // Check that the colour index is the right range |
| if ($index < 8 or $index > 64) { |
| // TODO: assign real error codes |
| $this->raiseError("Color index $index outside range: 8 <= index <= 64",0,PEAR_ERROR_DIE); |
| } |
| // Check that the colour components are in the right range |
| if ( ($red < 0 or $red > 255) or |
| ($green < 0 or $green > 255) or |
| ($blue < 0 or $blue > 255) ) |
| { |
| $this->raiseError("Color component outside range: 0 <= color <= 255"); |
| } |
| $index -= 8; // Adjust colour index (wingless dragonfly) |
| // Set the RGB value |
| $this->_palette[$index] = array($red, $green, $blue, 0); |
| return($index + 8); |
| } |
| /** |
| * Sets the colour palette to the Excel 97+ default. |
| * |
| * @access private |
| */ |
| function _setPaletteXl97() |
| { |
| $this->_palette = array( |
| array(0x00, 0x00, 0x00, 0x00), // 8 |
| array(0xff, 0xff, 0xff, 0x00), // 9 |
| array(0xff, 0x00, 0x00, 0x00), // 10 |
| array(0x00, 0xff, 0x00, 0x00), // 11 |
| array(0x00, 0x00, 0xff, 0x00), // 12 |
| array(0xff, 0xff, 0x00, 0x00), // 13 |
| array(0xff, 0x00, 0xff, 0x00), // 14 |
| array(0x00, 0xff, 0xff, 0x00), // 15 |
| array(0x80, 0x00, 0x00, 0x00), // 16 |
| array(0x00, 0x80, 0x00, 0x00), // 17 |
| array(0x00, 0x00, 0x80, 0x00), // 18 |
| array(0x80, 0x80, 0x00, 0x00), // 19 |
| array(0x80, 0x00, 0x80, 0x00), // 20 |
| array(0x00, 0x80, 0x80, 0x00), // 21 |
| array(0xc0, 0xc0, 0xc0, 0x00), // 22 |
| array(0x80, 0x80, 0x80, 0x00), // 23 |
| array(0x99, 0x99, 0xff, 0x00), // 24 |
| array(0x99, 0x33, 0x66, 0x00), // 25 |
| array(0xff, 0xff, 0xcc, 0x00), // 26 |
| array(0xcc, 0xff, 0xff, 0x00), // 27 |
| array(0x66, 0x00, 0x66, 0x00), // 28 |
| array(0xff, 0x80, 0x80, 0x00), // 29 |
| array(0x00, 0x66, 0xcc, 0x00), // 30 |
| array(0xcc, 0xcc, 0xff, 0x00), // 31 |
| array(0x00, 0x00, 0x80, 0x00), // 32 |
| array(0xff, 0x00, 0xff, 0x00), // 33 |
| array(0xff, 0xff, 0x00, 0x00), // 34 |
| array(0x00, 0xff, 0xff, 0x00), // 35 |
| array(0x80, 0x00, 0x80, 0x00), // 36 |
| array(0x80, 0x00, 0x00, 0x00), // 37 |
| array(0x00, 0x80, 0x80, 0x00), // 38 |
| array(0x00, 0x00, 0xff, 0x00), // 39 |
| array(0x00, 0xcc, 0xff, 0x00), // 40 |
| array(0xcc, 0xff, 0xff, 0x00), // 41 |
| array(0xcc, 0xff, 0xcc, 0x00), // 42 |
| array(0xff, 0xff, 0x99, 0x00), // 43 |
| array(0x99, 0xcc, 0xff, 0x00), // 44 |
| array(0xff, 0x99, 0xcc, 0x00), // 45 |
| array(0xcc, 0x99, 0xff, 0x00), // 46 |
| array(0xff, 0xcc, 0x99, 0x00), // 47 |
| array(0x33, 0x66, 0xff, 0x00), // 48 |
| array(0x33, 0xcc, 0xcc, 0x00), // 49 |
| array(0x99, 0xcc, 0x00, 0x00), // 50 |
| array(0xff, 0xcc, 0x00, 0x00), // 51 |
| array(0xff, 0x99, 0x00, 0x00), // 52 |
| array(0xff, 0x66, 0x00, 0x00), // 53 |
| array(0x66, 0x66, 0x99, 0x00), // 54 |
| array(0x96, 0x96, 0x96, 0x00), // 55 |
| array(0x00, 0x33, 0x66, 0x00), // 56 |
| array(0x33, 0x99, 0x66, 0x00), // 57 |
| array(0x00, 0x33, 0x00, 0x00), // 58 |
| array(0x33, 0x33, 0x00, 0x00), // 59 |
| array(0x99, 0x33, 0x00, 0x00), // 60 |
| array(0x99, 0x33, 0x66, 0x00), // 61 |
| array(0x33, 0x33, 0x99, 0x00), // 62 |
| array(0x33, 0x33, 0x33, 0x00), // 63 |
| ); |
| } |
| /** |
| * Assemble worksheets into a workbook and send the BIFF data to an OLE |
| * storage. |
| * |
| * @access private |
| */ |
| function _storeWorkbook() |
| { |
| // Ensure that at least one worksheet has been selected. |
| if ($this->_activesheet == 0) |
| { |
| $this->_worksheets[0]->selected = 1; |
| } |
| // Calculate the number of selected worksheet tabs and call the finalization |
| // methods for each worksheet |
| for($i=0; $i < count($this->_worksheets); $i++) |
| { |
| if($this->_worksheets[$i]->selected) { |
| $this->_selected++; |
| } |
| $this->_worksheets[$i]->close($this->_sheetnames); |
| } |
| // Add Workbook globals |
| $this->_storeBof(0x0005); |
| $this->_storeExterns(); // For print area and repeat rows |
| $this->_storeNames(); // For print area and repeat rows |
| $this->_storeWindow1(); |
| $this->_store1904(); |
| $this->_storeAllFonts(); |
| $this->_storeAllNumFormats(); |
| $this->_storeAllXfs(); |
| $this->_storeAllStyles(); |
| $this->_storePalette(); |
| $this->_calcSheetOffsets(); |
| // Add BOUNDSHEET records |
| for($i=0; $i < count($this->_worksheets); $i++) { |
| $this->_storeBoundsheet($this->_worksheets[$i]->name,$this->_worksheets[$i]->offset); |
| } |
| // End Workbook globals |
| $this->_storeEof(); |
| // Store the workbook in an OLE container |
| $this->_storeOLEFile(); |
| } |
| /** |
| * Store the workbook in an OLE container if the total size of the workbook data |
| * is less than ~ 7MB. |
| * |
| * @access private |
| */ |
| function _storeOLEFile() |
| { |
| $OLE = new Spreadsheet_Excel_Writer_OLEwriter($this->_filename); |
| $this->_tmp_filename = $OLE->_tmp_filename; |
| // Write Worksheet data if data <~ 7MB |
| if ($OLE->setSize($this->_biffsize)) |
| { |
| $OLE->writeHeader(); |
| $OLE->write($this->_data); |
| foreach($this->_worksheets as $sheet) |
| { |
| while ($tmp = $sheet->getData()) { |
| $OLE->write($tmp); |
| } |
| } |
| } |
| $OLE->close(); |
| } |
| /** |
| * Calculate offsets for Worksheet BOF records. |
| * |
| * @access private |
| */ |
| function _calcSheetOffsets() |
| { |
| $BOF = 11; |
| $EOF = 4; |
| $offset = $this->_datasize; |
| for($i=0; $i < count($this->_worksheets); $i++) { |
| $offset += $BOF + strlen($this->_worksheets[$i]->name); |
| } |
| $offset += $EOF; |
| for($i=0; $i < count($this->_worksheets); $i++) { |
| $this->_worksheets[$i]->offset = $offset; |
| $offset += $this->_worksheets[$i]->_datasize; |
| } |
| $this->_biffsize = $offset; |
| } |
| /** |
| * Store the Excel FONT records. |
| * |
| * @access private |
| */ |
| function _storeAllFonts() |
| { |
| // tmp_format is added by the constructor. We use this to write the default XF's |
| $format = $this->_tmp_format; |
| $font = $format->getFont(); |
| // Note: Fonts are 0-indexed. According to the SDK there is no index 4, |
| // so the following fonts are 0, 1, 2, 3, 5 |
| // |
| for($i=1; $i <= 5; $i++){ |
| $this->_append($font); |
| } |
| // Iterate through the XF objects and write a FONT record if it isn't the |
| // same as the default FONT and if it hasn't already been used. |
| // |
| $fonts = array(); |
| $index = 6; // The first user defined FONT |
| $key = $format->getFontKey(); // The default font from _tmp_format |
| $fonts[$key] = 0; // Index of the default font |
| for($i=0; $i < count($this->_formats); $i++) { |
| $key = $this->_formats[$i]->getFontKey(); |
| if (isset($fonts[$key])) { |
| // FONT has already been used |
| $this->_formats[$i]->font_index = $fonts[$key]; |
| } |
| else { |
| // Add a new FONT record |
| $fonts[$key] = $index; |
| $this->_formats[$i]->font_index = $index; |
| $index++; |
| $font = $this->_formats[$i]->getFont(); |
| $this->_append($font); |
| } |
| } |
| } |
| /** |
| * Store user defined numerical formats i.e. FORMAT records |
| * |
| * @access private |
| */ |
| function _storeAllNumFormats() |
| { |
| // Leaning num_format syndrome |
| $hash_num_formats = array(); |
| $num_formats = array(); |
| $index = 164; |
| // Iterate through the XF objects and write a FORMAT record if it isn't a |
| // built-in format type and if the FORMAT string hasn't already been used. |
| // |
| for($i=0; $i < count($this->_formats); $i++) |
| { |
| $num_format = $this->_formats[$i]->_num_format; |
| // Check if $num_format is an index to a built-in format. |
| // Also check for a string of zeros, which is a valid format string |
| // but would evaluate to zero. |
| // |
| if (!preg_match("/^0+\d/",$num_format)) |
| { |
| if (preg_match("/^\d+$/",$num_format)) { // built-in format |
| continue; |
| } |
| } |
| if (isset($hash_num_formats[$num_format])) { |
| // FORMAT has already been used |
| $this->_formats[$i]->_num_format = $hash_num_formats[$num_format]; |
| } |
| else{ |
| // Add a new FORMAT |
| $hash_num_formats[$num_format] = $index; |
| $this->_formats[$i]->_num_format = $index; |
| array_push($num_formats,$num_format); |
| $index++; |
| } |
| } |
| // Write the new FORMAT records starting from 0xA4 |
| $index = 164; |
| foreach ($num_formats as $num_format) { |
| $this->_storeNumFormat($num_format,$index); |
| $index++; |
| } |
| } |
| /** |
| * Write all XF records. |
| * |
| * @access private |
| */ |
| function _storeAllXfs() |
| { |
| // _tmp_format is added by the constructor. We use this to write the default XF's |
| // The default font index is 0 |
| // |
| $format = $this->_tmp_format; |
| for ($i=0; $i <= 14; $i++) { |
| $xf = $format->getXf('style'); // Style XF |
| $this->_append($xf); |
| } |
| $xf = $format->getXf('cell'); // Cell XF |
| $this->_append($xf); |
| // User defined XFs |
| for($i=0; $i < count($this->_formats); $i++) { |
| $xf = $this->_formats[$i]->getXf('cell'); |
| $this->_append($xf); |
| } |
| } |
| /** |
| * Write all STYLE records. |
| * |
| * @access private |
| */ |
| function _storeAllStyles() |
| { |
| $this->_storeStyle(); |
| } |
| /** |
| * Write the EXTERNCOUNT and EXTERNSHEET records. These are used as indexes for |
| * the NAME records. |
| * |
| * @access private |
| */ |
| function _storeExterns() |
| { |
| // Create EXTERNCOUNT with number of worksheets |
| $this->_storeExterncount(count($this->_worksheets)); |
| // Create EXTERNSHEET for each worksheet |
| foreach ($this->_sheetnames as $sheetname) { |
| $this->_storeExternsheet($sheetname); |
| } |
| } |
| /** |
| * Write the NAME record to define the print area and the repeat rows and cols. |
| * |
| * @access private |
| */ |
| function _storeNames() |
| { |
| // Create the print area NAME records |
| foreach ($this->_worksheets as $worksheet) { |
| // Write a Name record if the print area has been defined |
| if (isset($worksheet->print_rowmin)) |
| { |
| $this->_storeNameShort( |
| $worksheet->index, |
| 0x06, // NAME type |
| $worksheet->print_rowmin, |
| $worksheet->print_rowmax, |
| $worksheet->print_colmin, |
| $worksheet->print_colmax |
| ); |
| } |
| } |
| // Create the print title NAME records |
| foreach ($this->_worksheets as $worksheet) |
| { |
| $rowmin = $worksheet->title_rowmin; |
| $rowmax = $worksheet->title_rowmax; |
| $colmin = $worksheet->title_colmin; |
| $colmax = $worksheet->title_colmax; |
| // Determine if row + col, row, col or nothing has been defined |
| // and write the appropriate record |
| // |
| if (isset($rowmin) and isset($colmin)) { |
| // Row and column titles have been defined. |
| // Row title has been defined. |
| $this->_storeNameLong( |
| $worksheet->index, |
| 0x07, // NAME type |
| $rowmin, |
| $rowmax, |
| $colmin, |
| $colmax |
| ); |
| } |
| elseif (isset($rowmin)) { |
| // Row title has been defined. |
| $this->_storeNameShort( |
| $worksheet->index, |
| 0x07, // NAME type |
| $rowmin, |
| $rowmax, |
| 0x00, |
| 0xff |
| ); |
| } |
| elseif (isset($colmin)) { |
| // Column title has been defined. |
| $this->_storeNameShort( |
| $worksheet->index, |
| 0x07, // NAME type |
| 0x0000, |
| 0x3fff, |
| $colmin, |
| $colmax |
| ); |
| } |
| else { |
| // Print title hasn't been defined. |
| } |
| } |
| } |
| /****************************************************************************** |
| * |
| * BIFF RECORDS |
| * |
| */ |
| /** |
| * Write Excel BIFF WINDOW1 record. |
| * |
| * @access private |
| */ |
| function _storeWindow1() |
| { |
| $record = 0x003D; // Record identifier |
| $length = 0x0012; // Number of bytes to follow |
| $xWn = 0x0000; // Horizontal position of window |
| $yWn = 0x0000; // Vertical position of window |
| $dxWn = 0x25BC; // Width of window |
| $dyWn = 0x1572; // Height of window |
| $grbit = 0x0038; // Option flags |
| $ctabsel = $this->_selected; // Number of workbook tabs selected |
| $wTabRatio = 0x0258; // Tab to scrollbar ratio |
| $itabFirst = $this->_firstsheet; // 1st displayed worksheet |
| $itabCur = $this->_activesheet; // Active worksheet |
| $header = pack("vv", $record, $length); |
| $data = pack("vvvvvvvvv", $xWn, $yWn, $dxWn, $dyWn, |
| $grbit, |
| $itabCur, $itabFirst, |
| $ctabsel, $wTabRatio); |
| $this->_append($header.$data); |
| } |
| /** |
| * Writes Excel BIFF BOUNDSHEET record. |
| * |
| * @param string $sheetname Worksheet name |
| * @param integer $offset Location of worksheet BOF |
| * @access private |
| */ |
| function _storeBoundsheet($sheetname,$offset) |
| { |
| $record = 0x0085; // Record identifier |
| $length = 0x07 + strlen($sheetname); // Number of bytes to follow |
| $grbit = 0x0000; // Sheet identifier |
| $cch = strlen($sheetname); // Length of sheet name |
| $header = pack("vv", $record, $length); |
| $data = pack("VvC", $offset, $grbit, $cch); |
| $this->_append($header.$data.$sheetname); |
| } |
| /** |
| * Write Excel BIFF STYLE records. |
| * |
| * @access private |
| */ |
| function _storeStyle() |
| { |
| $record = 0x0293; // Record identifier |
| $length = 0x0004; // Bytes to follow |
| $ixfe = 0x8000; // Index to style XF |
| $BuiltIn = 0x00; // Built-in style |
| $iLevel = 0xff; // Outline style level |
| $header = pack("vv", $record, $length); |
| $data = pack("vCC", $ixfe, $BuiltIn, $iLevel); |
| $this->_append($header.$data); |
| } |
| /** |
| * Writes Excel FORMAT record for non "built-in" numerical formats. |
| * |
| * @param string $format Custom format string |
| * @param integer $ifmt Format index code |
| * @access private |
| */ |
| function _storeNumFormat($format,$ifmt) |
| { |
| $record = 0x041E; // Record identifier |
| $length = 0x03 + strlen($format); // Number of bytes to follow |
| $cch = strlen($format); // Length of format string |
| $header = pack("vv", $record, $length); |
| $data = pack("vC", $ifmt, $cch); |
| $this->_append($header.$data.$format); |
| } |
| /** |
| * Write Excel 1904 record to indicate the date system in use. |
| * |
| * @access private |
| */ |
| function _store1904() |
| { |
| $record = 0x0022; // Record identifier |
| $length = 0x0002; // Bytes to follow |
| $f1904 = $this->_1904; // Flag for 1904 date system |
| $header = pack("vv", $record, $length); |
| $data = pack("v", $f1904); |
| $this->_append($header.$data); |
| } |
| /** |
| * Write BIFF record EXTERNCOUNT to indicate the number of external sheet |
| * references in the workbook. |
| * |
| * Excel only stores references to external sheets that are used in NAME. |
| * The workbook NAME record is required to define the print area and the repeat |
| * rows and columns. |
| * |
| * A similar method is used in Worksheet.php for a slightly different purpose. |
| * |
| * @param integer $cxals Number of external references |
| * @access private |
| */ |
| function _storeExterncount($cxals) |
| { |
| $record = 0x0016; // Record identifier |
| $length = 0x0002; // Number of bytes to follow |
| $header = pack("vv", $record, $length); |
| $data = pack("v", $cxals); |
| $this->_append($header.$data); |
| } |
| /** |
| * Writes the Excel BIFF EXTERNSHEET record. These references are used by |
| * formulas. NAME record is required to define the print area and the repeat |
| * rows and columns. |
| * |
| * A similar method is used in Worksheet.php for a slightly different purpose. |
| * |
| * @param string $sheetname Worksheet name |
| * @access private |
| */ |
| function _storeExternsheet($sheetname) |
| { |
| $record = 0x0017; // Record identifier |
| $length = 0x02 + strlen($sheetname); // Number of bytes to follow |
| $cch = strlen($sheetname); // Length of sheet name |
| $rgch = 0x03; // Filename encoding |
| $header = pack("vv", $record, $length); |
| $data = pack("CC", $cch, $rgch); |
| $this->_append($header.$data.$sheetname); |
| } |
| /** |
| * Store the NAME record in the short format that is used for storing the print |
| * area, repeat rows only and repeat columns only. |
| * |
| * @param integer $index Sheet index |
| * @param integer $type Built-in name type |
| * @param integer $rowmin Start row |
| * @param integer $rowmax End row |
| * @param integer $colmin Start colum |
| * @param integer $colmax End column |
| * @access private |
| */ |
| function _storeNameShort($index,$type,$rowmin,$rowmax,$colmin,$colmax) |
| { |
| $record = 0x0018; // Record identifier |
| $length = 0x0024; // Number of bytes to follow |
| $grbit = 0x0020; // Option flags |
| $chKey = 0x00; // Keyboard shortcut |
| $cch = 0x01; // Length of text name |
| $cce = 0x0015; // Length of text definition |
| $ixals = $index + 1; // Sheet index |
| $itab = $ixals; // Equal to ixals |
| $cchCustMenu = 0x00; // Length of cust menu text |
| $cchDescription = 0x00; // Length of description text |
| $cchHelptopic = 0x00; // Length of help topic text |
| $cchStatustext = 0x00; // Length of status bar text |
| $rgch = $type; // Built-in name type |
| $unknown03 = 0x3b; |
| $unknown04 = 0xffff-$index; |
| $unknown05 = 0x0000; |
| $unknown06 = 0x0000; |
| $unknown07 = 0x1087; |
| $unknown08 = 0x8005; |
| $header = pack("vv", $record, $length); |
| $data = pack("v", $grbit); |
| $data .= pack("C", $chKey); |
| $data .= pack("C", $cch); |
| $data .= pack("v", $cce); |
| $data .= pack("v", $ixals); |
| $data .= pack("v", $itab); |
| $data .= pack("C", $cchCustMenu); |
| $data .= pack("C", $cchDescription); |
| $data .= pack("C", $cchHelptopic); |
| $data .= pack("C", $cchStatustext); |
| $data .= pack("C", $rgch); |
| $data .= pack("C", $unknown03); |
| $data .= pack("v", $unknown04); |
| $data .= pack("v", $unknown05); |
| $data .= pack("v", $unknown06); |
| $data .= pack("v", $unknown07); |
| $data .= pack("v", $unknown08); |
| $data .= pack("v", $index); |
| $data .= pack("v", $index); |
| $data .= pack("v", $rowmin); |
| $data .= pack("v", $rowmax); |
| $data .= pack("C", $colmin); |
| $data .= pack("C", $colmax); |
| $this->_append($header.$data); |
| } |
| /** |
| * Store the NAME record in the long format that is used for storing the repeat |
| * rows and columns when both are specified. This shares a lot of code with |
| * _storeNameShort() but we use a separate method to keep the code clean. |
| * Code abstraction for reuse can be carried too far, and I should know. ;-) |
| * |
| * @param integer $index Sheet index |
| * @param integer $type Built-in name type |
| * @param integer $rowmin Start row |
| * @param integer $rowmax End row |
| * @param integer $colmin Start colum |
| * @param integer $colmax End column |
| * @access private |
| */ |
| function _storeNameLong($index,$type,$rowmin,$rowmax,$colmin,$colmax) |
| { |
| $record = 0x0018; // Record identifier |
| $length = 0x003d; // Number of bytes to follow |
| $grbit = 0x0020; // Option flags |
| $chKey = 0x00; // Keyboard shortcut |
| $cch = 0x01; // Length of text name |
| $cce = 0x002e; // Length of text definition |
| $ixals = $index + 1; // Sheet index |
| $itab = $ixals; // Equal to ixals |
| $cchCustMenu = 0x00; // Length of cust menu text |
| $cchDescription = 0x00; // Length of description text |
| $cchHelptopic = 0x00; // Length of help topic text |
| $cchStatustext = 0x00; // Length of status bar text |
| $rgch = $type; // Built-in name type |
| $unknown01 = 0x29; |
| $unknown02 = 0x002b; |
| $unknown03 = 0x3b; |
| $unknown04 = 0xffff-$index; |
| $unknown05 = 0x0000; |
| $unknown06 = 0x0000; |
| $unknown07 = 0x1087; |
| $unknown08 = 0x8008; |
| $header = pack("vv", $record, $length); |
| $data = pack("v", $grbit); |
| $data .= pack("C", $chKey); |
| $data .= pack("C", $cch); |
| $data .= pack("v", $cce); |
| $data .= pack("v", $ixals); |
| $data .= pack("v", $itab); |
| $data .= pack("C", $cchCustMenu); |
| $data .= pack("C", $cchDescription); |
| $data .= pack("C", $cchHelptopic); |
| $data .= pack("C", $cchStatustext); |
| $data .= pack("C", $rgch); |
| $data .= pack("C", $unknown01); |
| $data .= pack("v", $unknown02); |
| // Column definition |
| $data .= pack("C", $unknown03); |
| $data .= pack("v", $unknown04); |
| $data .= pack("v", $unknown05); |
| $data .= pack("v", $unknown06); |
| $data .= pack("v", $unknown07); |
| $data .= pack("v", $unknown08); |
| $data .= pack("v", $index); |
| $data .= pack("v", $index); |
| $data .= pack("v", 0x0000); |
| $data .= pack("v", 0x3fff); |
| $data .= pack("C", $colmin); |
| $data .= pack("C", $colmax); |
| // Row definition |
| $data .= pack("C", $unknown03); |
| $data .= pack("v", $unknown04); |
| $data .= pack("v", $unknown05); |
| $data .= pack("v", $unknown06); |
| $data .= pack("v", $unknown07); |
| $data .= pack("v", $unknown08); |
| $data .= pack("v", $index); |
| $data .= pack("v", $index); |
| $data .= pack("v", $rowmin); |
| $data .= pack("v", $rowmax); |
| $data .= pack("C", 0x00); |
| $data .= pack("C", 0xff); |
| // End of data |
| $data .= pack("C", 0x10); |
| $this->_append($header.$data); |
| } |
| /** |
| * Stores the PALETTE biff record. |
| * |
| * @access private |
| */ |
| function _storePalette() |
| { |
| $aref = $this->_palette; |
| $record = 0x0092; // Record identifier |
| $length = 2 + 4 * count($aref); // Number of bytes to follow |
| $ccv = count($aref); // Number of RGB values to follow |
| $data = ''; // The RGB data |
| // Pack the RGB data |
| foreach($aref as $color) |
| { |
| foreach($color as $byte) { |
| $data .= pack("C",$byte); |
| } |
| } |
| $header = pack("vvv", $record, $length, $ccv); |
| $this->_append($header.$data); |
| } |
| } |
| ?> |
| /trunk/applications/jrest/lib/Spreadsheet/Excel/Writer/BIFFwriter.php |
|---|
| New file |
| 0,0 → 1,235 |
| <?php |
| /* |
| * Module written/ported by Xavier Noguer <xnoguer@rezebra.com> |
| * |
| * The majority of this is _NOT_ my code. I simply ported it from the |
| * PERL Spreadsheet::WriteExcel module. |
| * |
| * The author of the Spreadsheet::WriteExcel module is John McNamara |
| * <jmcnamara@cpan.org> |
| * |
| * I _DO_ maintain this code, and John McNamara has nothing to do with the |
| * porting of this code to PHP. Any questions directly related to this |
| * class library should be directed to me. |
| * |
| * License Information: |
| * |
| * Spreadsheet_Excel_Writer: A library for generating Excel Spreadsheets |
| * Copyright (c) 2002-2003 Xavier Noguer xnoguer@rezebra.com |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| */ |
| require_once('PEAR.php'); |
| /** |
| * Class for writing Excel BIFF records. |
| * |
| * From "MICROSOFT EXCEL BINARY FILE FORMAT" by Mark O'Brien (Microsoft Corporation): |
| * |
| * BIFF (BInary File Format) is the file format in which Excel documents are |
| * saved on disk. A BIFF file is a complete description of an Excel document. |
| * BIFF files consist of sequences of variable-length records. There are many |
| * different types of BIFF records. For example, one record type describes a |
| * formula entered into a cell; one describes the size and location of a |
| * window into a document; another describes a picture format. |
| * |
| * @author Xavier Noguer <xnoguer@rezebra.com> |
| * @category FileFormats |
| * @package Spreadsheet_Excel_Writer |
| */ |
| class Spreadsheet_Excel_Writer_BIFFwriter extends PEAR |
| { |
| /** |
| * The BIFF/Excel version (5). |
| * @var integer |
| */ |
| var $_BIFF_version = 0x0500; |
| /** |
| * The byte order of this architecture. 0 => little endian, 1 => big endian |
| * @var integer |
| */ |
| var $_byte_order; |
| /** |
| * The string containing the data of the BIFF stream |
| * @var string |
| */ |
| var $_data; |
| /** |
| * The size of the data in bytes. Should be the same as strlen($this->_data) |
| * @var integer |
| */ |
| var $_datasize; |
| /** |
| * The maximun length for a BIFF record. See _addContinue() |
| * @var integer |
| * @see _addContinue() |
| */ |
| var $_limit; |
| /** |
| * Constructor |
| * |
| * @access public |
| */ |
| function Spreadsheet_Excel_Writer_BIFFwriter() |
| { |
| $this->_byte_order = ''; |
| $this->_data = ''; |
| $this->_datasize = 0; |
| $this->_limit = 2080; |
| // Set the byte order |
| $this->_setByteOrder(); |
| } |
| /** |
| * Determine the byte order and store it as class data to avoid |
| * recalculating it for each call to new(). |
| * |
| * @access private |
| */ |
| function _setByteOrder() |
| { |
| if ($this->_byte_order == '') |
| { |
| // Check if "pack" gives the required IEEE 64bit float |
| $teststr = pack("d", 1.2345); |
| $number = pack("C8", 0x8D, 0x97, 0x6E, 0x12, 0x83, 0xC0, 0xF3, 0x3F); |
| if ($number == $teststr) { |
| $byte_order = 0; // Little Endian |
| } |
| elseif ($number == strrev($teststr)){ |
| $byte_order = 1; // Big Endian |
| } |
| else { |
| // Give up. I'll fix this in a later version. |
| $this->raiseError("Required floating point format not supported ". |
| "on this platform."); |
| } |
| } |
| $this->_byte_order = $byte_order; |
| } |
| /** |
| * General storage function |
| * |
| * @param string $data binary data to prepend |
| * @access private |
| */ |
| function _prepend($data) |
| { |
| if (strlen($data) > $this->_limit) { |
| $data = $this->_addContinue($data); |
| } |
| $this->_data = $data.$this->_data; |
| $this->_datasize += strlen($data); |
| } |
| /** |
| * General storage function |
| * |
| * @param string $data binary data to append |
| * @access private |
| */ |
| function _append($data) |
| { |
| if (strlen($data) > $this->_limit) { |
| $data = $this->_addContinue($data); |
| } |
| $this->_data = $this->_data.$data; |
| $this->_datasize += strlen($data); |
| } |
| /** |
| * Writes Excel BOF record to indicate the beginning of a stream or |
| * sub-stream in the BIFF file. |
| * |
| * @param integer $type type of BIFF file to write: 0x0005 Workbook, 0x0010 Worksheet. |
| * @access private |
| */ |
| function _storeBof($type) |
| { |
| $record = 0x0809; // Record identifier |
| $length = 0x0008; // Number of bytes to follow |
| $version = $this->_BIFF_version; |
| // According to the SDK $build and $year should be set to zero. |
| // However, this throws a warning in Excel 5. So, use these |
| // magic numbers. |
| $build = 0x096C; |
| $year = 0x07C9; |
| $header = pack("vv", $record, $length); |
| $data = pack("vvvv", $version, $type, $build, $year); |
| $this->_prepend($header.$data); |
| } |
| /** |
| * Writes Excel EOF record to indicate the end of a BIFF stream. |
| * |
| * @access private |
| */ |
| function _storeEof() |
| { |
| $record = 0x000A; // Record identifier |
| $length = 0x0000; // Number of bytes to follow |
| $header = pack("vv", $record, $length); |
| $this->_append($header); |
| } |
| /** |
| * Excel limits the size of BIFF records. In Excel 5 the limit is 2084 bytes. In |
| * Excel 97 the limit is 8228 bytes. Records that are longer than these limits |
| * must be split up into CONTINUE blocks. |
| * |
| * This function takes a long BIFF record and inserts CONTINUE records as |
| * necessary. |
| * |
| * @param string $data The original binary data to be written |
| * @return string A very convenient string of continue blocks |
| * @access private |
| */ |
| function _addContinue($data) |
| { |
| $limit = $this->_limit; |
| $record = 0x003C; // Record identifier |
| // The first 2080/8224 bytes remain intact. However, we have to change |
| // the length field of the record. |
| $tmp = substr($data, 0, 2).pack("v", $limit-4).substr($data, 4, $limit - 4); |
| $header = pack("vv", $record, $limit); // Headers for continue records |
| // Retrieve chunks of 2080/8224 bytes +4 for the header. |
| for($i = $limit; $i < strlen($data) - $limit; $i += $limit) |
| { |
| $tmp .= $header; |
| $tmp .= substr($data, $i, $limit); |
| } |
| // Retrieve the last chunk of data |
| $header = pack("vv", $record, strlen($data) - $i); |
| $tmp .= $header; |
| $tmp .= substr($data,$i,strlen($data) - $i); |
| return($tmp); |
| } |
| } |
| ?> |
| /trunk/applications/jrest/lib/Spreadsheet/Excel/Writer/Format.php |
|---|
| New file |
| 0,0 → 1,940 |
| <?php |
| /* |
| * Module written/ported by Xavier Noguer <xnoguer@rezebra.com> |
| * |
| * The majority of this is _NOT_ my code. I simply ported it from the |
| * PERL Spreadsheet::WriteExcel module. |
| * |
| * The author of the Spreadsheet::WriteExcel module is John McNamara |
| * <jmcnamara@cpan.org> |
| * |
| * I _DO_ maintain this code, and John McNamara has nothing to do with the |
| * porting of this code to PHP. Any questions directly related to this |
| * class library should be directed to me. |
| * |
| * License Information: |
| * |
| * Spreadsheet_Excel_Writer: A library for generating Excel Spreadsheets |
| * Copyright (c) 2002-2003 Xavier Noguer xnoguer@rezebra.com |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| */ |
| require_once('PEAR.php'); |
| /** |
| * Class for generating Excel XF records (formats) |
| * |
| * @author Xavier Noguer <xnoguer@rezebra.com> |
| * @category FileFormats |
| * @package Spreadsheet_Excel_Writer |
| */ |
| class Spreadsheet_Excel_Writer_Format extends PEAR |
| { |
| /** |
| * The index given by the workbook when creating a new format. |
| * @var integer |
| */ |
| var $_xf_index; |
| /** |
| * Index to the FONT record. |
| * @var integer |
| */ |
| var $font_index; |
| /** |
| * The font name (ASCII). |
| * @var string |
| */ |
| var $_font_name; |
| /** |
| * Height of font (1/20 of a point) |
| * @var integer |
| */ |
| var $_size; |
| /** |
| * Bold style |
| * @var integer |
| */ |
| var $_bold; |
| /** |
| * Bit specifiying if the font is italic. |
| * @var integer |
| */ |
| var $_italic; |
| /** |
| * Index to the cell's color |
| * @var integer |
| */ |
| var $_color; |
| /** |
| * The text underline property |
| * @var integer |
| */ |
| var $_underline; |
| /** |
| * Bit specifiying if the font has strikeout. |
| * @var integer |
| */ |
| var $_font_strikeout; |
| /** |
| * Bit specifiying if the font has outline. |
| * @var integer |
| */ |
| var $_font_outline; |
| /** |
| * Bit specifiying if the font has shadow. |
| * @var integer |
| */ |
| var $_font_shadow; |
| /** |
| * 2 bytes specifiying the script type for the font. |
| * @var integer |
| */ |
| var $_font_script; |
| /** |
| * Byte specifiying the font family. |
| * @var integer |
| */ |
| var $_font_family; |
| /** |
| * Byte specifiying the font charset. |
| * @var integer |
| */ |
| var $_font_charset; |
| /** |
| * An index (2 bytes) to a FORMAT record (number format). |
| * @var integer |
| */ |
| var $_num_format; |
| /** |
| * Bit specifying if formulas are hidden. |
| * @var integer |
| */ |
| var $_hidden; |
| /** |
| * Bit specifying if the cell is locked. |
| * @var integer |
| */ |
| var $_locked; |
| /** |
| * The three bits specifying the text horizontal alignment. |
| * @var integer |
| */ |
| var $_text_h_align; |
| /** |
| * Bit specifying if the text is wrapped at the right border. |
| * @var integer |
| */ |
| var $_text_wrap; |
| /** |
| * The three bits specifying the text vertical alignment. |
| * @var integer |
| */ |
| var $_text_v_align; |
| /** |
| * 1 bit, apparently not used. |
| * @var integer |
| */ |
| var $_text_justlast; |
| /** |
| * The two bits specifying the text rotation. |
| * @var integer |
| */ |
| var $_rotation; |
| /** |
| * The cell's foreground color. |
| * @var integer |
| */ |
| var $_fg_color; |
| /** |
| * The cell's background color. |
| * @var integer |
| */ |
| var $_bg_color; |
| /** |
| * The cell's background fill pattern. |
| * @var integer |
| */ |
| var $_pattern; |
| /** |
| * Style of the bottom border of the cell |
| * @var integer |
| */ |
| var $_bottom; |
| /** |
| * Color of the bottom border of the cell. |
| * @var integer |
| */ |
| var $_bottom_color; |
| /** |
| * Style of the top border of the cell |
| * @var integer |
| */ |
| var $_top; |
| /** |
| * Color of the top border of the cell. |
| * @var integer |
| */ |
| var $_top_color; |
| /** |
| * Style of the left border of the cell |
| * @var integer |
| */ |
| var $_left; |
| /** |
| * Color of the left border of the cell. |
| * @var integer |
| */ |
| var $_left_color; |
| /** |
| * Style of the right border of the cell |
| * @var integer |
| */ |
| var $_right; |
| /** |
| * Color of the right border of the cell. |
| * @var integer |
| */ |
| var $_right_color; |
| /** |
| * Constructor |
| * |
| * @access public |
| * @param integer $index the XF index for the format. |
| * @param array $properties array with properties to be set on initialization. |
| */ |
| function Spreadsheet_Excel_Writer_Format($index = 0,$properties = array()) |
| { |
| $this->_xf_index = $index; |
| $this->font_index = 0; |
| $this->_font_name = 'Arial'; |
| $this->_size = 10; |
| $this->_bold = 0x0190; |
| $this->_italic = 0; |
| $this->_color = 0x7FFF; |
| $this->_underline = 0; |
| $this->_font_strikeout = 0; |
| $this->_font_outline = 0; |
| $this->_font_shadow = 0; |
| $this->_font_script = 0; |
| $this->_font_family = 0; |
| $this->_font_charset = 0; |
| $this->_num_format = 0; |
| $this->_hidden = 0; |
| $this->_locked = 1; |
| $this->_text_h_align = 0; |
| $this->_text_wrap = 0; |
| $this->_text_v_align = 2; |
| $this->_text_justlast = 0; |
| $this->_rotation = 0; |
| $this->_fg_color = 0x40; |
| $this->_bg_color = 0x41; |
| $this->_pattern = 0; |
| $this->_bottom = 0; |
| $this->_top = 0; |
| $this->_left = 0; |
| $this->_right = 0; |
| $this->_bottom_color = 0x40; |
| $this->_top_color = 0x40; |
| $this->_left_color = 0x40; |
| $this->_right_color = 0x40; |
| // Set properties passed to Spreadsheet_Excel_Writer_Workbook::addFormat() |
| foreach($properties as $property => $value) |
| { |
| if(method_exists($this,'set'.ucwords($property))) |
| { |
| $method_name = 'set'.ucwords($property); |
| $this->$method_name($value); |
| } |
| } |
| } |
| /** |
| * Generate an Excel BIFF XF record (style or cell). |
| * |
| * @param string $style The type of the XF record ('style' or 'cell'). |
| * @return string The XF record |
| */ |
| function getXf($style) |
| { |
| // Set the type of the XF record and some of the attributes. |
| if ($style == "style") { |
| $style = 0xFFF5; |
| } |
| else { |
| $style = $this->_locked; |
| $style |= $this->_hidden << 1; |
| } |
| // Flags to indicate if attributes have been set. |
| $atr_num = ($this->_num_format != 0)?1:0; |
| $atr_fnt = ($this->font_index != 0)?1:0; |
| $atr_alc = ($this->_text_wrap)?1:0; |
| $atr_bdr = ($this->_bottom || |
| $this->_top || |
| $this->_left || |
| $this->_right)?1:0; |
| $atr_pat = (($this->_fg_color != 0x40) || |
| ($this->_bg_color != 0x41) || |
| $this->_pattern)?1:0; |
| $atr_prot = 0; |
| // Zero the default border colour if the border has not been set. |
| if ($this->_bottom == 0) { |
| $this->_bottom_color = 0; |
| } |
| if ($this->_top == 0) { |
| $this->_top_color = 0; |
| } |
| if ($this->_right == 0) { |
| $this->_right_color = 0; |
| } |
| if ($this->_left == 0) { |
| $this->_left_color = 0; |
| } |
| $record = 0x00E0; // Record identifier |
| $length = 0x0010; // Number of bytes to follow |
| $ifnt = $this->font_index; // Index to FONT record |
| $ifmt = $this->_num_format; // Index to FORMAT record |
| $align = $this->_text_h_align; // Alignment |
| $align |= $this->_text_wrap << 3; |
| $align |= $this->_text_v_align << 4; |
| $align |= $this->_text_justlast << 7; |
| $align |= $this->_rotation << 8; |
| $align |= $atr_num << 10; |
| $align |= $atr_fnt << 11; |
| $align |= $atr_alc << 12; |
| $align |= $atr_bdr << 13; |
| $align |= $atr_pat << 14; |
| $align |= $atr_prot << 15; |
| $icv = $this->_fg_color; // fg and bg pattern colors |
| $icv |= $this->_bg_color << 7; |
| $fill = $this->_pattern; // Fill and border line style |
| $fill |= $this->_bottom << 6; |
| $fill |= $this->_bottom_color << 9; |
| $border1 = $this->_top; // Border line style and color |
| $border1 |= $this->_left << 3; |
| $border1 |= $this->_right << 6; |
| $border1 |= $this->_top_color << 9; |
| $border2 = $this->_left_color; // Border color |
| $border2 |= $this->_right_color << 7; |
| $header = pack("vv", $record, $length); |
| $data = pack("vvvvvvvv", $ifnt, $ifmt, $style, $align, |
| $icv, $fill, |
| $border1, $border2); |
| return($header.$data); |
| } |
| /** |
| * Generate an Excel BIFF FONT record. |
| * |
| * @return string The FONT record |
| */ |
| function getFont() |
| { |
| $dyHeight = $this->_size * 20; // Height of font (1/20 of a point) |
| $icv = $this->_color; // Index to color palette |
| $bls = $this->_bold; // Bold style |
| $sss = $this->_font_script; // Superscript/subscript |
| $uls = $this->_underline; // Underline |
| $bFamily = $this->_font_family; // Font family |
| $bCharSet = $this->_font_charset; // Character set |
| $rgch = $this->_font_name; // Font name |
| $cch = strlen($rgch); // Length of font name |
| $record = 0x31; // Record identifier |
| $length = 0x0F + $cch; // Record length |
| $reserved = 0x00; // Reserved |
| $grbit = 0x00; // Font attributes |
| if ($this->_italic) { |
| $grbit |= 0x02; |
| } |
| if ($this->_font_strikeout) { |
| $grbit |= 0x08; |
| } |
| if ($this->_font_outline) { |
| $grbit |= 0x10; |
| } |
| if ($this->_font_shadow) { |
| $grbit |= 0x20; |
| } |
| $header = pack("vv", $record, $length); |
| $data = pack("vvvvvCCCCC", $dyHeight, $grbit, $icv, $bls, |
| $sss, $uls, $bFamily, |
| $bCharSet, $reserved, $cch); |
| return($header . $data. $this->_font_name); |
| } |
| /** |
| * Returns a unique hash key for a font. |
| * Used by Spreadsheet_Excel_Writer_Workbook::_storeAllFonts() |
| * |
| * The elements that form the key are arranged to increase the probability of |
| * generating a unique key. Elements that hold a large range of numbers |
| * (eg. _color) are placed between two binary elements such as _italic |
| * |
| * @return string A key for this font |
| */ |
| function getFontKey() |
| { |
| $key = "$this->_font_name$this->_size"; |
| $key .= "$this->_font_script$this->_underline"; |
| $key .= "$this->_font_strikeout$this->_bold$this->_font_outline"; |
| $key .= "$this->_font_family$this->_font_charset"; |
| $key .= "$this->_font_shadow$this->_color$this->_italic"; |
| $key = str_replace(" ","_",$key); |
| return ($key); |
| } |
| /** |
| * Returns the index used by Spreadsheet_Excel_Writer_Worksheet::_XF() |
| * |
| * @return integer The index for the XF record |
| */ |
| function getXfIndex() |
| { |
| return($this->_xf_index); |
| } |
| /** |
| * Used in conjunction with the set_xxx_color methods to convert a color |
| * string into a number. Color range is 0..63 but we will restrict it |
| * to 8..63 to comply with Gnumeric. Colors 0..7 are repeated in 8..15. |
| * |
| * @access private |
| * @param string $name_color name of the color (i.e.: 'blue', 'red', etc..). Optional. |
| * @return integer The color index |
| */ |
| function _getColor($name_color = '') |
| { |
| $colors = array( |
| 'aqua' => 0x0F, |
| 'cyan' => 0x0F, |
| 'black' => 0x08, |
| 'blue' => 0x0C, |
| 'brown' => 0x10, |
| 'magenta' => 0x0E, |
| 'fuchsia' => 0x0E, |
| 'gray' => 0x17, |
| 'grey' => 0x17, |
| 'green' => 0x11, |
| 'lime' => 0x0B, |
| 'navy' => 0x12, |
| 'orange' => 0x35, |
| 'purple' => 0x14, |
| 'red' => 0x0A, |
| 'silver' => 0x16, |
| 'white' => 0x09, |
| 'yellow' => 0x0D |
| ); |
| // Return the default color, 0x7FFF, if undef, |
| if($name_color == '') { |
| return(0x7FFF); |
| } |
| // or the color string converted to an integer, |
| if(isset($colors[$name_color])) { |
| return($colors[$name_color]); |
| } |
| // or the default color if string is unrecognised, |
| if(preg_match("/\D/",$name_color)) { |
| return(0x7FFF); |
| } |
| // or an index < 8 mapped into the correct range, |
| if($name_color < 8) { |
| return($name_color + 8); |
| } |
| // or the default color if arg is outside range, |
| if($name_color > 63) { |
| return(0x7FFF); |
| } |
| // or an integer in the valid range |
| return($name_color); |
| } |
| /** |
| * Set cell alignment. |
| * |
| * @access public |
| * @param string $location alignment for the cell ('left', 'right', etc...). |
| */ |
| function setAlign($location) |
| { |
| if (preg_match("/\d/",$location)) { |
| return; // Ignore numbers |
| } |
| $location = strtolower($location); |
| if ($location == 'left') { |
| $this->_text_h_align = 1; |
| } |
| if ($location == 'centre') { |
| $this->_text_h_align = 2; |
| } |
| if ($location == 'center') { |
| $this->_text_h_align = 2; |
| } |
| if ($location == 'right') { |
| $this->_text_h_align = 3; |
| } |
| if ($location == 'fill') { |
| $this->_text_h_align = 4; |
| } |
| if ($location == 'justify') { |
| $this->_text_h_align = 5; |
| } |
| if ($location == 'merge') { |
| $this->_text_h_align = 6; |
| } |
| if ($location == 'equal_space') { // For T.K. |
| $this->_text_h_align = 7; |
| } |
| if ($location == 'top') { |
| $this->_text_v_align = 0; |
| } |
| if ($location == 'vcentre') { |
| $this->_text_v_align = 1; |
| } |
| if ($location == 'vcenter') { |
| $this->_text_v_align = 1; |
| } |
| if ($location == 'bottom') { |
| $this->_text_v_align = 2; |
| } |
| if ($location == 'vjustify') { |
| $this->_text_v_align = 3; |
| } |
| if ($location == 'vequal_space') { // For T.K. |
| $this->_text_v_align = 4; |
| } |
| } |
| /** |
| * This is an alias for the unintuitive setAlign('merge') |
| * |
| * @access public |
| */ |
| function setMerge() |
| { |
| $this->setAlign('merge'); |
| } |
| /** |
| * Sets the boldness of the text. |
| * Bold has a range 100..1000. |
| * 0 (400) is normal. 1 (700) is bold. |
| * |
| * @access public |
| * @param integer $weight Weight for the text, 0 maps to 400 (normal text), |
| 1 maps to 700 (bold text). Valid range is: 100-1000. |
| It's Optional, default is 1 (bold). |
| */ |
| function setBold($weight = 1) |
| { |
| if($weight == 1) { |
| $weight = 0x2BC; // Bold text |
| } |
| if($weight == 0) { |
| $weight = 0x190; // Normal text |
| } |
| if($weight < 0x064) { |
| $weight = 0x190; // Lower bound |
| } |
| if($weight > 0x3E8) { |
| $weight = 0x190; // Upper bound |
| } |
| $this->_bold = $weight; |
| } |
| /************************************ |
| * FUNCTIONS FOR SETTING CELLS BORDERS |
| */ |
| /** |
| * Sets the width for the bottom border of the cell |
| * |
| * @access public |
| * @param integer $style style of the cell border. 1 => thin, 2 => thick. |
| */ |
| function setBottom($style) |
| { |
| $this->_bottom = $style; |
| } |
| /** |
| * Sets the width for the top border of the cell |
| * |
| * @access public |
| * @param integer $style style of the cell top border. 1 => thin, 2 => thick. |
| */ |
| function setTop($style) |
| { |
| $this->_top = $style; |
| } |
| /** |
| * Sets the width for the left border of the cell |
| * |
| * @access public |
| * @param integer $style style of the cell left border. 1 => thin, 2 => thick. |
| */ |
| function setLeft($style) |
| { |
| $this->_left = $style; |
| } |
| /** |
| * Sets the width for the right border of the cell |
| * |
| * @access public |
| * @param integer $style style of the cell right border. 1 => thin, 2 => thick. |
| */ |
| function setRight($style) |
| { |
| $this->_right = $style; |
| } |
| /** |
| * Set cells borders to the same style |
| * |
| * @access public |
| * @param integer $style style to apply for all cell borders. 1 => thin, 2 => thick. |
| */ |
| function setBorder($style) |
| { |
| $this->setBottom($style); |
| $this->setTop($style); |
| $this->setLeft($style); |
| $this->setRight($style); |
| } |
| /******************************************* |
| * FUNCTIONS FOR SETTING CELLS BORDERS COLORS |
| */ |
| /** |
| * Sets all the cell's borders to the same color |
| * |
| * @access public |
| * @param mixed $color The color we are setting. Either a string (like 'blue'), |
| * or an integer (range is [8...63]). |
| */ |
| function setBorderColor($color) |
| { |
| $this->setBottomColor($color); |
| $this->setTopColor($color); |
| $this->setLeftColor($color); |
| $this->setRightColor($color); |
| } |
| /** |
| * Sets the cell's bottom border color |
| * |
| * @access public |
| * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63]). |
| */ |
| function setBottomColor($color) |
| { |
| $value = $this->_getColor($color); |
| $this->_bottom_color = $value; |
| } |
| /** |
| * Sets the cell's top border color |
| * |
| * @access public |
| * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63]). |
| */ |
| function setTopColor($color) |
| { |
| $value = $this->_getColor($color); |
| $this->_top_color = $value; |
| } |
| /** |
| * Sets the cell's left border color |
| * |
| * @access public |
| * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63]). |
| */ |
| function setLeftColor($color) |
| { |
| $value = $this->_getColor($color); |
| $this->_left_color = $value; |
| } |
| /** |
| * Sets the cell's right border color |
| * |
| * @access public |
| * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63]). |
| */ |
| function setRightColor($color) |
| { |
| $value = $this->_getColor($color); |
| $this->_right_color = $value; |
| } |
| /** |
| * Sets the cell's foreground color |
| * |
| * @access public |
| * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63]). |
| */ |
| function setFgColor($color) |
| { |
| $value = $this->_getColor($color); |
| $this->_fg_color = $value; |
| } |
| /** |
| * Sets the cell's background color |
| * |
| * @access public |
| * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63]). |
| */ |
| function setBgColor($color) |
| { |
| $value = $this->_getColor($color); |
| $this->_bg_color = $value; |
| } |
| /** |
| * Sets the cell's color |
| * |
| * @access public |
| * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63]). |
| */ |
| function setColor($color) |
| { |
| $value = $this->_getColor($color); |
| $this->_color = $value; |
| } |
| /** |
| * Sets the fill pattern attribute of a cell |
| * |
| * @access public |
| * @param integer $arg Optional. Defaults to 1. Meaningful values are: 0-18, |
| * 0 meaning no background. |
| */ |
| function setPattern($arg = 1) |
| { |
| $this->_pattern = $arg; |
| } |
| /** |
| * Sets the underline of the text |
| * |
| * @access public |
| * @param integer $underline The value for underline. Possible values are: |
| * 1 => underline, 2 => double underline. |
| */ |
| function setUnderline($underline) |
| { |
| $this->_underline = $underline; |
| } |
| /** |
| * Sets the font style as italic |
| * |
| * @access public |
| */ |
| function setItalic() |
| { |
| $this->_italic = 1; |
| } |
| /** |
| * Sets the font size |
| * |
| * @access public |
| * @param integer $size The font size (in pixels I think). |
| */ |
| function setSize($size) |
| { |
| $this->_size = $size; |
| } |
| /** |
| * Sets text wrapping |
| * |
| * @access public |
| */ |
| function setTextWrap() |
| { |
| $this->_text_wrap = 1; |
| } |
| /** |
| * Sets the orientation of the text |
| * |
| * @access public |
| * @param integer $angle The rotation angle for the text (clockwise). Possible |
| values are: 0, 90, 270 and -1 for stacking top-to-bottom. |
| */ |
| function setTextRotation($angle) |
| { |
| switch ($angle) |
| { |
| case 0: |
| $this->_rotation = 0; |
| break; |
| case 90: |
| $this->_rotation = 3; |
| break; |
| case 270: |
| $this->_rotation = 2; |
| break; |
| case -1: |
| $this->_rotation = 1; |
| break; |
| default : |
| $this->raiseError("Invalid value for angle.". |
| " Possible values are: 0, 90, 270 and -1 ". |
| "for stacking top-to-bottom."); |
| $this->_rotation = 0; |
| break; |
| } |
| } |
| /** |
| * Sets the numeric format. |
| * It can be date, time, currency, etc... |
| * |
| * @access public |
| * @param integer $num_format The numeric format. |
| */ |
| function setNumFormat($num_format) |
| { |
| $this->_num_format = $num_format; |
| } |
| /** |
| * Sets font as strikeout. |
| * |
| * @access public |
| */ |
| function setStrikeOut() |
| { |
| $this->_font_strikeout = 1; |
| } |
| /** |
| * Sets outlining for a font. |
| * |
| * @access public |
| */ |
| function setOutLine() |
| { |
| $this->_font_outline = 1; |
| } |
| /** |
| * Sets font as shadow. |
| * |
| * @access public |
| */ |
| function setShadow() |
| { |
| $this->_font_shadow = 1; |
| } |
| /** |
| * Sets the script type of the text |
| * |
| * @access public |
| * @param integer $script The value for script type. Possible values are: |
| * 1 => superscript, 2 => subscript. |
| */ |
| function setScript($script) |
| { |
| $this->_font_script = $script; |
| } |
| /** |
| * Unlocks a cell. Useful for unprotecting particular cells of a protected sheet. |
| * |
| * @access public |
| */ |
| function setUnLocked() |
| { |
| $this->_locked = 0; |
| } |
| } |
| ?> |
| /trunk/applications/jrest/lib/Spreadsheet/Excel/Writer/Worksheet.php |
|---|
| New file |
| 0,0 → 1,3095 |
| <?php |
| /* |
| * Module written/ported by Xavier Noguer <xnoguer@rezebra.com> |
| * |
| * The majority of this is _NOT_ my code. I simply ported it from the |
| * PERL Spreadsheet::WriteExcel module. |
| * |
| * The author of the Spreadsheet::WriteExcel module is John McNamara |
| * <jmcnamara@cpan.org> |
| * |
| * I _DO_ maintain this code, and John McNamara has nothing to do with the |
| * porting of this code to PHP. Any questions directly related to this |
| * class library should be directed to me. |
| * |
| * License Information: |
| * |
| * Spreadsheet_Excel_Writer: A library for generating Excel Spreadsheets |
| * Copyright (c) 2002-2003 Xavier Noguer xnoguer@rezebra.com |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| */ |
| require_once('Parser.php'); |
| require_once('BIFFwriter.php'); |
| /** |
| * Class for generating Excel Spreadsheets |
| * |
| * @author Xavier Noguer <xnoguer@rezebra.com> |
| * @category FileFormats |
| * @package Spreadsheet_Excel_Writer |
| */ |
| class Spreadsheet_Excel_Writer_Worksheet extends Spreadsheet_Excel_Writer_BIFFwriter |
| { |
| /** |
| * Name of the Worksheet |
| * @var string |
| */ |
| var $name; |
| /** |
| * Index for the Worksheet |
| * @var integer |
| */ |
| var $index; |
| /** |
| * Reference to the (default) Format object for URLs |
| * @var object Format |
| */ |
| var $_url_format; |
| /** |
| * Reference to the parser used for parsing formulas |
| * @var object Format |
| */ |
| var $_parser; |
| /** |
| * Filehandle to the temporary file for storing data |
| * @var resource |
| */ |
| var $_filehandle; |
| /** |
| * Boolean indicating if we are using a temporary file for storing data |
| * @var bool |
| */ |
| var $_using_tmpfile; |
| /** |
| * Maximum number of rows for an Excel spreadsheet (BIFF5) |
| * @var integer |
| */ |
| var $_xls_rowmax; |
| /** |
| * Maximum number of columns for an Excel spreadsheet (BIFF5) |
| * @var integer |
| */ |
| var $_xls_colmax; |
| /** |
| * Maximum number of characters for a string (LABEL record in BIFF5) |
| * @var integer |
| */ |
| var $_xls_strmax; |
| /** |
| * First row for the DIMENSIONS record |
| * @var integer |
| * @see storeDimensions() |
| */ |
| var $_dim_rowmin; |
| /** |
| * Last row for the DIMENSIONS record |
| * @var integer |
| * @see storeDimensions() |
| */ |
| var $_dim_rowmax; |
| /** |
| * First column for the DIMENSIONS record |
| * @var integer |
| * @see storeDimensions() |
| */ |
| var $_dim_colmin; |
| /** |
| * Last column for the DIMENSIONS record |
| * @var integer |
| * @see storeDimensions() |
| */ |
| var $_dim_colmax; |
| /** |
| * Array containing format information for columns |
| * @var array |
| */ |
| var $_colinfo; |
| /** |
| * Array containing the selected area for the worksheet |
| * @var array |
| */ |
| var $_selection; |
| /** |
| * Array containing the panes for the worksheet |
| * @var array |
| */ |
| var $_panes; |
| /** |
| * The active pane for the worksheet |
| * @var integer |
| */ |
| var $_active_pane; |
| /** |
| * Bit specifying if panes are frozen |
| * @var integer |
| */ |
| var $_frozen; |
| /** |
| * Bit specifying if the worksheet is selected |
| * @var integer |
| */ |
| var $selected; |
| /** |
| * The paper size (for printing) (DOCUMENT!!!) |
| * @var integer |
| */ |
| var $_paper_size; |
| /** |
| * Bit specifying paper orientation (for printing). 0 => landscape, 1 => portrait |
| * @var integer |
| */ |
| var $_orientation; |
| /** |
| * The page header caption |
| * @var string |
| */ |
| var $_header; |
| /** |
| * The page footer caption |
| * @var string |
| */ |
| var $_footer; |
| /** |
| * The horizontal centering value for the page |
| * @var integer |
| */ |
| var $_hcenter; |
| /** |
| * The vertical centering value for the page |
| * @var integer |
| */ |
| var $_vcenter; |
| /** |
| * The margin for the header |
| * @var float |
| */ |
| var $_margin_head; |
| /** |
| * The margin for the footer |
| * @var float |
| */ |
| var $_margin_foot; |
| /** |
| * The left margin for the worksheet in inches |
| * @var float |
| */ |
| var $_margin_left; |
| /** |
| * The right margin for the worksheet in inches |
| * @var float |
| */ |
| var $_margin_right; |
| /** |
| * The top margin for the worksheet in inches |
| * @var float |
| */ |
| var $_margin_top; |
| /** |
| * The bottom margin for the worksheet in inches |
| * @var float |
| */ |
| var $_margin_bottom; |
| /** |
| * First row to reapeat on each printed page |
| * @var integer |
| */ |
| var $title_rowmin; |
| /** |
| * Last row to reapeat on each printed page |
| * @var integer |
| */ |
| var $title_rowmax; |
| /** |
| * First column to reapeat on each printed page |
| * @var integer |
| */ |
| var $title_colmin; |
| /** |
| * First row of the area to print |
| * @var integer |
| */ |
| var $print_rowmin; |
| /** |
| * Last row to of the area to print |
| * @var integer |
| */ |
| var $print_rowmax; |
| /** |
| * First column of the area to print |
| * @var integer |
| */ |
| var $print_colmin; |
| /** |
| * Last column of the area to print |
| * @var integer |
| */ |
| var $print_colmax; |
| /** |
| * Constructor |
| * |
| * @param string $name The name of the new worksheet |
| * @param integer $index The index of the new worksheet |
| * @param mixed &$activesheet The current activesheet of the workbook we belong to |
| * @param mixed &$firstsheet The first worksheet in the workbook we belong to |
| * @param mixed &$url_format The default format for hyperlinks |
| * @param mixed &$parser The formula parser created for the Workbook |
| */ |
| function Spreadsheet_Excel_Writer_Worksheet($name, $index, &$activesheet, |
| &$firstsheet, &$url_format, |
| &$parser) |
| { |
| // It needs to call its parent's constructor explicitly |
| $this->Spreadsheet_Excel_Writer_BIFFwriter(); |
| $rowmax = 65536; // 16384 in Excel 5 |
| $colmax = 256; |
| $this->name = $name; |
| $this->index = $index; |
| $this->activesheet = &$activesheet; |
| $this->firstsheet = &$firstsheet; |
| $this->_url_format = &$url_format; |
| $this->_parser = &$parser; |
| //$this->ext_sheets = array(); |
| $this->_filehandle = ""; |
| $this->_using_tmpfile = true; |
| //$this->fileclosed = 0; |
| //$this->offset = 0; |
| $this->_xls_rowmax = $rowmax; |
| $this->_xls_colmax = $colmax; |
| $this->_xls_strmax = 255; |
| $this->_dim_rowmin = $rowmax + 1; |
| $this->_dim_rowmax = 0; |
| $this->_dim_colmin = $colmax + 1; |
| $this->_dim_colmax = 0; |
| $this->_colinfo = array(); |
| $this->_selection = array(0,0,0,0); |
| $this->_panes = array(); |
| $this->_active_pane = 3; |
| $this->_frozen = 0; |
| $this->selected = 0; |
| $this->_paper_size = 0x0; |
| $this->_orientation = 0x1; |
| $this->_header = ''; |
| $this->_footer = ''; |
| $this->_hcenter = 0; |
| $this->_vcenter = 0; |
| $this->_margin_head = 0.50; |
| $this->_margin_foot = 0.50; |
| $this->_margin_left = 0.75; |
| $this->_margin_right = 0.75; |
| $this->_margin_top = 1.00; |
| $this->_margin_bottom = 1.00; |
| $this->title_rowmin = NULL; |
| $this->title_rowmax = NULL; |
| $this->title_colmin = NULL; |
| $this->title_colmax = NULL; |
| $this->print_rowmin = NULL; |
| $this->print_rowmax = NULL; |
| $this->print_colmin = NULL; |
| $this->print_colmax = NULL; |
| $this->_print_gridlines = 1; |
| $this->_print_headers = 0; |
| $this->_fit_page = 0; |
| $this->_fit_width = 0; |
| $this->_fit_height = 0; |
| $this->_hbreaks = array(); |
| $this->_vbreaks = array(); |
| $this->_protect = 0; |
| $this->_password = NULL; |
| $this->col_sizes = array(); |
| $this->row_sizes = array(); |
| $this->_zoom = 100; |
| $this->_print_scale = 100; |
| $this->_initialize(); |
| } |
| /** |
| * Open a tmp file to store the majority of the Worksheet data. If this fails, |
| * for example due to write permissions, store the data in memory. This can be |
| * slow for large files. |
| * |
| * @access private |
| */ |
| function _initialize() |
| { |
| // Open tmp file for storing Worksheet data |
| $fh = tmpfile(); |
| if ( $fh) { |
| // Store filehandle |
| $this->_filehandle = $fh; |
| } |
| else { |
| // If tmpfile() fails store data in memory |
| $this->_using_tmpfile = false; |
| } |
| } |
| /** |
| * Add data to the beginning of the workbook (note the reverse order) |
| * and to the end of the workbook. |
| * |
| * @access public |
| * @see Spreadsheet_Excel_Writer_Workbook::storeWorkbook() |
| * @param array $sheetnames The array of sheetnames from the Workbook this |
| * worksheet belongs to |
| */ |
| function close($sheetnames) |
| { |
| $num_sheets = count($sheetnames); |
| /*********************************************** |
| * Prepend in reverse order!! |
| */ |
| // Prepend the sheet dimensions |
| $this->storeDimensions(); |
| // Prepend the sheet password |
| $this->_storePassword(); |
| // Prepend the sheet protection |
| $this->_storeProtect(); |
| // Prepend the page setup |
| $this->_storeSetup(); |
| // Prepend the bottom margin |
| $this->_storeMarginBottom(); |
| // Prepend the top margin |
| $this->_storeMarginTop(); |
| // Prepend the right margin |
| $this->_storeMarginRight(); |
| // Prepend the left margin |
| $this->_storeMarginLeft(); |
| // Prepend the page vertical centering |
| $this->_storeVcenter(); |
| // Prepend the page horizontal centering |
| $this->_storeHcenter(); |
| // Prepend the page footer |
| $this->_storeFooter(); |
| // Prepend the page header |
| $this->_storeHeader(); |
| // Prepend the vertical page breaks |
| $this->_storeVbreak(); |
| // Prepend the horizontal page breaks |
| $this->_storeHbreak(); |
| // Prepend WSBOOL |
| $this->_storeWsbool(); |
| // Prepend GRIDSET |
| $this->_storeGridset(); |
| // Prepend PRINTGRIDLINES |
| $this->_storePrintGridlines(); |
| // Prepend PRINTHEADERS |
| $this->_storePrintHeaders(); |
| // Prepend EXTERNSHEET references |
| for ($i = $num_sheets; $i > 0; $i--) |
| { |
| $sheetname = $sheetnames[$i-1]; |
| $this->_storeExternsheet($sheetname); |
| } |
| // Prepend the EXTERNCOUNT of external references. |
| $this->_storeExterncount($num_sheets); |
| // Prepend the COLINFO records if they exist |
| if (!empty($this->_colinfo)) |
| { |
| for($i=0; $i < count($this->_colinfo); $i++) { |
| $this->_storeColinfo($this->_colinfo[$i]); |
| } |
| $this->_storeDefcol(); |
| } |
| // Prepend the BOF record |
| $this->_storeBof(0x0010); |
| /* |
| * End of prepend. Read upwards from here. |
| ***********************************************/ |
| // Append |
| $this->_storeWindow2(); |
| $this->_storeZoom(); |
| if (!empty($this->_panes)) { |
| $this->_storePanes($this->_panes); |
| } |
| $this->_storeSelection($this->_selection); |
| $this->_storeEof(); |
| } |
| /** |
| * Retrieve the worksheet name. |
| * This is usefull when creating worksheets without a name. |
| * |
| * @access public |
| * @return string The worksheet's name |
| */ |
| function getName() |
| { |
| return $this->name; |
| } |
| /** |
| * Retrieves data from memory in one chunk, or from disk in $buffer |
| * sized chunks. |
| * |
| * @return string The data |
| */ |
| function getData() |
| { |
| $buffer = 4096; |
| // Return data stored in memory |
| if (isset($this->_data)) |
| { |
| $tmp = $this->_data; |
| unset($this->_data); |
| $fh = $this->_filehandle; |
| if ($this->_using_tmpfile) { |
| fseek($fh, 0); |
| } |
| return($tmp); |
| } |
| // Return data stored on disk |
| if ($this->_using_tmpfile) |
| { |
| if ($tmp = fread($this->_filehandle, $buffer)) { |
| return($tmp); |
| } |
| } |
| // No data to return |
| return(''); |
| } |
| /** |
| * Set this worksheet as a selected worksheet, |
| * i.e. the worksheet has its tab highlighted. |
| * |
| * @access public |
| */ |
| function select() |
| { |
| $this->selected = 1; |
| } |
| /** |
| * Set this worksheet as the active worksheet, |
| * i.e. the worksheet that is displayed when the workbook is opened. |
| * Also set it as selected. |
| * |
| * @access public |
| */ |
| function activate() |
| { |
| $this->selected = 1; |
| $this->activesheet = $this->index; |
| } |
| /** |
| * Set this worksheet as the first visible sheet. |
| * This is necessary when there are a large number of worksheets and the |
| * activated worksheet is not visible on the screen. |
| * |
| * @access public |
| */ |
| function setFirstSheet() |
| { |
| $this->firstsheet = $this->index; |
| } |
| /** |
| * Set the worksheet protection flag |
| * to prevent accidental modification and to |
| * hide formulas if the locked and hidden format properties have been set. |
| * |
| * @access public |
| * @param string $password The password to use for protecting the sheet. |
| */ |
| function protect($password) |
| { |
| $this->_protect = 1; |
| $this->_password = $this->_encodePassword($password); |
| } |
| /** |
| * Set the width of a single column or a range of columns. |
| * |
| * @access public |
| * @param integer $firstcol first column on the range |
| * @param integer $lastcol last column on the range |
| * @param integer $width width to set |
| * @param mixed $format The optional XF format to apply to the columns |
| * @param integer $hidden The optional hidden atribute |
| */ |
| function setColumn($firstcol, $lastcol, $width, $format = 0, $hidden = 0) |
| { |
| $this->_colinfo[] = array($firstcol, $lastcol, $width, &$format, $hidden); |
| // Set width to zero if column is hidden |
| $width = ($hidden) ? 0 : $width; |
| for($col = $firstcol; $col <= $lastcol; $col++) { |
| $this->col_sizes[$col] = $width; |
| } |
| } |
| /** |
| * Set which cell or cells are selected in a worksheet |
| * |
| * @access public |
| * @param integer $first_row first row in the selected quadrant |
| * @param integer $first_column first column in the selected quadrant |
| * @param integer $last_row last row in the selected quadrant |
| * @param integer $last_column last column in the selected quadrant |
| */ |
| function setSelection($first_row,$first_column,$last_row,$last_column) |
| { |
| $this->_selection = array($first_row,$first_column,$last_row,$last_column); |
| } |
| /** |
| * Set panes and mark them as frozen. |
| * |
| * @access public |
| * @param array $panes This is the only parameter received and is composed of the following: |
| * 0 => Vertical split position, |
| * 1 => Horizontal split position |
| * 2 => Top row visible |
| * 3 => Leftmost column visible |
| * 4 => Active pane |
| */ |
| function freezePanes($panes) |
| { |
| $this->_frozen = 1; |
| $this->_panes = $panes; |
| } |
| /** |
| * Set panes and mark them as unfrozen. |
| * |
| * @access public |
| * @param array $panes This is the only parameter received and is composed of the following: |
| * 0 => Vertical split position, |
| * 1 => Horizontal split position |
| * 2 => Top row visible |
| * 3 => Leftmost column visible |
| * 4 => Active pane |
| */ |
| function thawPanes($panes) |
| { |
| $this->_frozen = 0; |
| $this->_panes = $panes; |
| } |
| /** |
| * Set the page orientation as portrait. |
| * |
| * @access public |
| */ |
| function setPortrait() |
| { |
| $this->_orientation = 1; |
| } |
| /** |
| * Set the page orientation as landscape. |
| * |
| * @access public |
| */ |
| function setLandscape() |
| { |
| $this->_orientation = 0; |
| } |
| /** |
| * Set the paper type. Ex. 1 = US Letter, 9 = A4 |
| * |
| * @access public |
| * @param integer $size The type of paper size to use |
| */ |
| function setPaper($size = 0) |
| { |
| $this->_paper_size = $size; |
| } |
| /** |
| * Set the page header caption and optional margin. |
| * |
| * @access public |
| * @param string $string The header text |
| * @param float $margin optional head margin in inches. |
| */ |
| function setHeader($string,$margin = 0.50) |
| { |
| if (strlen($string) >= 255) { |
| //carp 'Header string must be less than 255 characters'; |
| return; |
| } |
| $this->_header = $string; |
| $this->_margin_head = $margin; |
| } |
| /** |
| * Set the page footer caption and optional margin. |
| * |
| * @access public |
| * @param string $string The footer text |
| * @param float $margin optional foot margin in inches. |
| */ |
| function setFooter($string,$margin = 0.50) |
| { |
| if (strlen($string) >= 255) { |
| //carp 'Footer string must be less than 255 characters'; |
| return; |
| } |
| $this->_footer = $string; |
| $this->_margin_foot = $margin; |
| } |
| /** |
| * Center the page horinzontally. |
| * |
| * @access public |
| * @param integer $center the optional value for centering. Defaults to 1 (center). |
| */ |
| function centerHorizontally($center = 1) |
| { |
| $this->_hcenter = $center; |
| } |
| /** |
| * Center the page vertically. |
| * |
| * @access public |
| * @param integer $center the optional value for centering. Defaults to 1 (center). |
| */ |
| function centerVertically($center = 1) |
| { |
| $this->_vcenter = $center; |
| } |
| /** |
| * Set all the page margins to the same value in inches. |
| * |
| * @access public |
| * @param float $margin The margin to set in inches |
| */ |
| function setMargins($margin) |
| { |
| $this->setMarginLeft($margin); |
| $this->setMarginRight($margin); |
| $this->setMarginTop($margin); |
| $this->setMarginBottom($margin); |
| } |
| /** |
| * Set the left and right margins to the same value in inches. |
| * |
| * @access public |
| * @param float $margin The margin to set in inches |
| */ |
| function setMargins_LR($margin) |
| { |
| $this->setMarginLeft($margin); |
| $this->setMarginRight($margin); |
| } |
| /** |
| * Set the top and bottom margins to the same value in inches. |
| * |
| * @access public |
| * @param float $margin The margin to set in inches |
| */ |
| function setMargins_TB($margin) |
| { |
| $this->setMarginTop($margin); |
| $this->setMarginBottom($margin); |
| } |
| /** |
| * Set the left margin in inches. |
| * |
| * @access public |
| * @param float $margin The margin to set in inches |
| */ |
| function setMarginLeft($margin = 0.75) |
| { |
| $this->_margin_left = $margin; |
| } |
| /** |
| * Set the right margin in inches. |
| * |
| * @access public |
| * @param float $margin The margin to set in inches |
| */ |
| function setMarginRight($margin = 0.75) |
| { |
| $this->_margin_right = $margin; |
| } |
| /** |
| * Set the top margin in inches. |
| * |
| * @access public |
| * @param float $margin The margin to set in inches |
| */ |
| function setMarginTop($margin = 1.00) |
| { |
| $this->_margin_top = $margin; |
| } |
| /** |
| * Set the bottom margin in inches. |
| * |
| * @access public |
| * @param float $margin The margin to set in inches |
| */ |
| function setMarginBottom($margin = 1.00) |
| { |
| $this->_margin_bottom = $margin; |
| } |
| /** |
| * Set the rows to repeat at the top of each printed page. |
| * |
| * @access public |
| * @param integer $first_row First row to repeat |
| * @param integer $last_row Last row to repeat. Optional. |
| */ |
| function repeatRows($first_row, $last_row = NULL) |
| { |
| $this->title_rowmin = $first_row; |
| if (isset($last_row)) { //Second row is optional |
| $this->title_rowmax = $last_row; |
| } |
| else { |
| $this->title_rowmax = $first_row; |
| } |
| } |
| /** |
| * Set the columns to repeat at the left hand side of each printed page. |
| * |
| * @access public |
| * @param integer $first_col First column to repeat |
| * @param integer $last_col Last column to repeat. Optional. |
| */ |
| function repeatColumns($first_col, $last_col = NULL) |
| { |
| $this->title_colmin = $first_col; |
| if (isset($last_col)) { // Second col is optional |
| $this->title_colmax = $last_col; |
| } |
| else { |
| $this->title_colmax = $first_col; |
| } |
| } |
| /** |
| * Set the area of each worksheet that will be printed. |
| * |
| * @access public |
| * @param integer $first_row First row of the area to print |
| * @param integer $first_col First column of the area to print |
| * @param integer $last_row Last row of the area to print |
| * @param integer $last_col Last column of the area to print |
| */ |
| function printArea($first_row, $first_col, $last_row, $last_col) |
| { |
| $this->print_rowmin = $first_row; |
| $this->print_colmin = $first_col; |
| $this->print_rowmax = $last_row; |
| $this->print_colmax = $last_col; |
| } |
| /** |
| * Set the option to hide gridlines on the printed page. |
| * |
| * @access public |
| */ |
| function hideGridlines() |
| { |
| $this->_print_gridlines = 0; |
| } |
| /** |
| * Set the option to print the row and column headers on the printed page. |
| * |
| * @access public |
| * @param integer $print Whether to print the headers or not. Defaults to 1 (print). |
| */ |
| function printRowColHeaders($print = 1) |
| { |
| $this->_print_headers = $print; |
| } |
| /** |
| * Set the vertical and horizontal number of pages that will define the maximum area printed. |
| * It doesn't seem to work with OpenOffice. |
| * |
| * @access public |
| * @param integer $width Maximun width of printed area in pages |
| * @param integer $height Maximun heigth of printed area in pages |
| * @see setPrintScale() |
| */ |
| function fitToPages($width, $height) |
| { |
| $this->_fit_page = 1; |
| $this->_fit_width = $width; |
| $this->_fit_height = $height; |
| } |
| /** |
| * Store the horizontal page breaks on a worksheet (for printing). |
| * The breaks represent the row after which the break is inserted. |
| * |
| * @access public |
| * @param array $breaks Array containing the horizontal page breaks |
| */ |
| function setHPagebreaks($breaks) |
| { |
| foreach($breaks as $break) { |
| array_push($this->_hbreaks,$break); |
| } |
| } |
| /** |
| * Store the vertical page breaks on a worksheet (for printing). |
| * The breaks represent the column after which the break is inserted. |
| * |
| * @access public |
| * @param array $breaks Array containing the vertical page breaks |
| */ |
| function setVPagebreaks($breaks) |
| { |
| foreach($breaks as $break) { |
| array_push($this->_vbreaks,$break); |
| } |
| } |
| /** |
| * Set the worksheet zoom factor. |
| * |
| * @access public |
| * @param integer $scale The zoom factor |
| */ |
| function setZoom($scale = 100) |
| { |
| // Confine the scale to Excel's range |
| if ($scale < 10 or $scale > 400) |
| { |
| $this->raiseError("Zoom factor $scale outside range: 10 <= zoom <= 400"); |
| $scale = 100; |
| } |
| $this->_zoom = floor($scale); |
| } |
| /** |
| * Set the scale factor for the printed page. |
| * It turns off the "fit to page" option |
| * |
| * @access public |
| * @param integer $scale The optional scale factor. Defaults to 100 |
| */ |
| function setPrintScale($scale = 100) |
| { |
| // Confine the scale to Excel's range |
| if ($scale < 10 or $scale > 400) |
| { |
| $this->raiseError("Print scale $scale outside range: 10 <= zoom <= 400"); |
| $scale = 100; |
| } |
| // Turn off "fit to page" option |
| $this->_fit_page = 0; |
| $this->_print_scale = floor($scale); |
| } |
| /** |
| * Map to the appropriate write method acording to the token recieved. |
| * |
| * @access public |
| * @param integer $row The row of the cell we are writing to |
| * @param integer $col The column of the cell we are writing to |
| * @param mixed $token What we are writing |
| * @param mixed $format The optional format to apply to the cell |
| */ |
| function write($row, $col, $token, $format = 0) |
| { |
| // Check for a cell reference in A1 notation and substitute row and column |
| /*if ($_[0] =~ /^\D/) { |
| @_ = $this->_substituteCellref(@_); |
| }*/ |
| // Match number |
| if (preg_match("/^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/",$token)) { |
| return $this->writeNumber($row,$col,$token,$format); |
| } |
| // Match http or ftp URL |
| elseif (preg_match("/^[fh]tt?p:\/\//",$token)) { |
| return $this->writeUrl($row, $col, $token, $format); |
| } |
| // Match mailto: |
| elseif (preg_match("/^mailto:/",$token)) { |
| return $this->writeUrl($row, $col, $token, $format); |
| } |
| // Match internal or external sheet link |
| elseif (preg_match("/^(?:in|ex)ternal:/",$token)) { |
| return $this->writeUrl($row, $col, $token, $format); |
| } |
| // Match formula |
| elseif (preg_match("/^=/",$token)) { |
| return $this->writeFormula($row, $col, $token, $format); |
| } |
| // Match formula |
| elseif (preg_match("/^@/",$token)) { |
| return $this->writeFormula($row, $col, $token, $format); |
| } |
| // Match blank |
| elseif ($token == '') { |
| return $this->writeBlank($row,$col,$format); |
| } |
| // Default: match string |
| else { |
| return $this->writeString($row,$col,$token,$format); |
| } |
| } |
| /** |
| * Write an array of values as a row |
| * |
| * @access public |
| * @param |
| * @return |
| */ |
| function writeRow($row, $col, $val, $format=0) |
| { |
| if (is_array($val)) { |
| foreach($val as $v) { |
| if (is_array($v)) { |
| $this->writeCol($row, $col, $v, $format); |
| } else { |
| $this->write($row, $col, $v, $format); |
| } |
| $col++; |
| } |
| } else { |
| $retval = new PEAR_Error('$val needs to be an array'); |
| } |
| return($retval); |
| } |
| /** |
| * Write an array of values as a column |
| * |
| * @access public |
| * @param |
| * @return |
| */ |
| function writeCol($row, $col, $val, $format=0) |
| { |
| if (is_array($val)) { |
| foreach($val as $v) { |
| $this->write($row, $col, $v, $format); |
| $row++; |
| } |
| } else { |
| $retval = new PEAR_Error('$val needs to be an array'); |
| } |
| return($retval); |
| } |
| /** |
| * Returns an index to the XF record in the workbook |
| * |
| * @access private |
| * @param mixed &$format The optional XF format |
| * @return integer The XF record index |
| */ |
| function _XF(&$format) |
| { |
| if ($format != 0) { |
| return($format->getXfIndex()); |
| } |
| else { |
| return(0x0F); |
| } |
| } |
| /****************************************************************************** |
| ******************************************************************************* |
| * |
| * Internal methods |
| */ |
| /** |
| * Store Worksheet data in memory using the parent's class append() or to a |
| * temporary file, the default. |
| * |
| * @access private |
| * @param string $data The binary data to append |
| */ |
| function _append($data) |
| { |
| if ($this->_using_tmpfile) |
| { |
| // Add CONTINUE records if necessary |
| if (strlen($data) > $this->_limit) { |
| $data = $this->_addContinue($data); |
| } |
| fwrite($this->_filehandle,$data); |
| $this->_datasize += strlen($data); |
| } |
| else { |
| parent::_append($data); |
| } |
| } |
| /** |
| * Substitute an Excel cell reference in A1 notation for zero based row and |
| * column values in an argument list. |
| * |
| * Ex: ("A4", "Hello") is converted to (3, 0, "Hello"). |
| * |
| * @access private |
| * @param string $cell The cell reference. Or range of cells. |
| * @return array |
| */ |
| function _substituteCellref($cell) |
| { |
| $cell = strtoupper($cell); |
| // Convert a column range: 'A:A' or 'B:G' |
| if (preg_match("/([A-I]?[A-Z]):([A-I]?[A-Z])/",$cell,$match)) { |
| list($no_use, $col1) = $this->_cellToRowcol($match[1] .'1'); // Add a dummy row |
| list($no_use, $col2) = $this->_cellToRowcol($match[2] .'1'); // Add a dummy row |
| return(array($col1, $col2)); |
| } |
| // Convert a cell range: 'A1:B7' |
| if (preg_match("/\$?([A-I]?[A-Z]\$?\d+):\$?([A-I]?[A-Z]\$?\d+)/",$cell,$match)) { |
| list($row1, $col1) = $this->_cellToRowcol($match[1]); |
| list($row2, $col2) = $this->_cellToRowcol($match[2]); |
| return(array($row1, $col1, $row2, $col2)); |
| } |
| // Convert a cell reference: 'A1' or 'AD2000' |
| if (preg_match("/\$?([A-I]?[A-Z]\$?\d+)/",$cell)) { |
| list($row1, $col1) = $this->_cellToRowcol($match[1]); |
| return(array($row1, $col1)); |
| } |
| // TODO use real error codes |
| $this->raiseError("Unknown cell reference $cell", 0, PEAR_ERROR_DIE); |
| } |
| /** |
| * Convert an Excel cell reference in A1 notation to a zero based row and column |
| * reference; converts C1 to (0, 2). |
| * |
| * @access private |
| * @param string $cell The cell reference. |
| * @return array containing (row, column) |
| */ |
| function _cellToRowcol($cell) |
| { |
| preg_match("/\$?([A-I]?[A-Z])\$?(\d+)/",$cell,$match); |
| $col = $match[1]; |
| $row = $match[2]; |
| // Convert base26 column string to number |
| $chars = split('', $col); |
| $expn = 0; |
| $col = 0; |
| while ($chars) { |
| $char = array_pop($chars); // LS char first |
| $col += (ord($char) -ord('A') +1) * pow(26,$expn); |
| $expn++; |
| } |
| // Convert 1-index to zero-index |
| $row--; |
| $col--; |
| return(array($row, $col)); |
| } |
| /** |
| * Based on the algorithm provided by Daniel Rentz of OpenOffice. |
| * |
| * @access private |
| * @param string $plaintext The password to be encoded in plaintext. |
| * @return string The encoded password |
| */ |
| function _encodePassword($plaintext) |
| { |
| $password = 0x0000; |
| $i = 1; // char position |
| // split the plain text password in its component characters |
| $chars = preg_split('//', $plaintext, -1, PREG_SPLIT_NO_EMPTY); |
| foreach($chars as $char) |
| { |
| $value = ord($char) << $i; // shifted ASCII value |
| $rotated_bits = $value >> 15; // rotated bits beyond bit 15 |
| $value &= 0x7fff; // first 15 bits |
| $password ^= ($value | $rotated_bits); |
| $i++; |
| } |
| $password ^= strlen($plaintext); |
| $password ^= 0xCE4B; |
| return($password); |
| } |
| /****************************************************************************** |
| ******************************************************************************* |
| * |
| * BIFF RECORDS |
| */ |
| /** |
| * Write a double to the specified row and column (zero indexed). |
| * An integer can be written as a double. Excel will display an |
| * integer. $format is optional. |
| * |
| * Returns 0 : normal termination |
| * -2 : row or column out of range |
| * |
| * @access public |
| * @param integer $row Zero indexed row |
| * @param integer $col Zero indexed column |
| * @param float $num The number to write |
| * @param mixed $format The optional XF format |
| * @return integer |
| */ |
| function writeNumber($row, $col, $num, $format = 0) |
| { |
| $record = 0x0203; // Record identifier |
| $length = 0x000E; // Number of bytes to follow |
| $xf = $this->_XF($format); // The cell format |
| // Check that row and col are valid and store max and min values |
| if ($row >= $this->_xls_rowmax) |
| { |
| return(-2); |
| } |
| if ($col >= $this->_xls_colmax) |
| { |
| return(-2); |
| } |
| if ($row < $this->_dim_rowmin) |
| { |
| $this->_dim_rowmin = $row; |
| } |
| if ($row > $this->_dim_rowmax) |
| { |
| $this->_dim_rowmax = $row; |
| } |
| if ($col < $this->_dim_colmin) |
| { |
| $this->_dim_colmin = $col; |
| } |
| if ($col > $this->_dim_colmax) |
| { |
| $this->_dim_colmax = $col; |
| } |
| $header = pack("vv", $record, $length); |
| $data = pack("vvv", $row, $col, $xf); |
| $xl_double = pack("d", $num); |
| if ($this->_byte_order) // if it's Big Endian |
| { |
| $xl_double = strrev($xl_double); |
| } |
| $this->_append($header.$data.$xl_double); |
| return(0); |
| } |
| /** |
| * Write a string to the specified row and column (zero indexed). |
| * NOTE: there is an Excel 5 defined limit of 255 characters. |
| * $format is optional. |
| * Returns 0 : normal termination |
| * -2 : row or column out of range |
| * -3 : long string truncated to 255 chars |
| * |
| * @access public |
| * @param integer $row Zero indexed row |
| * @param integer $col Zero indexed column |
| * @param string $str The string to write |
| * @param mixed $format The XF format for the cell |
| * @return integer |
| */ |
| function writeString($row, $col, $str, $format = 0) |
| { |
| $strlen = strlen($str); |
| $record = 0x0204; // Record identifier |
| $length = 0x0008 + $strlen; // Bytes to follow |
| $xf = $this->_XF($format); // The cell format |
| $str_error = 0; |
| // Check that row and col are valid and store max and min values |
| if ($row >= $this->_xls_rowmax) |
| { |
| return(-2); |
| } |
| if ($col >= $this->_xls_colmax) |
| { |
| return(-2); |
| } |
| if ($row < $this->_dim_rowmin) |
| { |
| $this->_dim_rowmin = $row; |
| } |
| if ($row > $this->_dim_rowmax) |
| { |
| $this->_dim_rowmax = $row; |
| } |
| if ($col < $this->_dim_colmin) |
| { |
| $this->_dim_colmin = $col; |
| } |
| if ($col > $this->_dim_colmax) |
| { |
| $this->_dim_colmax = $col; |
| } |
| if ($strlen > $this->_xls_strmax) // LABEL must be < 255 chars |
| { |
| $str = substr($str, 0, $this->_xls_strmax); |
| $length = 0x0008 + $this->_xls_strmax; |
| $strlen = $this->_xls_strmax; |
| $str_error = -3; |
| } |
| $header = pack("vv", $record, $length); |
| $data = pack("vvvv", $row, $col, $xf, $strlen); |
| $this->_append($header.$data.$str); |
| return($str_error); |
| } |
| /** |
| * Writes a note associated with the cell given by the row and column. |
| * NOTE records don't have a length limit. |
| * |
| * @access public |
| * @param integer $row Zero indexed row |
| * @param integer $col Zero indexed column |
| * @param string $note The note to write |
| */ |
| function writeNote($row, $col, $note) |
| { |
| $note_length = strlen($note); |
| $record = 0x001C; // Record identifier |
| $max_length = 2048; // Maximun length for a NOTE record |
| //$length = 0x0006 + $note_length; // Bytes to follow |
| // Check that row and col are valid and store max and min values |
| if ($row >= $this->_xls_rowmax) |
| { |
| return(-2); |
| } |
| if ($col >= $this->_xls_colmax) |
| { |
| return(-2); |
| } |
| if ($row < $this->_dim_rowmin) |
| { |
| $this->_dim_rowmin = $row; |
| } |
| if ($row > $this->_dim_rowmax) |
| { |
| $this->_dim_rowmax = $row; |
| } |
| if ($col < $this->_dim_colmin) |
| { |
| $this->_dim_colmin = $col; |
| } |
| if ($col > $this->_dim_colmax) |
| { |
| $this->_dim_colmax = $col; |
| } |
| // Length for this record is no more than 2048 + 6 |
| $length = 0x0006 + min($note_length, 2048); |
| $header = pack("vv", $record, $length); |
| $data = pack("vvv", $row, $col, $note_length); |
| $this->_append($header.$data.substr($note, 0, 2048)); |
| for($i = $max_length; $i < $note_length; $i += $max_length) |
| { |
| $chunk = substr($note, $i, $max_length); |
| $length = 0x0006 + strlen($chunk); |
| $header = pack("vv", $record, $length); |
| $data = pack("vvv", -1, 0, strlen($chunk)); |
| $this->_append($header.$data.$chunk); |
| } |
| return(0); |
| } |
| /** |
| * Write a blank cell to the specified row and column (zero indexed). |
| * A blank cell is used to specify formatting without adding a string |
| * or a number. |
| * |
| * A blank cell without a format serves no purpose. Therefore, we don't write |
| * a BLANK record unless a format is specified. |
| * |
| * Returns 0 : normal termination (including no format) |
| * -1 : insufficient number of arguments |
| * -2 : row or column out of range |
| * |
| * @access public |
| * @param integer $row Zero indexed row |
| * @param integer $col Zero indexed column |
| * @param mixed $format The XF format |
| */ |
| function writeBlank($row, $col, $format) |
| { |
| // Don't write a blank cell unless it has a format |
| if ($format == 0) |
| { |
| return(0); |
| } |
| $record = 0x0201; // Record identifier |
| $length = 0x0006; // Number of bytes to follow |
| $xf = $this->_XF($format); // The cell format |
| // Check that row and col are valid and store max and min values |
| if ($row >= $this->_xls_rowmax) |
| { |
| return(-2); |
| } |
| if ($col >= $this->_xls_colmax) |
| { |
| return(-2); |
| } |
| if ($row < $this->_dim_rowmin) |
| { |
| $this->_dim_rowmin = $row; |
| } |
| if ($row > $this->_dim_rowmax) |
| { |
| $this->_dim_rowmax = $row; |
| } |
| if ($col < $this->_dim_colmin) |
| { |
| $this->_dim_colmin = $col; |
| } |
| if ($col > $this->_dim_colmax) |
| { |
| $this->_dim_colmax = $col; |
| } |
| $header = pack("vv", $record, $length); |
| $data = pack("vvv", $row, $col, $xf); |
| $this->_append($header.$data); |
| return 0; |
| } |
| /** |
| * Write a formula to the specified row and column (zero indexed). |
| * The textual representation of the formula is passed to the parser in |
| * Parser.php which returns a packed binary string. |
| * |
| * Returns 0 : normal termination |
| * -1 : formula errors (bad formula) |
| * -2 : row or column out of range |
| * |
| * @access public |
| * @param integer $row Zero indexed row |
| * @param integer $col Zero indexed column |
| * @param string $formula The formula text string |
| * @param mixed $format The optional XF format |
| * @return integer |
| */ |
| function writeFormula($row, $col, $formula, $format = 0) |
| { |
| $record = 0x0006; // Record identifier |
| // Excel normally stores the last calculated value of the formula in $num. |
| // Clearly we are not in a position to calculate this a priori. Instead |
| // we set $num to zero and set the option flags in $grbit to ensure |
| // automatic calculation of the formula when the file is opened. |
| // |
| $xf = $this->_XF($format); // The cell format |
| $num = 0x00; // Current value of formula |
| $grbit = 0x03; // Option flags |
| $chn = 0x0000; // Must be zero |
| // Check that row and col are valid and store max and min values |
| if ($row >= $this->_xls_rowmax) |
| { |
| return(-2); |
| } |
| if ($col >= $this->_xls_colmax) |
| { |
| return(-2); |
| } |
| if ($row < $this->_dim_rowmin) |
| { |
| $this->_dim_rowmin = $row; |
| } |
| if ($row > $this->_dim_rowmax) |
| { |
| $this->_dim_rowmax = $row; |
| } |
| if ($col < $this->_dim_colmin) |
| { |
| $this->_dim_colmin = $col; |
| } |
| if ($col > $this->_dim_colmax) |
| { |
| $this->_dim_colmax = $col; |
| } |
| // Strip the '=' or '@' sign at the beginning of the formula string |
| if (preg_match("/^=/",$formula)) { |
| $formula = preg_replace("/(^=)/","",$formula); |
| } |
| elseif (preg_match("/^@/",$formula)) { |
| $formula = preg_replace("/(^@)/","",$formula); |
| } |
| else |
| { |
| // Error handling |
| $this->writeString($row, $col, 'Unrecognised character for formula'); |
| return -1; |
| } |
| // Parse the formula using the parser in Parser.php |
| $error = $this->_parser->parse($formula); |
| if ($this->isError($error)) |
| { |
| $this->writeString($row, $col, $error->getMessage()); |
| return -1; |
| } |
| $formula = $this->_parser->toReversePolish(); |
| if ($this->isError($formula)) |
| { |
| $this->writeString($row, $col, $formula->getMessage()); |
| return -1; |
| } |
| $formlen = strlen($formula); // Length of the binary string |
| $length = 0x16 + $formlen; // Length of the record data |
| $header = pack("vv", $record, $length); |
| $data = pack("vvvdvVv", $row, $col, $xf, $num, |
| $grbit, $chn, $formlen); |
| $this->_append($header.$data.$formula); |
| return 0; |
| } |
| /** |
| * Write a hyperlink. |
| * This is comprised of two elements: the visible label and |
| * the invisible link. The visible label is the same as the link unless an |
| * alternative string is specified. The label is written using the |
| * writeString() method. Therefore the 255 characters string limit applies. |
| * $string and $format are optional. |
| * |
| * The hyperlink can be to a http, ftp, mail, internal sheet (not yet), or external |
| * directory url. |
| * |
| * Returns 0 : normal termination |
| * -2 : row or column out of range |
| * -3 : long string truncated to 255 chars |
| * |
| * @access public |
| * @param integer $row Row |
| * @param integer $col Column |
| * @param string $url URL string |
| * @param string $string Alternative label |
| * @param mixed $format The cell format |
| * @return integer |
| */ |
| function writeUrl($row, $col, $url, $string = '', $format = 0) |
| { |
| // Add start row and col to arg list |
| return($this->_writeUrl_range($row, $col, $row, $col, $url, $string, $format)); |
| } |
| /** |
| * This is the more general form of writeUrl(). It allows a hyperlink to be |
| * written to a range of cells. This function also decides the type of hyperlink |
| * to be written. These are either, Web (http, ftp, mailto), Internal |
| * (Sheet1!A1) or external ('c:\temp\foo.xls#Sheet1!A1'). |
| * |
| * @access private |
| * @see writeUrl() |
| * @param integer $row1 Start row |
| * @param integer $col1 Start column |
| * @param integer $row2 End row |
| * @param integer $col2 End column |
| * @param string $url URL string |
| * @param string $string Alternative label |
| * @param mixed $format The cell format |
| * @return integer |
| */ |
| function _writeUrl_range($row1, $col1, $row2, $col2, $url, $string = '', $format = 0) |
| { |
| // Check for internal/external sheet links or default to web link |
| if (preg_match('[^internal:]', $url)) { |
| return($this->_writeUrlInternal($row1, $col1, $row2, $col2, $url, $string, $format)); |
| } |
| if (preg_match('[^external:]', $url)) { |
| return($this->_writeUrlExternal($row1, $col1, $row2, $col2, $url, $string, $format)); |
| } |
| return($this->_writeUrlWeb($row1, $col1, $row2, $col2, $url, $string, $format)); |
| } |
| /** |
| * Used to write http, ftp and mailto hyperlinks. |
| * The link type ($options) is 0x03 is the same as absolute dir ref without |
| * sheet. However it is differentiated by the $unknown2 data stream. |
| * |
| * @access private |
| * @see writeUrl() |
| * @param integer $row1 Start row |
| * @param integer $col1 Start column |
| * @param integer $row2 End row |
| * @param integer $col2 End column |
| * @param string $url URL string |
| * @param string $str Alternative label |
| * @param mixed $format The cell format |
| * @return integer |
| */ |
| function _writeUrlWeb($row1, $col1, $row2, $col2, $url, $str, $format = 0) |
| { |
| $record = 0x01B8; // Record identifier |
| $length = 0x00000; // Bytes to follow |
| if ($format == 0) { |
| $format = $this->_url_format; |
| } |
| // Write the visible label using the writeString() method. |
| if ($str == '') { |
| $str = $url; |
| } |
| $str_error = $this->writeString($row1, $col1, $str, $format); |
| if (($str_error == -2) or ($str_error == -3)) { |
| return $str_error; |
| } |
| // Pack the undocumented parts of the hyperlink stream |
| $unknown1 = pack("H*", "D0C9EA79F9BACE118C8200AA004BA90B02000000"); |
| $unknown2 = pack("H*", "E0C9EA79F9BACE118C8200AA004BA90B"); |
| // Pack the option flags |
| $options = pack("V", 0x03); |
| // Convert URL to a null terminated wchar string |
| $url = join("\0", preg_split("''", $url, -1, PREG_SPLIT_NO_EMPTY)); |
| $url = $url . "\0\0\0"; |
| // Pack the length of the URL |
| $url_len = pack("V", strlen($url)); |
| // Calculate the data length |
| $length = 0x34 + strlen($url); |
| // Pack the header data |
| $header = pack("vv", $record, $length); |
| $data = pack("vvvv", $row1, $row2, $col1, $col2); |
| // Write the packed data |
| $this->_append( $header. $data. |
| $unknown1. $options. |
| $unknown2. $url_len. $url); |
| return($str_error); |
| } |
| /** |
| * Used to write internal reference hyperlinks such as "Sheet1!A1". |
| * |
| * @access private |
| * @see writeUrl() |
| * @param integer $row1 Start row |
| * @param integer $col1 Start column |
| * @param integer $row2 End row |
| * @param integer $col2 End column |
| * @param string $url URL string |
| * @param string $str Alternative label |
| * @param mixed $format The cell format |
| * @return integer |
| */ |
| function _writeUrlInternal($row1, $col1, $row2, $col2, $url, $str, $format = 0) |
| { |
| $record = 0x01B8; // Record identifier |
| $length = 0x00000; // Bytes to follow |
| if ($format == 0) { |
| $format = $this->_url_format; |
| } |
| // Strip URL type |
| $url = preg_replace('s[^internal:]', '', $url); |
| // Write the visible label |
| if ($str == '') { |
| $str = $url; |
| } |
| $str_error = $this->writeString($row1, $col1, $str, $format); |
| if (($str_error == -2) or ($str_error == -3)) { |
| return $str_error; |
| } |
| // Pack the undocumented parts of the hyperlink stream |
| $unknown1 = pack("H*", "D0C9EA79F9BACE118C8200AA004BA90B02000000"); |
| // Pack the option flags |
| $options = pack("V", 0x08); |
| // Convert the URL type and to a null terminated wchar string |
| $url = join("\0", preg_split("''", $url, -1, PREG_SPLIT_NO_EMPTY)); |
| $url = $url . "\0\0\0"; |
| // Pack the length of the URL as chars (not wchars) |
| $url_len = pack("V", floor(strlen($url)/2)); |
| // Calculate the data length |
| $length = 0x24 + strlen($url); |
| // Pack the header data |
| $header = pack("vv", $record, $length); |
| $data = pack("vvvv", $row1, $row2, $col1, $col2); |
| // Write the packed data |
| $this->_append($header. $data. |
| $unknown1. $options. |
| $url_len. $url); |
| return($str_error); |
| } |
| /** |
| * Write links to external directory names such as 'c:\foo.xls', |
| * c:\foo.xls#Sheet1!A1', '../../foo.xls'. and '../../foo.xls#Sheet1!A1'. |
| * |
| * Note: Excel writes some relative links with the $dir_long string. We ignore |
| * these cases for the sake of simpler code. |
| * |
| * @access private |
| * @see writeUrl() |
| * @param integer $row1 Start row |
| * @param integer $col1 Start column |
| * @param integer $row2 End row |
| * @param integer $col2 End column |
| * @param string $url URL string |
| * @param string $str Alternative label |
| * @param mixed $format The cell format |
| * @return integer |
| */ |
| function _writeUrlExternal($row1, $col1, $row2, $col2, $url, $str, $format = 0) |
| { |
| // Network drives are different. We will handle them separately |
| // MS/Novell network drives and shares start with \\ |
| if (preg_match('[^external:\\\\]', $url)) { |
| return; //($this->_writeUrlExternal_net($row1, $col1, $row2, $col2, $url, $str, $format)); |
| } |
| $record = 0x01B8; // Record identifier |
| $length = 0x00000; // Bytes to follow |
| if ($format == 0) { |
| $format = $this->_url_format; |
| } |
| // Strip URL type and change Unix dir separator to Dos style (if needed) |
| // |
| $url = preg_replace('[^external:]', '', $url); |
| $url = preg_replace('[/]', "\\", $url); |
| // Write the visible label |
| if ($str == '') { |
| $str = preg_replace('[\#]', ' - ', $url); |
| } |
| $str_error = $this->writeString($row1, $col1, $str, $format); |
| if (($str_error == -2) or ($str_error == -3)) { |
| return $str_error; |
| } |
| // Determine if the link is relative or absolute: |
| // relative if link contains no dir separator, "somefile.xls" |
| // relative if link starts with up-dir, "..\..\somefile.xls" |
| // otherwise, absolute |
| $absolute = 0x02; // Bit mask |
| if (!preg_match('[\\]', $url)) { |
| $absolute = 0x00; |
| } |
| if (preg_match('[^\.\.\\]', $url)) { |
| $absolute = 0x00; |
| } |
| // Determine if the link contains a sheet reference and change some of the |
| // parameters accordingly. |
| // Split the dir name and sheet name (if it exists) |
| list($dir_long , $sheet) = split('/\#/', $url); |
| $link_type = 0x01 | $absolute; |
| if (isset($sheet)) { |
| $link_type |= 0x08; |
| $sheet_len = pack("V", strlen($sheet) + 0x01); |
| $sheet = join("\0", split('', $sheet)); |
| $sheet .= "\0\0\0"; |
| } |
| else { |
| $sheet_len = ''; |
| $sheet = ''; |
| } |
| // Pack the link type |
| $link_type = pack("V", $link_type); |
| // Calculate the up-level dir count e.g.. (..\..\..\ == 3) |
| $up_count = preg_match_all("/\.\.\\/", $dir_long, $useless); |
| $up_count = pack("v", $up_count); |
| // Store the short dos dir name (null terminated) |
| $dir_short = preg_replace('/\.\.\\/', '', $dir_long) . "\0"; |
| // Store the long dir name as a wchar string (non-null terminated) |
| $dir_long = join("\0", split('', $dir_long)); |
| $dir_long = $dir_long . "\0"; |
| // Pack the lengths of the dir strings |
| $dir_short_len = pack("V", strlen($dir_short) ); |
| $dir_long_len = pack("V", strlen($dir_long) ); |
| $stream_len = pack("V", strlen($dir_long) + 0x06); |
| // Pack the undocumented parts of the hyperlink stream |
| $unknown1 = pack("H*",'D0C9EA79F9BACE118C8200AA004BA90B02000000' ); |
| $unknown2 = pack("H*",'0303000000000000C000000000000046' ); |
| $unknown3 = pack("H*",'FFFFADDE000000000000000000000000000000000000000'); |
| $unknown4 = pack("v", 0x03 ); |
| // Pack the main data stream |
| $data = pack("vvvv", $row1, $row2, $col1, $col2) . |
| $unknown1 . |
| $link_type . |
| $unknown2 . |
| $up_count . |
| $dir_short_len. |
| $dir_short . |
| $unknown3 . |
| $stream_len . |
| $dir_long_len . |
| $unknown4 . |
| $dir_long . |
| $sheet_len . |
| $sheet ; |
| // Pack the header data |
| $length = strlen($data); |
| $header = pack("vv", $record, $length); |
| // Write the packed data |
| $this->_append($header. $data); |
| return($str_error); |
| } |
| /** |
| * This method is used to set the height and format for a row. |
| * |
| * @access public |
| * @param integer $row The row to set |
| * @param integer $height Height we are giving to the row. |
| * Use NULL to set XF without setting height |
| * @param mixed $format XF format we are giving to the row |
| */ |
| function setRow($row, $height, $format = 0) |
| { |
| $record = 0x0208; // Record identifier |
| $length = 0x0010; // Number of bytes to follow |
| $colMic = 0x0000; // First defined column |
| $colMac = 0x0000; // Last defined column |
| $irwMac = 0x0000; // Used by Excel to optimise loading |
| $reserved = 0x0000; // Reserved |
| $grbit = 0x01C0; // Option flags. (monkey) see $1 do |
| $ixfe = $this->_XF($format); // XF index |
| // Use setRow($row, NULL, $XF) to set XF format without setting height |
| if ($height != NULL) { |
| $miyRw = $height * 20; // row height |
| } |
| else { |
| $miyRw = 0xff; // default row height is 256 |
| } |
| $header = pack("vv", $record, $length); |
| $data = pack("vvvvvvvv", $row, $colMic, $colMac, $miyRw, |
| $irwMac,$reserved, $grbit, $ixfe); |
| $this->_append($header.$data); |
| } |
| /** |
| * Writes Excel DIMENSIONS to define the area in which there is data. |
| * |
| * @access private |
| */ |
| function storeDimensions() |
| { |
| $record = 0x0000; // Record identifier |
| $length = 0x000A; // Number of bytes to follow |
| $row_min = $this->_dim_rowmin; // First row |
| $row_max = $this->_dim_rowmax; // Last row plus 1 |
| $col_min = $this->_dim_colmin; // First column |
| $col_max = $this->_dim_colmax; // Last column plus 1 |
| $reserved = 0x0000; // Reserved by Excel |
| $header = pack("vv", $record, $length); |
| $data = pack("vvvvv", $row_min, $row_max, |
| $col_min, $col_max, $reserved); |
| $this->_prepend($header.$data); |
| } |
| /** |
| * Write BIFF record Window2. |
| * |
| * @access private |
| */ |
| function _storeWindow2() |
| { |
| $record = 0x023E; // Record identifier |
| $length = 0x000A; // Number of bytes to follow |
| $grbit = 0x00B6; // Option flags |
| $rwTop = 0x0000; // Top row visible in window |
| $colLeft = 0x0000; // Leftmost column visible in window |
| $rgbHdr = 0x00000000; // Row/column heading and gridline color |
| // The options flags that comprise $grbit |
| $fDspFmla = 0; // 0 - bit |
| $fDspGrid = 1; // 1 |
| $fDspRwCol = 1; // 2 |
| $fFrozen = $this->_frozen; // 3 |
| $fDspZeros = 1; // 4 |
| $fDefaultHdr = 1; // 5 |
| $fArabic = 0; // 6 |
| $fDspGuts = 1; // 7 |
| $fFrozenNoSplit = 0; // 0 - bit |
| $fSelected = $this->selected; // 1 |
| $fPaged = 1; // 2 |
| $grbit = $fDspFmla; |
| $grbit |= $fDspGrid << 1; |
| $grbit |= $fDspRwCol << 2; |
| $grbit |= $fFrozen << 3; |
| $grbit |= $fDspZeros << 4; |
| $grbit |= $fDefaultHdr << 5; |
| $grbit |= $fArabic << 6; |
| $grbit |= $fDspGuts << 7; |
| $grbit |= $fFrozenNoSplit << 8; |
| $grbit |= $fSelected << 9; |
| $grbit |= $fPaged << 10; |
| $header = pack("vv", $record, $length); |
| $data = pack("vvvV", $grbit, $rwTop, $colLeft, $rgbHdr); |
| $this->_append($header.$data); |
| } |
| /** |
| * Write BIFF record DEFCOLWIDTH if COLINFO records are in use. |
| * |
| * @access private |
| */ |
| function _storeDefcol() |
| { |
| $record = 0x0055; // Record identifier |
| $length = 0x0002; // Number of bytes to follow |
| $colwidth = 0x0008; // Default column width |
| $header = pack("vv", $record, $length); |
| $data = pack("v", $colwidth); |
| $this->_prepend($header.$data); |
| } |
| /** |
| * Write BIFF record COLINFO to define column widths |
| * |
| * Note: The SDK says the record length is 0x0B but Excel writes a 0x0C |
| * length record. |
| * |
| * @access private |
| * @param array $col_array This is the only parameter received and is composed of the following: |
| * 0 => First formatted column, |
| * 1 => Last formatted column, |
| * 2 => Col width (8.43 is Excel default), |
| * 3 => The optional XF format of the column, |
| * 4 => Option flags. |
| */ |
| function _storeColinfo($col_array) |
| { |
| if (isset($col_array[0])) { |
| $colFirst = $col_array[0]; |
| } |
| if (isset($col_array[1])) { |
| $colLast = $col_array[1]; |
| } |
| if (isset($col_array[2])) { |
| $coldx = $col_array[2]; |
| } |
| else { |
| $coldx = 8.43; |
| } |
| if (isset($col_array[3])) { |
| $format = $col_array[3]; |
| } |
| else { |
| $format = 0; |
| } |
| if (isset($col_array[4])) { |
| $grbit = $col_array[4]; |
| } |
| else { |
| $grbit = 0; |
| } |
| $record = 0x007D; // Record identifier |
| $length = 0x000B; // Number of bytes to follow |
| $coldx += 0.72; // Fudge. Excel subtracts 0.72 !? |
| $coldx *= 256; // Convert to units of 1/256 of a char |
| $ixfe = $this->_XF($format); |
| $reserved = 0x00; // Reserved |
| $header = pack("vv", $record, $length); |
| $data = pack("vvvvvC", $colFirst, $colLast, $coldx, |
| $ixfe, $grbit, $reserved); |
| $this->_prepend($header.$data); |
| } |
| /** |
| * Write BIFF record SELECTION. |
| * |
| * @access private |
| * @param array $array array containing ($rwFirst,$colFirst,$rwLast,$colLast) |
| * @see setSelection() |
| */ |
| function _storeSelection($array) |
| { |
| list($rwFirst,$colFirst,$rwLast,$colLast) = $array; |
| $record = 0x001D; // Record identifier |
| $length = 0x000F; // Number of bytes to follow |
| $pnn = $this->_active_pane; // Pane position |
| $rwAct = $rwFirst; // Active row |
| $colAct = $colFirst; // Active column |
| $irefAct = 0; // Active cell ref |
| $cref = 1; // Number of refs |
| if (!isset($rwLast)) { |
| $rwLast = $rwFirst; // Last row in reference |
| } |
| if (!isset($colLast)) { |
| $colLast = $colFirst; // Last col in reference |
| } |
| // Swap last row/col for first row/col as necessary |
| if ($rwFirst > $rwLast) |
| { |
| list($rwFirst, $rwLast) = array($rwLast, $rwFirst); |
| } |
| if ($colFirst > $colLast) |
| { |
| list($colFirst, $colLast) = array($colLast, $colFirst); |
| } |
| $header = pack("vv", $record, $length); |
| $data = pack("CvvvvvvCC", $pnn, $rwAct, $colAct, |
| $irefAct, $cref, |
| $rwFirst, $rwLast, |
| $colFirst, $colLast); |
| $this->_append($header.$data); |
| } |
| /** |
| * Write BIFF record EXTERNCOUNT to indicate the number of external sheet |
| * references in a worksheet. |
| * |
| * Excel only stores references to external sheets that are used in formulas. |
| * For simplicity we store references to all the sheets in the workbook |
| * regardless of whether they are used or not. This reduces the overall |
| * complexity and eliminates the need for a two way dialogue between the formula |
| * parser the worksheet objects. |
| * |
| * @access private |
| * @param integer $count The number of external sheet references in this worksheet |
| */ |
| function _storeExterncount($count) |
| { |
| $record = 0x0016; // Record identifier |
| $length = 0x0002; // Number of bytes to follow |
| $header = pack("vv", $record, $length); |
| $data = pack("v", $count); |
| $this->_prepend($header.$data); |
| } |
| /** |
| * Writes the Excel BIFF EXTERNSHEET record. These references are used by |
| * formulas. A formula references a sheet name via an index. Since we store a |
| * reference to all of the external worksheets the EXTERNSHEET index is the same |
| * as the worksheet index. |
| * |
| * @access private |
| * @param string $sheetname The name of a external worksheet |
| */ |
| function _storeExternsheet($sheetname) |
| { |
| $record = 0x0017; // Record identifier |
| // References to the current sheet are encoded differently to references to |
| // external sheets. |
| // |
| if ($this->name == $sheetname) { |
| $sheetname = ''; |
| $length = 0x02; // The following 2 bytes |
| $cch = 1; // The following byte |
| $rgch = 0x02; // Self reference |
| } |
| else { |
| $length = 0x02 + strlen($sheetname); |
| $cch = strlen($sheetname); |
| $rgch = 0x03; // Reference to a sheet in the current workbook |
| } |
| $header = pack("vv", $record, $length); |
| $data = pack("CC", $cch, $rgch); |
| $this->_prepend($header.$data.$sheetname); |
| } |
| /** |
| * Writes the Excel BIFF PANE record. |
| * The panes can either be frozen or thawed (unfrozen). |
| * Frozen panes are specified in terms of an integer number of rows and columns. |
| * Thawed panes are specified in terms of Excel's units for rows and columns. |
| * |
| * @access private |
| * @param array $panes This is the only parameter received and is composed of the following: |
| * 0 => Vertical split position, |
| * 1 => Horizontal split position |
| * 2 => Top row visible |
| * 3 => Leftmost column visible |
| * 4 => Active pane |
| */ |
| function _storePanes($panes) |
| { |
| $y = $panes[0]; |
| $x = $panes[1]; |
| $rwTop = $panes[2]; |
| $colLeft = $panes[3]; |
| if (count($panes) > 4) { // if Active pane was received |
| $pnnAct = $panes[4]; |
| } |
| else { |
| $pnnAct = NULL; |
| } |
| $record = 0x0041; // Record identifier |
| $length = 0x000A; // Number of bytes to follow |
| // Code specific to frozen or thawed panes. |
| if ($this->_frozen) |
| { |
| // Set default values for $rwTop and $colLeft |
| if (!isset($rwTop)) { |
| $rwTop = $y; |
| } |
| if (!isset($colLeft)) { |
| $colLeft = $x; |
| } |
| } |
| else |
| { |
| // Set default values for $rwTop and $colLeft |
| if (!isset($rwTop)) { |
| $rwTop = 0; |
| } |
| if (!isset($colLeft)) { |
| $colLeft = 0; |
| } |
| // Convert Excel's row and column units to the internal units. |
| // The default row height is 12.75 |
| // The default column width is 8.43 |
| // The following slope and intersection values were interpolated. |
| // |
| $y = 20*$y + 255; |
| $x = 113.879*$x + 390; |
| } |
| // Determine which pane should be active. There is also the undocumented |
| // option to override this should it be necessary: may be removed later. |
| // |
| if (!isset($pnnAct)) |
| { |
| if ($x != 0 and $y != 0) |
| $pnnAct = 0; // Bottom right |
| if ($x != 0 and $y == 0) |
| $pnnAct = 1; // Top right |
| if ($x == 0 and $y != 0) |
| $pnnAct = 2; // Bottom left |
| if ($x == 0 and $y == 0) |
| $pnnAct = 3; // Top left |
| } |
| $this->_active_pane = $pnnAct; // Used in _storeSelection |
| $header = pack("vv", $record, $length); |
| $data = pack("vvvvv", $x, $y, $rwTop, $colLeft, $pnnAct); |
| $this->_append($header.$data); |
| } |
| /** |
| * Store the page setup SETUP BIFF record. |
| * |
| * @access private |
| */ |
| function _storeSetup() |
| { |
| $record = 0x00A1; // Record identifier |
| $length = 0x0022; // Number of bytes to follow |
| $iPaperSize = $this->_paper_size; // Paper size |
| $iScale = $this->_print_scale; // Print scaling factor |
| $iPageStart = 0x01; // Starting page number |
| $iFitWidth = $this->_fit_width; // Fit to number of pages wide |
| $iFitHeight = $this->_fit_height; // Fit to number of pages high |
| $grbit = 0x00; // Option flags |
| $iRes = 0x0258; // Print resolution |
| $iVRes = 0x0258; // Vertical print resolution |
| $numHdr = $this->_margin_head; // Header Margin |
| $numFtr = $this->_margin_foot; // Footer Margin |
| $iCopies = 0x01; // Number of copies |
| $fLeftToRight = 0x0; // Print over then down |
| $fLandscape = $this->_orientation; // Page orientation |
| $fNoPls = 0x0; // Setup not read from printer |
| $fNoColor = 0x0; // Print black and white |
| $fDraft = 0x0; // Print draft quality |
| $fNotes = 0x0; // Print notes |
| $fNoOrient = 0x0; // Orientation not set |
| $fUsePage = 0x0; // Use custom starting page |
| $grbit = $fLeftToRight; |
| $grbit |= $fLandscape << 1; |
| $grbit |= $fNoPls << 2; |
| $grbit |= $fNoColor << 3; |
| $grbit |= $fDraft << 4; |
| $grbit |= $fNotes << 5; |
| $grbit |= $fNoOrient << 6; |
| $grbit |= $fUsePage << 7; |
| $numHdr = pack("d", $numHdr); |
| $numFtr = pack("d", $numFtr); |
| if ($this->_byte_order) // if it's Big Endian |
| { |
| $numHdr = strrev($numHdr); |
| $numFtr = strrev($numFtr); |
| } |
| $header = pack("vv", $record, $length); |
| $data1 = pack("vvvvvvvv", $iPaperSize, |
| $iScale, |
| $iPageStart, |
| $iFitWidth, |
| $iFitHeight, |
| $grbit, |
| $iRes, |
| $iVRes); |
| $data2 = $numHdr.$numFtr; |
| $data3 = pack("v", $iCopies); |
| $this->_prepend($header.$data1.$data2.$data3); |
| } |
| /** |
| * Store the header caption BIFF record. |
| * |
| * @access private |
| */ |
| function _storeHeader() |
| { |
| $record = 0x0014; // Record identifier |
| $str = $this->_header; // header string |
| $cch = strlen($str); // Length of header string |
| $length = 1 + $cch; // Bytes to follow |
| $header = pack("vv", $record, $length); |
| $data = pack("C", $cch); |
| $this->_append($header.$data.$str); |
| } |
| /** |
| * Store the footer caption BIFF record. |
| * |
| * @access private |
| */ |
| function _storeFooter() |
| { |
| $record = 0x0015; // Record identifier |
| $str = $this->_footer; // Footer string |
| $cch = strlen($str); // Length of footer string |
| $length = 1 + $cch; // Bytes to follow |
| $header = pack("vv", $record, $length); |
| $data = pack("C", $cch); |
| $this->_append($header.$data.$str); |
| } |
| /** |
| * Store the horizontal centering HCENTER BIFF record. |
| * |
| * @access private |
| */ |
| function _storeHcenter() |
| { |
| $record = 0x0083; // Record identifier |
| $length = 0x0002; // Bytes to follow |
| $fHCenter = $this->_hcenter; // Horizontal centering |
| $header = pack("vv", $record, $length); |
| $data = pack("v", $fHCenter); |
| $this->_append($header.$data); |
| } |
| /** |
| * Store the vertical centering VCENTER BIFF record. |
| * |
| * @access private |
| */ |
| function _storeVcenter() |
| { |
| $record = 0x0084; // Record identifier |
| $length = 0x0002; // Bytes to follow |
| $fVCenter = $this->_vcenter; // Horizontal centering |
| $header = pack("vv", $record, $length); |
| $data = pack("v", $fVCenter); |
| $this->_append($header.$data); |
| } |
| /** |
| * Store the LEFTMARGIN BIFF record. |
| * |
| * @access private |
| */ |
| function _storeMarginLeft() |
| { |
| $record = 0x0026; // Record identifier |
| $length = 0x0008; // Bytes to follow |
| $margin = $this->_margin_left; // Margin in inches |
| $header = pack("vv", $record, $length); |
| $data = pack("d", $margin); |
| if ($this->_byte_order) // if it's Big Endian |
| { |
| $data = strrev($data); |
| } |
| $this->_append($header.$data); |
| } |
| /** |
| * Store the RIGHTMARGIN BIFF record. |
| * |
| * @access private |
| */ |
| function _storeMarginRight() |
| { |
| $record = 0x0027; // Record identifier |
| $length = 0x0008; // Bytes to follow |
| $margin = $this->_margin_right; // Margin in inches |
| $header = pack("vv", $record, $length); |
| $data = pack("d", $margin); |
| if ($this->_byte_order) // if it's Big Endian |
| { |
| $data = strrev($data); |
| } |
| $this->_append($header.$data); |
| } |
| /** |
| * Store the TOPMARGIN BIFF record. |
| * |
| * @access private |
| */ |
| function _storeMarginTop() |
| { |
| $record = 0x0028; // Record identifier |
| $length = 0x0008; // Bytes to follow |
| $margin = $this->_margin_top; // Margin in inches |
| $header = pack("vv", $record, $length); |
| $data = pack("d", $margin); |
| if ($this->_byte_order) // if it's Big Endian |
| { |
| $data = strrev($data); |
| } |
| $this->_append($header.$data); |
| } |
| /** |
| * Store the BOTTOMMARGIN BIFF record. |
| * |
| * @access private |
| */ |
| function _storeMarginBottom() |
| { |
| $record = 0x0029; // Record identifier |
| $length = 0x0008; // Bytes to follow |
| $margin = $this->_margin_bottom; // Margin in inches |
| $header = pack("vv", $record, $length); |
| $data = pack("d", $margin); |
| if ($this->_byte_order) // if it's Big Endian |
| { |
| $data = strrev($data); |
| } |
| $this->_append($header.$data); |
| } |
| /** |
| * Merges the area given by its arguments. |
| * This is an Excel97/2000 method. It is required to perform more complicated |
| * merging than the normal setAlign('merge'). |
| * |
| * @access public |
| * @param integer $first_row First row of the area to merge |
| * @param integer $first_col First column of the area to merge |
| * @param integer $last_row Last row of the area to merge |
| * @param integer $last_col Last column of the area to merge |
| */ |
| function mergeCells($first_row, $first_col, $last_row, $last_col) |
| { |
| $record = 0x00E5; // Record identifier |
| $length = 0x000A; // Bytes to follow |
| $cref = 1; // Number of refs |
| // Swap last row/col for first row/col as necessary |
| if ($first_row > $last_row) { |
| list($first_row, $last_row) = array($last_row, $first_row); |
| } |
| if ($first_col > $last_col) { |
| list($first_col, $last_col) = array($last_col, $first_col); |
| } |
| $header = pack("vv", $record, $length); |
| $data = pack("vvvvv", $cref, $first_row, $last_row, |
| $first_col, $last_col); |
| $this->_append($header.$data); |
| } |
| /** |
| * Write the PRINTHEADERS BIFF record. |
| * |
| * @access private |
| */ |
| function _storePrintHeaders() |
| { |
| $record = 0x002a; // Record identifier |
| $length = 0x0002; // Bytes to follow |
| $fPrintRwCol = $this->_print_headers; // Boolean flag |
| $header = pack("vv", $record, $length); |
| $data = pack("v", $fPrintRwCol); |
| $this->_prepend($header.$data); |
| } |
| /** |
| * Write the PRINTGRIDLINES BIFF record. Must be used in conjunction with the |
| * GRIDSET record. |
| * |
| * @access private |
| */ |
| function _storePrintGridlines() |
| { |
| $record = 0x002b; // Record identifier |
| $length = 0x0002; // Bytes to follow |
| $fPrintGrid = $this->_print_gridlines; // Boolean flag |
| $header = pack("vv", $record, $length); |
| $data = pack("v", $fPrintGrid); |
| $this->_prepend($header.$data); |
| } |
| /** |
| * Write the GRIDSET BIFF record. Must be used in conjunction with the |
| * PRINTGRIDLINES record. |
| * |
| * @access private |
| */ |
| function _storeGridset() |
| { |
| $record = 0x0082; // Record identifier |
| $length = 0x0002; // Bytes to follow |
| $fGridSet = !($this->_print_gridlines); // Boolean flag |
| $header = pack("vv", $record, $length); |
| $data = pack("v", $fGridSet); |
| $this->_prepend($header.$data); |
| } |
| /** |
| * Write the WSBOOL BIFF record, mainly for fit-to-page. Used in conjunction |
| * with the SETUP record. |
| * |
| * @access private |
| */ |
| function _storeWsbool() |
| { |
| $record = 0x0081; // Record identifier |
| $length = 0x0002; // Bytes to follow |
| // The only option that is of interest is the flag for fit to page. So we |
| // set all the options in one go. |
| // |
| if ($this->_fit_page) { |
| $grbit = 0x05c1; |
| } |
| else { |
| $grbit = 0x04c1; |
| } |
| $header = pack("vv", $record, $length); |
| $data = pack("v", $grbit); |
| $this->_prepend($header.$data); |
| } |
| /** |
| * Write the HORIZONTALPAGEBREAKS BIFF record. |
| * |
| * @access private |
| */ |
| function _storeHbreak() |
| { |
| // Return if the user hasn't specified pagebreaks |
| if (empty($this->_hbreaks)) { |
| return; |
| } |
| // Sort and filter array of page breaks |
| $breaks = $this->_hbreaks; |
| sort($breaks,SORT_NUMERIC); |
| if ($breaks[0] == 0) { // don't use first break if it's 0 |
| array_shift($breaks); |
| } |
| $record = 0x001b; // Record identifier |
| $cbrk = count($breaks); // Number of page breaks |
| $length = ($cbrk + 1) * 2; // Bytes to follow |
| $header = pack("vv", $record, $length); |
| $data = pack("v", $cbrk); |
| // Append each page break |
| foreach($breaks as $break) { |
| $data .= pack("v", $break); |
| } |
| $this->_prepend($header.$data); |
| } |
| /** |
| * Write the VERTICALPAGEBREAKS BIFF record. |
| * |
| * @access private |
| */ |
| function _storeVbreak() |
| { |
| // Return if the user hasn't specified pagebreaks |
| if (empty($this->_vbreaks)) { |
| return; |
| } |
| // 1000 vertical pagebreaks appears to be an internal Excel 5 limit. |
| // It is slightly higher in Excel 97/200, approx. 1026 |
| $breaks = array_slice($this->_vbreaks,0,1000); |
| // Sort and filter array of page breaks |
| sort($breaks,SORT_NUMERIC); |
| if ($breaks[0] == 0) { // don't use first break if it's 0 |
| array_shift($breaks); |
| } |
| $record = 0x001a; // Record identifier |
| $cbrk = count($breaks); // Number of page breaks |
| $length = ($cbrk + 1) * 2; // Bytes to follow |
| $header = pack("vv", $record, $length); |
| $data = pack("v", $cbrk); |
| // Append each page break |
| foreach ($breaks as $break) { |
| $data .= pack("v", $break); |
| } |
| $this->_prepend($header.$data); |
| } |
| /** |
| * Set the Biff PROTECT record to indicate that the worksheet is protected. |
| * |
| * @access private |
| */ |
| function _storeProtect() |
| { |
| // Exit unless sheet protection has been specified |
| if ($this->_protect == 0) { |
| return; |
| } |
| $record = 0x0012; // Record identifier |
| $length = 0x0002; // Bytes to follow |
| $fLock = $this->_protect; // Worksheet is protected |
| $header = pack("vv", $record, $length); |
| $data = pack("v", $fLock); |
| $this->_prepend($header.$data); |
| } |
| /** |
| * Write the worksheet PASSWORD record. |
| * |
| * @access private |
| */ |
| function _storePassword() |
| { |
| // Exit unless sheet protection and password have been specified |
| if (($this->_protect == 0) or (!isset($this->_password))) { |
| return; |
| } |
| $record = 0x0013; // Record identifier |
| $length = 0x0002; // Bytes to follow |
| $wPassword = $this->_password; // Encoded password |
| $header = pack("vv", $record, $length); |
| $data = pack("v", $wPassword); |
| $this->_prepend($header.$data); |
| } |
| /** |
| * Insert a 24bit bitmap image in a worksheet. |
| * |
| * @access public |
| * @param integer $row The row we are going to insert the bitmap into |
| * @param integer $col The column we are going to insert the bitmap into |
| * @param string $bitmap The bitmap filename |
| * @param integer $x The horizontal position (offset) of the image inside the cell. |
| * @param integer $y The vertical position (offset) of the image inside the cell. |
| * @param integer $scale_x The horizontal scale |
| * @param integer $scale_y The vertical scale |
| */ |
| function insertBitmap($row, $col, $bitmap, $x = 0, $y = 0, $scale_x = 1, $scale_y = 1) |
| { |
| $bitmap_array = $this->_processBitmap($bitmap); |
| if ($this->isError($bitmap_array)) |
| { |
| $this->writeString($row, $col, $bitmap_array->getMessage()); |
| return; |
| } |
| list($width, $height, $size, $data) = $bitmap_array; //$this->_processBitmap($bitmap); |
| // Scale the frame of the image. |
| $width *= $scale_x; |
| $height *= $scale_y; |
| // Calculate the vertices of the image and write the OBJ record |
| $this->_positionImage($col, $row, $x, $y, $width, $height); |
| // Write the IMDATA record to store the bitmap data |
| $record = 0x007f; |
| $length = 8 + $size; |
| $cf = 0x09; |
| $env = 0x01; |
| $lcb = $size; |
| $header = pack("vvvvV", $record, $length, $cf, $env, $lcb); |
| $this->_append($header.$data); |
| } |
| /** |
| * Calculate the vertices that define the position of the image as required by |
| * the OBJ record. |
| * |
| * +------------+------------+ |
| * | A | B | |
| * +-----+------------+------------+ |
| * | |(x1,y1) | | |
| * | 1 |(A1)._______|______ | |
| * | | | | | |
| * | | | | | |
| * +-----+----| BITMAP |-----+ |
| * | | | | | |
| * | 2 | |______________. | |
| * | | | (B2)| |
| * | | | (x2,y2)| |
| * +---- +------------+------------+ |
| * |
| * Example of a bitmap that covers some of the area from cell A1 to cell B2. |
| * |
| * Based on the width and height of the bitmap we need to calculate 8 vars: |
| * $col_start, $row_start, $col_end, $row_end, $x1, $y1, $x2, $y2. |
| * The width and height of the cells are also variable and have to be taken into |
| * account. |
| * The values of $col_start and $row_start are passed in from the calling |
| * function. The values of $col_end and $row_end are calculated by subtracting |
| * the width and height of the bitmap from the width and height of the |
| * underlying cells. |
| * The vertices are expressed as a percentage of the underlying cell width as |
| * follows (rhs values are in pixels): |
| * |
| * x1 = X / W *1024 |
| * y1 = Y / H *256 |
| * x2 = (X-1) / W *1024 |
| * y2 = (Y-1) / H *256 |
| * |
| * Where: X is distance from the left side of the underlying cell |
| * Y is distance from the top of the underlying cell |
| * W is the width of the cell |
| * H is the height of the cell |
| * |
| * @access private |
| * @note the SDK incorrectly states that the height should be expressed as a |
| * percentage of 1024. |
| * @param integer $col_start Col containing upper left corner of object |
| * @param integer $row_start Row containing top left corner of object |
| * @param integer $x1 Distance to left side of object |
| * @param integer $y1 Distance to top of object |
| * @param integer $width Width of image frame |
| * @param integer $height Height of image frame |
| */ |
| function _positionImage($col_start, $row_start, $x1, $y1, $width, $height) |
| { |
| // Initialise end cell to the same as the start cell |
| $col_end = $col_start; // Col containing lower right corner of object |
| $row_end = $row_start; // Row containing bottom right corner of object |
| // Zero the specified offset if greater than the cell dimensions |
| if ($x1 >= $this->_sizeCol($col_start)) |
| { |
| $x1 = 0; |
| } |
| if ($y1 >= $this->_sizeRow($row_start)) |
| { |
| $y1 = 0; |
| } |
| $width = $width + $x1 -1; |
| $height = $height + $y1 -1; |
| // Subtract the underlying cell widths to find the end cell of the image |
| while ($width >= $this->_sizeCol($col_end)) { |
| $width -= $this->_sizeCol($col_end); |
| $col_end++; |
| } |
| // Subtract the underlying cell heights to find the end cell of the image |
| while ($height >= $this->_sizeRow($row_end)) { |
| $height -= $this->_sizeRow($row_end); |
| $row_end++; |
| } |
| // Bitmap isn't allowed to start or finish in a hidden cell, i.e. a cell |
| // with zero eight or width. |
| // |
| if ($this->_sizeCol($col_start) == 0) |
| return; |
| if ($this->_sizeCol($col_end) == 0) |
| return; |
| if ($this->_sizeRow($row_start) == 0) |
| return; |
| if ($this->_sizeRow($row_end) == 0) |
| return; |
| // Convert the pixel values to the percentage value expected by Excel |
| $x1 = $x1 / $this->_sizeCol($col_start) * 1024; |
| $y1 = $y1 / $this->_sizeRow($row_start) * 256; |
| $x2 = $width / $this->_sizeCol($col_end) * 1024; // Distance to right side of object |
| $y2 = $height / $this->_sizeRow($row_end) * 256; // Distance to bottom of object |
| $this->_storeObjPicture( $col_start, $x1, |
| $row_start, $y1, |
| $col_end, $x2, |
| $row_end, $y2 |
| ); |
| } |
| /** |
| * Convert the width of a cell from user's units to pixels. By interpolation |
| * the relationship is: y = 7x +5. If the width hasn't been set by the user we |
| * use the default value. If the col is hidden we use a value of zero. |
| * |
| * @access private |
| * @param integer $col The column |
| * @return integer The width in pixels |
| */ |
| function _sizeCol($col) |
| { |
| // Look up the cell value to see if it has been changed |
| if (isset($this->col_sizes[$col])) { |
| if ($this->col_sizes[$col] == 0) { |
| return(0); |
| } |
| else { |
| return(floor(7 * $this->col_sizes[$col] + 5)); |
| } |
| } |
| else { |
| return(64); |
| } |
| } |
| /** |
| * Convert the height of a cell from user's units to pixels. By interpolation |
| * the relationship is: y = 4/3x. If the height hasn't been set by the user we |
| * use the default value. If the row is hidden we use a value of zero. (Not |
| * possible to hide row yet). |
| * |
| * @access private |
| * @param integer $row The row |
| * @return integer The width in pixels |
| */ |
| function _sizeRow($row) |
| { |
| // Look up the cell value to see if it has been changed |
| if (isset($this->row_sizes[$row])) { |
| if ($this->row_sizes[$row] == 0) { |
| return(0); |
| } |
| else { |
| return(floor(4/3 * $this->row_sizes[$row])); |
| } |
| } |
| else { |
| return(17); |
| } |
| } |
| /** |
| * Store the OBJ record that precedes an IMDATA record. This could be generalise |
| * to support other Excel objects. |
| * |
| * @access private |
| * @param integer $colL Column containing upper left corner of object |
| * @param integer $dxL Distance from left side of cell |
| * @param integer $rwT Row containing top left corner of object |
| * @param integer $dyT Distance from top of cell |
| * @param integer $colR Column containing lower right corner of object |
| * @param integer $dxR Distance from right of cell |
| * @param integer $rwB Row containing bottom right corner of object |
| * @param integer $dyB Distance from bottom of cell |
| */ |
| function _storeObjPicture($colL,$dxL,$rwT,$dyT,$colR,$dxR,$rwB,$dyB) |
| { |
| $record = 0x005d; // Record identifier |
| $length = 0x003c; // Bytes to follow |
| $cObj = 0x0001; // Count of objects in file (set to 1) |
| $OT = 0x0008; // Object type. 8 = Picture |
| $id = 0x0001; // Object ID |
| $grbit = 0x0614; // Option flags |
| $cbMacro = 0x0000; // Length of FMLA structure |
| $Reserved1 = 0x0000; // Reserved |
| $Reserved2 = 0x0000; // Reserved |
| $icvBack = 0x09; // Background colour |
| $icvFore = 0x09; // Foreground colour |
| $fls = 0x00; // Fill pattern |
| $fAuto = 0x00; // Automatic fill |
| $icv = 0x08; // Line colour |
| $lns = 0xff; // Line style |
| $lnw = 0x01; // Line weight |
| $fAutoB = 0x00; // Automatic border |
| $frs = 0x0000; // Frame style |
| $cf = 0x0009; // Image format, 9 = bitmap |
| $Reserved3 = 0x0000; // Reserved |
| $cbPictFmla = 0x0000; // Length of FMLA structure |
| $Reserved4 = 0x0000; // Reserved |
| $grbit2 = 0x0001; // Option flags |
| $Reserved5 = 0x0000; // Reserved |
| $header = pack("vv", $record, $length); |
| $data = pack("V", $cObj); |
| $data .= pack("v", $OT); |
| $data .= pack("v", $id); |
| $data .= pack("v", $grbit); |
| $data .= pack("v", $colL); |
| $data .= pack("v", $dxL); |
| $data .= pack("v", $rwT); |
| $data .= pack("v", $dyT); |
| $data .= pack("v", $colR); |
| $data .= pack("v", $dxR); |
| $data .= pack("v", $rwB); |
| $data .= pack("v", $dyB); |
| $data .= pack("v", $cbMacro); |
| $data .= pack("V", $Reserved1); |
| $data .= pack("v", $Reserved2); |
| $data .= pack("C", $icvBack); |
| $data .= pack("C", $icvFore); |
| $data .= pack("C", $fls); |
| $data .= pack("C", $fAuto); |
| $data .= pack("C", $icv); |
| $data .= pack("C", $lns); |
| $data .= pack("C", $lnw); |
| $data .= pack("C", $fAutoB); |
| $data .= pack("v", $frs); |
| $data .= pack("V", $cf); |
| $data .= pack("v", $Reserved3); |
| $data .= pack("v", $cbPictFmla); |
| $data .= pack("v", $Reserved4); |
| $data .= pack("v", $grbit2); |
| $data .= pack("V", $Reserved5); |
| $this->_append($header.$data); |
| } |
| /** |
| * Convert a 24 bit bitmap into the modified internal format used by Windows. |
| * This is described in BITMAPCOREHEADER and BITMAPCOREINFO structures in the |
| * MSDN library. |
| * |
| * @access private |
| * @param string $bitmap The bitmap to process |
| * @return array Array with data and properties of the bitmap |
| */ |
| function _processBitmap($bitmap) |
| { |
| // Open file. |
| $bmp_fd = @fopen($bitmap,"rb"); |
| if (!$bmp_fd) { |
| return($this->raiseError("Couldn't import $bitmap")); |
| } |
| // Slurp the file into a string. |
| $data = fread($bmp_fd, filesize($bitmap)); |
| // Check that the file is big enough to be a bitmap. |
| if (strlen($data) <= 0x36) { |
| return($this->raiseError("$bitmap doesn't contain enough data.\n")); |
| } |
| // The first 2 bytes are used to identify the bitmap. |
| $identity = unpack("A2", $data); |
| if ($identity[''] != "BM") { |
| return($this->raiseError("$bitmap doesn't appear to be a valid bitmap image.\n")); |
| } |
| // Remove bitmap data: ID. |
| $data = substr($data, 2); |
| // Read and remove the bitmap size. This is more reliable than reading |
| // the data size at offset 0x22. |
| // |
| $size_array = unpack("V", substr($data, 0, 4)); |
| $size = $size_array['']; |
| $data = substr($data, 4); |
| $size -= 0x36; // Subtract size of bitmap header. |
| $size += 0x0C; // Add size of BIFF header. |
| // Remove bitmap data: reserved, offset, header length. |
| $data = substr($data, 12); |
| // Read and remove the bitmap width and height. Verify the sizes. |
| $width_and_height = unpack("V2", substr($data, 0, 8)); |
| $width = $width_and_height[1]; |
| $height = $width_and_height[2]; |
| $data = substr($data, 8); |
| if ($width > 0xFFFF) { |
| return($this->raiseError("$bitmap: largest image width supported is 65k.\n")); |
| } |
| if ($height > 0xFFFF) { |
| return($this->raiseError("$bitmap: largest image height supported is 65k.\n")); |
| } |
| // Read and remove the bitmap planes and bpp data. Verify them. |
| $planes_and_bitcount = unpack("v2", substr($data, 0, 4)); |
| $data = substr($data, 4); |
| if ($planes_and_bitcount[2] != 24) { // Bitcount |
| return($this->raiseError("$bitmap isn't a 24bit true color bitmap.\n")); |
| } |
| if ($planes_and_bitcount[1] != 1) { |
| return($this->raiseError("$bitmap: only 1 plane nupported in bitmap image.\n")); |
| } |
| // Read and remove the bitmap compression. Verify compression. |
| $compression = unpack("V", substr($data, 0, 4)); |
| $data = substr($data, 4); |
| //$compression = 0; |
| if ($compression[""] != 0) { |
| return($this->raiseError("$bitmap: compression not supported in bitmap image.\n")); |
| } |
| // Remove bitmap data: data size, hres, vres, colours, imp. colours. |
| $data = substr($data, 20); |
| // Add the BITMAPCOREHEADER data |
| $header = pack("Vvvvv", 0x000c, $width, $height, 0x01, 0x18); |
| $data = $header . $data; |
| return (array($width, $height, $size, $data)); |
| } |
| /** |
| * Store the window zoom factor. This should be a reduced fraction but for |
| * simplicity we will store all fractions with a numerator of 100. |
| * |
| * @access private |
| */ |
| function _storeZoom() |
| { |
| // If scale is 100 we don't need to write a record |
| if ($this->_zoom == 100) { |
| return; |
| } |
| $record = 0x00A0; // Record identifier |
| $length = 0x0004; // Bytes to follow |
| $header = pack("vv", $record, $length); |
| $data = pack("vv", $this->_zoom, 100); |
| $this->_append($header.$data); |
| } |
| } |
| ?> |
| /trunk/applications/jrest/lib/Spreadsheet/Excel/Writer/OLEwriter.php |
|---|
| New file |
| 0,0 → 1,428 |
| <?php |
| /* |
| * Module written/ported by Xavier Noguer <xnoguer@rezebra.com> |
| * |
| * The majority of this is _NOT_ my code. I simply ported it from the |
| * PERL Spreadsheet::WriteExcel module. |
| * |
| * The author of the Spreadsheet::WriteExcel module is John McNamara |
| * <jmcnamara@cpan.org> |
| * |
| * I _DO_ maintain this code, and John McNamara has nothing to do with the |
| * porting of this code to PHP. Any questions directly related to this |
| * class library should be directed to me. |
| * |
| * License Information: |
| * |
| * Spreadsheet_Excel_Writer: A library for generating Excel Spreadsheets |
| * Copyright (c) 2002-2003 Xavier Noguer xnoguer@rezebra.com |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| */ |
| require_once('PEAR.php'); |
| /** |
| * Class for creating OLE streams for Excel Spreadsheets |
| * |
| * @author Xavier Noguer <xnoguer@rezebra.com> |
| * @category FileFormats |
| * @package Spreadsheet_Excel_Writer |
| */ |
| class Spreadsheet_Excel_Writer_OLEwriter extends PEAR |
| { |
| /** |
| * Filename for the OLE stream |
| * @var string |
| * @see _initialize() |
| */ |
| var $_OLEfilename; |
| /** |
| * Filehandle for the OLE stream |
| * @var resource |
| */ |
| var $_filehandle; |
| /** |
| * Name of the temporal file in case OLE stream goes to stdout |
| * @var string |
| */ |
| var $_tmp_filename; |
| /** |
| * Variable for preventing closing two times |
| * @var integer |
| */ |
| var $_fileclosed; |
| /** |
| * Size of the data to be written to the OLE stream |
| * @var integer |
| */ |
| var $_biffsize; |
| /** |
| * Real data size to be written to the OLE stream |
| * @var integer |
| */ |
| var $_booksize; |
| /** |
| * Number of big blocks in the OLE stream |
| * @var integer |
| */ |
| var $_big_blocks; |
| /** |
| * Number of list blocks in the OLE stream |
| * @var integer |
| */ |
| var $_list_blocks; |
| /** |
| * Number of big blocks in the OLE stream |
| * @var integer |
| */ |
| var $_root_start; |
| /** |
| * Constructor for the OLEwriter class |
| * |
| * @param string $OLEfilename the name of the file for the OLE stream |
| */ |
| function Spreadsheet_Excel_Writer_OLEwriter($OLEfilename) |
| { |
| $this->_OLEfilename = $OLEfilename; |
| $this->_filehandle = ""; |
| $this->_tmp_filename = ""; |
| $this->_fileclosed = 0; |
| $this->_biff_only = 0; |
| //$this->_size_allowed = 0; |
| $this->_biffsize = 0; |
| $this->_booksize = 0; |
| $this->_big_blocks = 0; |
| $this->_list_blocks = 0; |
| $this->_root_start = 0; |
| //$this->_block_count = 4; |
| $this->_initialize(); |
| } |
| /** |
| * Check for a valid filename and store the filehandle. |
| * Filehandle "-" writes to STDOUT |
| * |
| * @access private |
| */ |
| function _initialize() |
| { |
| $OLEfile = $this->_OLEfilename; |
| if(($OLEfile == '-') or ($OLEfile == '')) |
| { |
| $this->_tmp_filename = tempnam("/tmp", "OLEwriter"); |
| $fh = fopen($this->_tmp_filename,"wb"); |
| if ($fh == false) { |
| $this->raiseError("Can't create temporary file."); |
| } |
| } |
| else |
| { |
| // Create a new file, open for writing (in binmode) |
| $fh = fopen($OLEfile,"wb"); |
| if ($fh == false) { |
| $this->raiseError("Can't open $OLEfile. It may be in use or protected."); |
| } |
| } |
| // Store filehandle |
| $this->_filehandle = $fh; |
| } |
| /** |
| * Set the size of the data to be written to the OLE stream. |
| * The maximun size comes from this: |
| * $big_blocks = (109 depot block x (128 -1 marker word) |
| * - (1 x end words)) = 13842 |
| * $maxsize = $big_blocks * 512 bytes = 7087104 |
| * |
| * @access public |
| * @see Spreadsheet_Excel_Writer_Workbook::store_OLE_file() |
| * @param integer $biffsize The size of the data to be written to the OLE stream |
| * @return integer 1 for success |
| */ |
| function setSize($biffsize) |
| { |
| $maxsize = 7087104; // TODO: extend max size |
| if ($biffsize > $maxsize) { |
| $this->raiseError("Maximum file size, $maxsize, exceeded."); |
| } |
| $this->_biffsize = $biffsize; |
| // Set the min file size to 4k to avoid having to use small blocks |
| if ($biffsize > 4096) { |
| $this->_booksize = $biffsize; |
| } |
| else { |
| $this->_booksize = 4096; |
| } |
| //$this->_size_allowed = 1; |
| return(1); |
| } |
| /** |
| * Calculate various sizes needed for the OLE stream |
| * |
| * @access private |
| */ |
| function _calculateSizes() |
| { |
| $datasize = $this->_booksize; |
| if ($datasize % 512 == 0) { |
| $this->_big_blocks = $datasize/512; |
| } |
| else { |
| $this->_big_blocks = floor($datasize/512) + 1; |
| } |
| // There are 127 list blocks and 1 marker blocks for each big block |
| // depot + 1 end of chain block |
| $this->_list_blocks = floor(($this->_big_blocks)/127) + 1; |
| $this->_root_start = $this->_big_blocks; |
| } |
| /** |
| * Write root entry, big block list and close the filehandle. |
| * This routine is used to explicitly close the open filehandle without |
| * having to wait for DESTROY. |
| * |
| * @access public |
| * @see Spreadsheet_Excel_Writer_Workbook::store_OLE_file() |
| */ |
| function close() |
| { |
| //return if not $this->{_size_allowed}; |
| $this->_writePadding(); |
| $this->_writePropertyStorage(); |
| $this->_writeBigBlockDepot(); |
| // Close the filehandle |
| fclose($this->_filehandle); |
| if(($this->_OLEfilename == '-') or ($this->_OLEfilename == '')) |
| { |
| $fh = fopen($this->_tmp_filename, "rb"); |
| if ($fh == false) { |
| $this->raiseError("Can't read temporary file."); |
| } |
| fpassthru($fh); |
| @unlink($this->_tmp_filename); |
| } |
| $this->_fileclosed = 1; |
| } |
| /** |
| * Write BIFF data to OLE file. |
| * |
| * @param string $data string of bytes to be written |
| */ |
| function write($data) |
| { |
| fwrite($this->_filehandle,$data,strlen($data)); |
| } |
| /** |
| * Write OLE header block. |
| */ |
| function writeHeader() |
| { |
| $this->_calculateSizes(); |
| $root_start = $this->_root_start; |
| $num_lists = $this->_list_blocks; |
| $id = pack("nnnn", 0xD0CF, 0x11E0, 0xA1B1, 0x1AE1); |
| $unknown1 = pack("VVVV", 0x00, 0x00, 0x00, 0x00); |
| $unknown2 = pack("vv", 0x3E, 0x03); |
| $unknown3 = pack("v", -2); |
| $unknown4 = pack("v", 0x09); |
| $unknown5 = pack("VVV", 0x06, 0x00, 0x00); |
| $num_bbd_blocks = pack("V", $num_lists); |
| $root_startblock = pack("V", $root_start); |
| $unknown6 = pack("VV", 0x00, 0x1000); |
| $sbd_startblock = pack("V", -2); |
| $unknown7 = pack("VVV", 0x00, -2 ,0x00); |
| $unused = pack("V", -1); |
| fwrite($this->_filehandle,$id); |
| fwrite($this->_filehandle,$unknown1); |
| fwrite($this->_filehandle,$unknown2); |
| fwrite($this->_filehandle,$unknown3); |
| fwrite($this->_filehandle,$unknown4); |
| fwrite($this->_filehandle,$unknown5); |
| fwrite($this->_filehandle,$num_bbd_blocks); |
| fwrite($this->_filehandle,$root_startblock); |
| fwrite($this->_filehandle,$unknown6); |
| fwrite($this->_filehandle,$sbd_startblock); |
| fwrite($this->_filehandle,$unknown7); |
| for($i=1; $i <= $num_lists; $i++) |
| { |
| $root_start++; |
| fwrite($this->_filehandle,pack("V",$root_start)); |
| } |
| for($i = $num_lists; $i <=108; $i++) |
| { |
| fwrite($this->_filehandle,$unused); |
| } |
| } |
| /** |
| * Write big block depot. |
| * |
| * @access private |
| */ |
| function _writeBigBlockDepot() |
| { |
| $num_blocks = $this->_big_blocks; |
| $num_lists = $this->_list_blocks; |
| $total_blocks = $num_lists *128; |
| $used_blocks = $num_blocks + $num_lists +2; |
| $marker = pack("V", -3); |
| $end_of_chain = pack("V", -2); |
| $unused = pack("V", -1); |
| for($i=1; $i < $num_blocks; $i++) |
| { |
| fwrite($this->_filehandle,pack("V",$i)); |
| } |
| fwrite($this->_filehandle,$end_of_chain); |
| fwrite($this->_filehandle,$end_of_chain); |
| for($i=0; $i < $num_lists; $i++) |
| { |
| fwrite($this->_filehandle,$marker); |
| } |
| for($i=$used_blocks; $i <= $total_blocks; $i++) |
| { |
| fwrite($this->_filehandle,$unused); |
| } |
| } |
| /** |
| * Write property storage. TODO: add summary sheets |
| * |
| * @access private |
| */ |
| function _writePropertyStorage() |
| { |
| //$rootsize = -2; |
| /*************** name type dir start size */ |
| $this->_writePps("Root Entry", 0x05, 1, -2, 0x00); |
| $this->_writePps("Book", 0x02, -1, 0x00, $this->_booksize); |
| $this->_writePps('', 0x00, -1, 0x00, 0x0000); |
| $this->_writePps('', 0x00, -1, 0x00, 0x0000); |
| } |
| /** |
| * Write property sheet in property storage |
| * |
| * @param string $name name of the property storage. |
| * @param integer $type type of the property storage. |
| * @param integer $dir dir of the property storage. |
| * @param integer $start start of the property storage. |
| * @param integer $size size of the property storage. |
| * @access private |
| */ |
| function _writePps($name,$type,$dir,$start,$size) |
| { |
| $length = 0; |
| $rawname = ''; |
| if ($name != '') |
| { |
| $name = $name . "\0"; |
| for($i=0;$i<strlen($name);$i++) |
| { |
| // Simulate a Unicode string |
| $rawname .= pack("H*",dechex(ord($name{$i}))).pack("C",0); |
| } |
| $length = strlen($name) * 2; |
| } |
| $zero = pack("C", 0); |
| $pps_sizeofname = pack("v", $length); // 0x40 |
| $pps_type = pack("v", $type); // 0x42 |
| $pps_prev = pack("V", -1); // 0x44 |
| $pps_next = pack("V", -1); // 0x48 |
| $pps_dir = pack("V", $dir); // 0x4c |
| $unknown1 = pack("V", 0); |
| $pps_ts1s = pack("V", 0); // 0x64 |
| $pps_ts1d = pack("V", 0); // 0x68 |
| $pps_ts2s = pack("V", 0); // 0x6c |
| $pps_ts2d = pack("V", 0); // 0x70 |
| $pps_sb = pack("V", $start); // 0x74 |
| $pps_size = pack("V", $size); // 0x78 |
| fwrite($this->_filehandle,$rawname); |
| for($i=0; $i < (64 -$length); $i++) { |
| fwrite($this->_filehandle,$zero); |
| } |
| fwrite($this->_filehandle,$pps_sizeofname); |
| fwrite($this->_filehandle,$pps_type); |
| fwrite($this->_filehandle,$pps_prev); |
| fwrite($this->_filehandle,$pps_next); |
| fwrite($this->_filehandle,$pps_dir); |
| for($i=0; $i < 5; $i++) { |
| fwrite($this->_filehandle,$unknown1); |
| } |
| fwrite($this->_filehandle,$pps_ts1s); |
| fwrite($this->_filehandle,$pps_ts1d); |
| fwrite($this->_filehandle,$pps_ts2d); |
| fwrite($this->_filehandle,$pps_ts2d); |
| fwrite($this->_filehandle,$pps_sb); |
| fwrite($this->_filehandle,$pps_size); |
| fwrite($this->_filehandle,$unknown1); |
| } |
| /** |
| * Pad the end of the file |
| * |
| * @access private |
| */ |
| function _writePadding() |
| { |
| $biffsize = $this->_biffsize; |
| if ($biffsize < 4096) { |
| $min_size = 4096; |
| } |
| else { |
| $min_size = 512; |
| } |
| if ($biffsize % $min_size != 0) |
| { |
| $padding = $min_size - ($biffsize % $min_size); |
| for($i=0; $i < $padding; $i++) { |
| fwrite($this->_filehandle,"\0"); |
| } |
| } |
| } |
| } |
| ?> |
| /trunk/applications/jrest/lib/Spreadsheet/Excel/Writer/Parser.php |
|---|
| New file |
| 0,0 → 1,1551 |
| <?php |
| /** |
| * Class for parsing Excel formulas |
| * |
| * License Information: |
| * |
| * Spreadsheet_Excel_Writer: A library for generating Excel Spreadsheets |
| * Copyright (c) 2002-2003 Xavier Noguer xnoguer@rezebra.com |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| */ |
| /** |
| * @const SPREADSHEET_EXCEL_WRITER_ADD token identifier for character "+" |
| */ |
| define('SPREADSHEET_EXCEL_WRITER_ADD',"+"); |
| /** |
| * @const SPREADSHEET_EXCEL_WRITER_SUB token identifier for character "-" |
| */ |
| define('SPREADSHEET_EXCEL_WRITER_SUB',"-"); |
| /** |
| * @const SPREADSHEET_EXCEL_WRITER_MUL token identifier for character "*" |
| */ |
| define('SPREADSHEET_EXCEL_WRITER_MUL',"*"); |
| /** |
| * @const SPREADSHEET_EXCEL_WRITER_DIV token identifier for character "/" |
| */ |
| define('SPREADSHEET_EXCEL_WRITER_DIV',"/"); |
| /** |
| * @const SPREADSHEET_EXCEL_WRITER_OPEN token identifier for character "(" |
| */ |
| define('SPREADSHEET_EXCEL_WRITER_OPEN',"("); |
| /** |
| * @const SPREADSHEET_EXCEL_WRITER_CLOSE token identifier for character ")" |
| */ |
| define('SPREADSHEET_EXCEL_WRITER_CLOSE',")"); |
| /** |
| * @const SPREADSHEET_EXCEL_WRITER_COMA token identifier for character "," |
| */ |
| define('SPREADSHEET_EXCEL_WRITER_COMA',","); |
| /** |
| * @const SPREADSHEET_EXCEL_WRITER_GT token identifier for character ">" |
| */ |
| define('SPREADSHEET_EXCEL_WRITER_GT',">"); |
| /** |
| * @const SPREADSHEET_EXCEL_WRITER_LT token identifier for character "<" |
| */ |
| define('SPREADSHEET_EXCEL_WRITER_LT',"<"); |
| /** |
| * @const SPREADSHEET_EXCEL_WRITER_LE token identifier for character "<=" |
| */ |
| define('SPREADSHEET_EXCEL_WRITER_LE',"<="); |
| /** |
| * @const SPREADSHEET_EXCEL_WRITER_GE token identifier for character ">=" |
| */ |
| define('SPREADSHEET_EXCEL_WRITER_GE',">="); |
| /** |
| * @const SPREADSHEET_EXCEL_WRITER_EQ token identifier for character "=" |
| */ |
| define('SPREADSHEET_EXCEL_WRITER_EQ',"="); |
| /** |
| * @const SPREADSHEET_EXCEL_WRITER_NE token identifier for character "<>" |
| */ |
| define('SPREADSHEET_EXCEL_WRITER_NE',"<>"); |
| require_once('PEAR.php'); |
| /** |
| * Class for parsing Excel formulas |
| * |
| * @author Xavier Noguer <xnoguer@rezebra.com> |
| * @category FileFormats |
| * @package Spreadsheet_Excel_Writer |
| */ |
| class Spreadsheet_Excel_Writer_Parser extends PEAR |
| { |
| /** |
| * The index of the character we are currently looking at |
| * @var integer |
| */ |
| var $_current_char; |
| /** |
| * The token we are working on. |
| * @var string |
| */ |
| var $_current_token; |
| /** |
| * The formula to parse |
| * @var string |
| */ |
| var $_formula; |
| /** |
| * The character ahead of the current char |
| * @var string |
| */ |
| var $_lookahead; |
| /** |
| * The parse tree to be generated |
| * @var string |
| */ |
| var $_parse_tree; |
| /** |
| * The byte order. 1 => big endian, 0 => little endian. |
| * @var integer |
| */ |
| var $_byte_order; |
| /** |
| * Number of arguments for the current function |
| * @var integer |
| */ |
| var $_func_args; |
| /** |
| * Array of external sheets |
| * @var array |
| */ |
| var $_ext_sheets; |
| /** |
| * The class constructor |
| * |
| * @param integer $byte_order The byte order (Little endian or Big endian) of the architecture |
| (optional). 1 => big endian, 0 (default) => little endian. |
| */ |
| function Spreadsheet_Excel_Writer_Parser($byte_order = 0) |
| { |
| $this->_current_char = 0; |
| $this->_current_token = ''; // The token we are working on. |
| $this->_formula = ""; // The formula to parse. |
| $this->_lookahead = ''; // The character ahead of the current char. |
| $this->_parse_tree = ''; // The parse tree to be generated. |
| $this->_initializeHashes(); // Initialize the hashes: ptg's and function's ptg's |
| $this->_byte_order = $byte_order; // Little Endian or Big Endian |
| $this->_func_args = 0; // Number of arguments for the current function |
| $this->_ext_sheets = array(); |
| } |
| /** |
| * Initialize the ptg and function hashes. |
| * |
| * @access private |
| */ |
| function _initializeHashes() |
| { |
| // The Excel ptg indices |
| $this->ptg = array( |
| 'ptgExp' => 0x01, |
| 'ptgTbl' => 0x02, |
| 'ptgAdd' => 0x03, |
| 'ptgSub' => 0x04, |
| 'ptgMul' => 0x05, |
| 'ptgDiv' => 0x06, |
| 'ptgPower' => 0x07, |
| 'ptgConcat' => 0x08, |
| 'ptgLT' => 0x09, |
| 'ptgLE' => 0x0A, |
| 'ptgEQ' => 0x0B, |
| 'ptgGE' => 0x0C, |
| 'ptgGT' => 0x0D, |
| 'ptgNE' => 0x0E, |
| 'ptgIsect' => 0x0F, |
| 'ptgUnion' => 0x10, |
| 'ptgRange' => 0x11, |
| 'ptgUplus' => 0x12, |
| 'ptgUminus' => 0x13, |
| 'ptgPercent' => 0x14, |
| 'ptgParen' => 0x15, |
| 'ptgMissArg' => 0x16, |
| 'ptgStr' => 0x17, |
| 'ptgAttr' => 0x19, |
| 'ptgSheet' => 0x1A, |
| 'ptgEndSheet' => 0x1B, |
| 'ptgErr' => 0x1C, |
| 'ptgBool' => 0x1D, |
| 'ptgInt' => 0x1E, |
| 'ptgNum' => 0x1F, |
| 'ptgArray' => 0x20, |
| 'ptgFunc' => 0x21, |
| 'ptgFuncVar' => 0x22, |
| 'ptgName' => 0x23, |
| 'ptgRef' => 0x24, |
| 'ptgArea' => 0x25, |
| 'ptgMemArea' => 0x26, |
| 'ptgMemErr' => 0x27, |
| 'ptgMemNoMem' => 0x28, |
| 'ptgMemFunc' => 0x29, |
| 'ptgRefErr' => 0x2A, |
| 'ptgAreaErr' => 0x2B, |
| 'ptgRefN' => 0x2C, |
| 'ptgAreaN' => 0x2D, |
| 'ptgMemAreaN' => 0x2E, |
| 'ptgMemNoMemN' => 0x2F, |
| 'ptgNameX' => 0x39, |
| 'ptgRef3d' => 0x3A, |
| 'ptgArea3d' => 0x3B, |
| 'ptgRefErr3d' => 0x3C, |
| 'ptgAreaErr3d' => 0x3D, |
| 'ptgArrayV' => 0x40, |
| 'ptgFuncV' => 0x41, |
| 'ptgFuncVarV' => 0x42, |
| 'ptgNameV' => 0x43, |
| 'ptgRefV' => 0x44, |
| 'ptgAreaV' => 0x45, |
| 'ptgMemAreaV' => 0x46, |
| 'ptgMemErrV' => 0x47, |
| 'ptgMemNoMemV' => 0x48, |
| 'ptgMemFuncV' => 0x49, |
| 'ptgRefErrV' => 0x4A, |
| 'ptgAreaErrV' => 0x4B, |
| 'ptgRefNV' => 0x4C, |
| 'ptgAreaNV' => 0x4D, |
| 'ptgMemAreaNV' => 0x4E, |
| 'ptgMemNoMemN' => 0x4F, |
| 'ptgFuncCEV' => 0x58, |
| 'ptgNameXV' => 0x59, |
| 'ptgRef3dV' => 0x5A, |
| 'ptgArea3dV' => 0x5B, |
| 'ptgRefErr3dV' => 0x5C, |
| 'ptgAreaErr3d' => 0x5D, |
| 'ptgArrayA' => 0x60, |
| 'ptgFuncA' => 0x61, |
| 'ptgFuncVarA' => 0x62, |
| 'ptgNameA' => 0x63, |
| 'ptgRefA' => 0x64, |
| 'ptgAreaA' => 0x65, |
| 'ptgMemAreaA' => 0x66, |
| 'ptgMemErrA' => 0x67, |
| 'ptgMemNoMemA' => 0x68, |
| 'ptgMemFuncA' => 0x69, |
| 'ptgRefErrA' => 0x6A, |
| 'ptgAreaErrA' => 0x6B, |
| 'ptgRefNA' => 0x6C, |
| 'ptgAreaNA' => 0x6D, |
| 'ptgMemAreaNA' => 0x6E, |
| 'ptgMemNoMemN' => 0x6F, |
| 'ptgFuncCEA' => 0x78, |
| 'ptgNameXA' => 0x79, |
| 'ptgRef3dA' => 0x7A, |
| 'ptgArea3dA' => 0x7B, |
| 'ptgRefErr3dA' => 0x7C, |
| 'ptgAreaErr3d' => 0x7D |
| ); |
| // Thanks to Michael Meeks and Gnumeric for the initial arg values. |
| // |
| // The following hash was generated by "function_locale.pl" in the distro. |
| // Refer to function_locale.pl for non-English function names. |
| // |
| // The array elements are as follow: |
| // ptg: The Excel function ptg code. |
| // args: The number of arguments that the function takes: |
| // >=0 is a fixed number of arguments. |
| // -1 is a variable number of arguments. |
| // class: The reference, value or array class of the function args. |
| // vol: The function is volatile. |
| // |
| $this->_functions = array( |
| // function ptg args class vol |
| 'COUNT' => array( 0, -1, 0, 0 ), |
| 'IF' => array( 1, -1, 1, 0 ), |
| 'ISNA' => array( 2, 1, 1, 0 ), |
| 'ISERROR' => array( 3, 1, 1, 0 ), |
| 'SUM' => array( 4, -1, 0, 0 ), |
| 'AVERAGE' => array( 5, -1, 0, 0 ), |
| 'MIN' => array( 6, -1, 0, 0 ), |
| 'MAX' => array( 7, -1, 0, 0 ), |
| 'ROW' => array( 8, -1, 0, 0 ), |
| 'COLUMN' => array( 9, -1, 0, 0 ), |
| 'NA' => array( 10, 0, 0, 0 ), |
| 'NPV' => array( 11, -1, 1, 0 ), |
| 'STDEV' => array( 12, -1, 0, 0 ), |
| 'DOLLAR' => array( 13, -1, 1, 0 ), |
| 'FIXED' => array( 14, -1, 1, 0 ), |
| 'SIN' => array( 15, 1, 1, 0 ), |
| 'COS' => array( 16, 1, 1, 0 ), |
| 'TAN' => array( 17, 1, 1, 0 ), |
| 'ATAN' => array( 18, 1, 1, 0 ), |
| 'PI' => array( 19, 0, 1, 0 ), |
| 'SQRT' => array( 20, 1, 1, 0 ), |
| 'EXP' => array( 21, 1, 1, 0 ), |
| 'LN' => array( 22, 1, 1, 0 ), |
| 'LOG10' => array( 23, 1, 1, 0 ), |
| 'ABS' => array( 24, 1, 1, 0 ), |
| 'INT' => array( 25, 1, 1, 0 ), |
| 'SIGN' => array( 26, 1, 1, 0 ), |
| 'ROUND' => array( 27, 2, 1, 0 ), |
| 'LOOKUP' => array( 28, -1, 0, 0 ), |
| 'INDEX' => array( 29, -1, 0, 1 ), |
| 'REPT' => array( 30, 2, 1, 0 ), |
| 'MID' => array( 31, 3, 1, 0 ), |
| 'LEN' => array( 32, 1, 1, 0 ), |
| 'VALUE' => array( 33, 1, 1, 0 ), |
| 'TRUE' => array( 34, 0, 1, 0 ), |
| 'FALSE' => array( 35, 0, 1, 0 ), |
| 'AND' => array( 36, -1, 0, 0 ), |
| 'OR' => array( 37, -1, 0, 0 ), |
| 'NOT' => array( 38, 1, 1, 0 ), |
| 'MOD' => array( 39, 2, 1, 0 ), |
| 'DCOUNT' => array( 40, 3, 0, 0 ), |
| 'DSUM' => array( 41, 3, 0, 0 ), |
| 'DAVERAGE' => array( 42, 3, 0, 0 ), |
| 'DMIN' => array( 43, 3, 0, 0 ), |
| 'DMAX' => array( 44, 3, 0, 0 ), |
| 'DSTDEV' => array( 45, 3, 0, 0 ), |
| 'VAR' => array( 46, -1, 0, 0 ), |
| 'DVAR' => array( 47, 3, 0, 0 ), |
| 'TEXT' => array( 48, 2, 1, 0 ), |
| 'LINEST' => array( 49, -1, 0, 0 ), |
| 'TREND' => array( 50, -1, 0, 0 ), |
| 'LOGEST' => array( 51, -1, 0, 0 ), |
| 'GROWTH' => array( 52, -1, 0, 0 ), |
| 'PV' => array( 56, -1, 1, 0 ), |
| 'FV' => array( 57, -1, 1, 0 ), |
| 'NPER' => array( 58, -1, 1, 0 ), |
| 'PMT' => array( 59, -1, 1, 0 ), |
| 'RATE' => array( 60, -1, 1, 0 ), |
| 'MIRR' => array( 61, 3, 0, 0 ), |
| 'IRR' => array( 62, -1, 0, 0 ), |
| 'RAND' => array( 63, 0, 1, 1 ), |
| 'MATCH' => array( 64, -1, 0, 0 ), |
| 'DATE' => array( 65, 3, 1, 0 ), |
| 'TIME' => array( 66, 3, 1, 0 ), |
| 'DAY' => array( 67, 1, 1, 0 ), |
| 'MONTH' => array( 68, 1, 1, 0 ), |
| 'YEAR' => array( 69, 1, 1, 0 ), |
| 'WEEKDAY' => array( 70, -1, 1, 0 ), |
| 'HOUR' => array( 71, 1, 1, 0 ), |
| 'MINUTE' => array( 72, 1, 1, 0 ), |
| 'SECOND' => array( 73, 1, 1, 0 ), |
| 'NOW' => array( 74, 0, 1, 1 ), |
| 'AREAS' => array( 75, 1, 0, 1 ), |
| 'ROWS' => array( 76, 1, 0, 1 ), |
| 'COLUMNS' => array( 77, 1, 0, 1 ), |
| 'OFFSET' => array( 78, -1, 0, 1 ), |
| 'SEARCH' => array( 82, -1, 1, 0 ), |
| 'TRANSPOSE' => array( 83, 1, 1, 0 ), |
| 'TYPE' => array( 86, 1, 1, 0 ), |
| 'ATAN2' => array( 97, 2, 1, 0 ), |
| 'ASIN' => array( 98, 1, 1, 0 ), |
| 'ACOS' => array( 99, 1, 1, 0 ), |
| 'CHOOSE' => array( 100, -1, 1, 0 ), |
| 'HLOOKUP' => array( 101, -1, 0, 0 ), |
| 'VLOOKUP' => array( 102, -1, 0, 0 ), |
| 'ISREF' => array( 105, 1, 0, 0 ), |
| 'LOG' => array( 109, -1, 1, 0 ), |
| 'CHAR' => array( 111, 1, 1, 0 ), |
| 'LOWER' => array( 112, 1, 1, 0 ), |
| 'UPPER' => array( 113, 1, 1, 0 ), |
| 'PROPER' => array( 114, 1, 1, 0 ), |
| 'LEFT' => array( 115, -1, 1, 0 ), |
| 'RIGHT' => array( 116, -1, 1, 0 ), |
| 'EXACT' => array( 117, 2, 1, 0 ), |
| 'TRIM' => array( 118, 1, 1, 0 ), |
| 'REPLACE' => array( 119, 4, 1, 0 ), |
| 'SUBSTITUTE' => array( 120, -1, 1, 0 ), |
| 'CODE' => array( 121, 1, 1, 0 ), |
| 'FIND' => array( 124, -1, 1, 0 ), |
| 'CELL' => array( 125, -1, 0, 1 ), |
| 'ISERR' => array( 126, 1, 1, 0 ), |
| 'ISTEXT' => array( 127, 1, 1, 0 ), |
| 'ISNUMBER' => array( 128, 1, 1, 0 ), |
| 'ISBLANK' => array( 129, 1, 1, 0 ), |
| 'T' => array( 130, 1, 0, 0 ), |
| 'N' => array( 131, 1, 0, 0 ), |
| 'DATEVALUE' => array( 140, 1, 1, 0 ), |
| 'TIMEVALUE' => array( 141, 1, 1, 0 ), |
| 'SLN' => array( 142, 3, 1, 0 ), |
| 'SYD' => array( 143, 4, 1, 0 ), |
| 'DDB' => array( 144, -1, 1, 0 ), |
| 'INDIRECT' => array( 148, -1, 1, 1 ), |
| 'CALL' => array( 150, -1, 1, 0 ), |
| 'CLEAN' => array( 162, 1, 1, 0 ), |
| 'MDETERM' => array( 163, 1, 2, 0 ), |
| 'MINVERSE' => array( 164, 1, 2, 0 ), |
| 'MMULT' => array( 165, 2, 2, 0 ), |
| 'IPMT' => array( 167, -1, 1, 0 ), |
| 'PPMT' => array( 168, -1, 1, 0 ), |
| 'COUNTA' => array( 169, -1, 0, 0 ), |
| 'PRODUCT' => array( 183, -1, 0, 0 ), |
| 'FACT' => array( 184, 1, 1, 0 ), |
| 'DPRODUCT' => array( 189, 3, 0, 0 ), |
| 'ISNONTEXT' => array( 190, 1, 1, 0 ), |
| 'STDEVP' => array( 193, -1, 0, 0 ), |
| 'VARP' => array( 194, -1, 0, 0 ), |
| 'DSTDEVP' => array( 195, 3, 0, 0 ), |
| 'DVARP' => array( 196, 3, 0, 0 ), |
| 'TRUNC' => array( 197, -1, 1, 0 ), |
| 'ISLOGICAL' => array( 198, 1, 1, 0 ), |
| 'DCOUNTA' => array( 199, 3, 0, 0 ), |
| 'ROUNDUP' => array( 212, 2, 1, 0 ), |
| 'ROUNDDOWN' => array( 213, 2, 1, 0 ), |
| 'RANK' => array( 216, -1, 0, 0 ), |
| 'ADDRESS' => array( 219, -1, 1, 0 ), |
| 'DAYS360' => array( 220, -1, 1, 0 ), |
| 'TODAY' => array( 221, 0, 1, 1 ), |
| 'VDB' => array( 222, -1, 1, 0 ), |
| 'MEDIAN' => array( 227, -1, 0, 0 ), |
| 'SUMPRODUCT' => array( 228, -1, 2, 0 ), |
| 'SINH' => array( 229, 1, 1, 0 ), |
| 'COSH' => array( 230, 1, 1, 0 ), |
| 'TANH' => array( 231, 1, 1, 0 ), |
| 'ASINH' => array( 232, 1, 1, 0 ), |
| 'ACOSH' => array( 233, 1, 1, 0 ), |
| 'ATANH' => array( 234, 1, 1, 0 ), |
| 'DGET' => array( 235, 3, 0, 0 ), |
| 'INFO' => array( 244, 1, 1, 1 ), |
| 'DB' => array( 247, -1, 1, 0 ), |
| 'FREQUENCY' => array( 252, 2, 0, 0 ), |
| 'ERROR.TYPE' => array( 261, 1, 1, 0 ), |
| 'REGISTER.ID' => array( 267, -1, 1, 0 ), |
| 'AVEDEV' => array( 269, -1, 0, 0 ), |
| 'BETADIST' => array( 270, -1, 1, 0 ), |
| 'GAMMALN' => array( 271, 1, 1, 0 ), |
| 'BETAINV' => array( 272, -1, 1, 0 ), |
| 'BINOMDIST' => array( 273, 4, 1, 0 ), |
| 'CHIDIST' => array( 274, 2, 1, 0 ), |
| 'CHIINV' => array( 275, 2, 1, 0 ), |
| 'COMBIN' => array( 276, 2, 1, 0 ), |
| 'CONFIDENCE' => array( 277, 3, 1, 0 ), |
| 'CRITBINOM' => array( 278, 3, 1, 0 ), |
| 'EVEN' => array( 279, 1, 1, 0 ), |
| 'EXPONDIST' => array( 280, 3, 1, 0 ), |
| 'FDIST' => array( 281, 3, 1, 0 ), |
| 'FINV' => array( 282, 3, 1, 0 ), |
| 'FISHER' => array( 283, 1, 1, 0 ), |
| 'FISHERINV' => array( 284, 1, 1, 0 ), |
| 'FLOOR' => array( 285, 2, 1, 0 ), |
| 'GAMMADIST' => array( 286, 4, 1, 0 ), |
| 'GAMMAINV' => array( 287, 3, 1, 0 ), |
| 'CEILING' => array( 288, 2, 1, 0 ), |
| 'HYPGEOMDIST' => array( 289, 4, 1, 0 ), |
| 'LOGNORMDIST' => array( 290, 3, 1, 0 ), |
| 'LOGINV' => array( 291, 3, 1, 0 ), |
| 'NEGBINOMDIST' => array( 292, 3, 1, 0 ), |
| 'NORMDIST' => array( 293, 4, 1, 0 ), |
| 'NORMSDIST' => array( 294, 1, 1, 0 ), |
| 'NORMINV' => array( 295, 3, 1, 0 ), |
| 'NORMSINV' => array( 296, 1, 1, 0 ), |
| 'STANDARDIZE' => array( 297, 3, 1, 0 ), |
| 'ODD' => array( 298, 1, 1, 0 ), |
| 'PERMUT' => array( 299, 2, 1, 0 ), |
| 'POISSON' => array( 300, 3, 1, 0 ), |
| 'TDIST' => array( 301, 3, 1, 0 ), |
| 'WEIBULL' => array( 302, 4, 1, 0 ), |
| 'SUMXMY2' => array( 303, 2, 2, 0 ), |
| 'SUMX2MY2' => array( 304, 2, 2, 0 ), |
| 'SUMX2PY2' => array( 305, 2, 2, 0 ), |
| 'CHITEST' => array( 306, 2, 2, 0 ), |
| 'CORREL' => array( 307, 2, 2, 0 ), |
| 'COVAR' => array( 308, 2, 2, 0 ), |
| 'FORECAST' => array( 309, 3, 2, 0 ), |
| 'FTEST' => array( 310, 2, 2, 0 ), |
| 'INTERCEPT' => array( 311, 2, 2, 0 ), |
| 'PEARSON' => array( 312, 2, 2, 0 ), |
| 'RSQ' => array( 313, 2, 2, 0 ), |
| 'STEYX' => array( 314, 2, 2, 0 ), |
| 'SLOPE' => array( 315, 2, 2, 0 ), |
| 'TTEST' => array( 316, 4, 2, 0 ), |
| 'PROB' => array( 317, -1, 2, 0 ), |
| 'DEVSQ' => array( 318, -1, 0, 0 ), |
| 'GEOMEAN' => array( 319, -1, 0, 0 ), |
| 'HARMEAN' => array( 320, -1, 0, 0 ), |
| 'SUMSQ' => array( 321, -1, 0, 0 ), |
| 'KURT' => array( 322, -1, 0, 0 ), |
| 'SKEW' => array( 323, -1, 0, 0 ), |
| 'ZTEST' => array( 324, -1, 0, 0 ), |
| 'LARGE' => array( 325, 2, 0, 0 ), |
| 'SMALL' => array( 326, 2, 0, 0 ), |
| 'QUARTILE' => array( 327, 2, 0, 0 ), |
| 'PERCENTILE' => array( 328, 2, 0, 0 ), |
| 'PERCENTRANK' => array( 329, -1, 0, 0 ), |
| 'MODE' => array( 330, -1, 2, 0 ), |
| 'TRIMMEAN' => array( 331, 2, 0, 0 ), |
| 'TINV' => array( 332, 2, 1, 0 ), |
| 'CONCATENATE' => array( 336, -1, 1, 0 ), |
| 'POWER' => array( 337, 2, 1, 0 ), |
| 'RADIANS' => array( 342, 1, 1, 0 ), |
| 'DEGREES' => array( 343, 1, 1, 0 ), |
| 'SUBTOTAL' => array( 344, -1, 0, 0 ), |
| 'SUMIF' => array( 345, -1, 0, 0 ), |
| 'COUNTIF' => array( 346, 2, 0, 0 ), |
| 'COUNTBLANK' => array( 347, 1, 0, 0 ), |
| 'ROMAN' => array( 354, -1, 1, 0 ) |
| ); |
| } |
| /** |
| * Convert a token to the proper ptg value. |
| * |
| * @access private |
| * @param mixed $token The token to convert. |
| */ |
| function _convert($token) |
| { |
| if (preg_match("/^\"[^\"]{0,255}\"$/", $token)) |
| { |
| return $this->_convertString($token); |
| } |
| elseif (is_numeric($token)) |
| { |
| return $this->_convertNumber($token); |
| } |
| // match references like A1 or $A$1 |
| elseif(preg_match('/^\$?([A-I]?[A-Z])\$?(\d+)$/',$token)) |
| { |
| return($this->_convertRef2d($token)); |
| } |
| // match external references like Sheet1:Sheet2!A1 |
| elseif (preg_match("/^[A-Za-z0-9_]+(\:[A-Za-z0-9_]+)?\![A-I]?[A-Z](\d+)$/",$token)) |
| { |
| return $this->_convertRef3d($token); |
| } |
| // match ranges like A1:B2 |
| elseif(preg_match("/^(\$)?[A-I]?[A-Z](\$)?(\d+)\:(\$)?[A-I]?[A-Z](\$)?(\d+)$/",$token)) |
| { |
| return($this->_convertRange2d($token)); |
| } |
| // match ranges like A1..B2 |
| elseif(preg_match("/^(\$)?[A-I]?[A-Z](\$)?(\d+)\.\.(\$)?[A-I]?[A-Z](\$)?(\d+)$/",$token)) |
| { |
| return($this->_convertRange2d($token)); |
| } |
| // match external ranges like Sheet1:Sheet2!A1:B2 |
| elseif (preg_match("/^[A-Za-z0-9_]+(\:[A-Za-z0-9_]+)?\!([A-I]?[A-Z])?(\d+)\:([A-I]?[A-Z])?(\d+)$/",$token)) |
| { |
| return $this->_convertRange3d($token); |
| } |
| elseif(isset($this->ptg[$token])) // operators (including parentheses) |
| { |
| return(pack("C", $this->ptg[$token])); |
| } |
| elseif(preg_match("/[A-Z0-9\xc0-\xdc\.]+/",$token)) |
| { |
| return($this->_convertFunction($token,$this->_func_args)); |
| } |
| // if it's an argument, ignore the token (the argument remains) |
| elseif($token == 'arg') |
| { |
| $this->_func_args++; |
| return(''); |
| } |
| // TODO: use real error codes |
| $this->raiseError("Unknown token $token", 0, PEAR_ERROR_DIE); |
| } |
| /** |
| * Convert a number token to ptgInt or ptgNum |
| * |
| * @access private |
| * @param mixed $num an integer or double for conversion to its ptg value |
| */ |
| function _convertNumber($num) |
| { |
| // Integer in the range 0..2**16-1 |
| if ((preg_match("/^\d+$/",$num)) and ($num <= 65535)) { |
| return(pack("Cv", $this->ptg['ptgInt'], $num)); |
| } |
| else // A float |
| { |
| if($this->_byte_order) // if it's Big Endian |
| { |
| $num = strrev($num); |
| } |
| return(pack("Cd", $this->ptg['ptgNum'], $num)); |
| } |
| } |
| /** |
| * Convert a string token to ptgStr |
| * |
| * @access private |
| * @param string $string A string for conversion to its ptg value |
| */ |
| function _convertString($string) |
| { |
| // chop away beggining and ending quotes |
| $string = substr($string, 1, strlen($string) - 2); |
| return pack("CC", $this->ptg['ptgStr'], strlen($string)).$string; |
| } |
| /** |
| * Convert a function to a ptgFunc or ptgFuncVarV depending on the number of |
| * args that it takes. |
| * |
| * @access private |
| * @param string $token The name of the function for convertion to ptg value. |
| * @param integer $num_args The number of arguments the function recieves. |
| */ |
| function _convertFunction($token, $num_args) |
| { |
| $this->_func_args = 0; // re initialize the number of arguments |
| $args = $this->_functions[$token][1]; |
| $volatile = $this->_functions[$token][3]; |
| // Fixed number of args eg. TIME($i,$j,$k). |
| if ($args >= 0) { |
| return(pack("Cv", $this->ptg['ptgFuncV'], $this->_functions[$token][0])); |
| } |
| // Variable number of args eg. SUM($i,$j,$k, ..). |
| if ($args == -1) { |
| return(pack("CCv", $this->ptg['ptgFuncVarV'], $num_args, $this->_functions[$token][0])); |
| } |
| } |
| /** |
| * Convert an Excel range such as A1:D4 to a ptgRefV. |
| * |
| * @access private |
| * @param string $range An Excel range in the A1:A2 or A1..A2 format. |
| */ |
| function _convertRange2d($range) |
| { |
| $class = 2; // as far as I know, this is magick. |
| // Split the range into 2 cell refs |
| if(preg_match("/^([A-I]?[A-Z])(\d+)\:([A-I]?[A-Z])(\d+)$/",$range)) { |
| list($cell1, $cell2) = split(':', $range); |
| } |
| elseif(preg_match("/^([A-I]?[A-Z])(\d+)\.\.([A-I]?[A-Z])(\d+)$/",$range)) { |
| list($cell1, $cell2) = split('\.\.', $range); |
| } |
| else { |
| // TODO: use real error codes |
| $this->raiseError("Unknown range separator", 0, PEAR_ERROR_DIE); |
| } |
| // Convert the cell references |
| $cell_array1 = $this->_cellToPackedRowcol($cell1); |
| if($this->isError($cell_array1)) { |
| return($cell_array1); |
| } |
| list($row1, $col1) = $cell_array1; //$this->_cellToPackedRowcol($cell1); |
| $cell_array2 = $this->_cellToPackedRowcol($cell2); |
| if($this->isError($cell_array2)) { |
| return($cell_array2); |
| } |
| list($row2, $col2) = $cell_array2; //$this->_cellToPackedRowcol($cell2); |
| // The ptg value depends on the class of the ptg. |
| if ($class == 0) { |
| $ptgArea = pack("C", $this->ptg['ptgArea']); |
| } |
| elseif ($class == 1) { |
| $ptgArea = pack("C", $this->ptg['ptgAreaV']); |
| } |
| elseif ($class == 2) { |
| $ptgArea = pack("C", $this->ptg['ptgAreaA']); |
| } |
| else { |
| // TODO: use real error codes |
| $this->raiseError("Unknown class $class", 0, PEAR_ERROR_DIE); |
| } |
| return($ptgArea . $row1 . $row2 . $col1. $col2); |
| } |
| /** |
| * Convert an Excel 3d range such as "Sheet1!A1:D4" or "Sheet1:Sheet2!A1:D4" to |
| * a ptgArea3dV. |
| * |
| * @access private |
| * @param string $token An Excel range in the Sheet1!A1:A2 format. |
| */ |
| function _convertRange3d($token) |
| { |
| $class = 2; // as far as I know, this is magick. |
| // Split the ref at the ! symbol |
| list($ext_ref, $range) = split('!', $token); |
| // Convert the external reference part |
| $ext_ref = $this->_packExtRef($ext_ref); |
| if ($this->isError($ext_ref)) { |
| return $ext_ref; |
| } |
| // Split the range into 2 cell refs |
| list($cell1, $cell2) = split(':', $range); |
| // Convert the cell references |
| if (preg_match("/^(\$)?[A-I]?[A-Z](\$)?(\d+)$/", $cell1)) |
| { |
| $cell_array1 = $this->_cellToPackedRowcol($cell1); |
| if (PEAR::isError($cell_array1)) { |
| return $cell_array1; |
| } |
| list($row1, $col1) = $cell_array1; |
| $cell_array2 = $this->_cellToPackedRowcol($cell2); |
| if (PEAR::isError($cell_array2)) { |
| return $cell_array2; |
| } |
| list($row2, $col2) = $cell_array2; |
| } |
| else { // It's a columns range (like 26:27) |
| $cells_array = $this->_rangeToPackedRange($cell1.':'.$cell2); |
| if (PEAR::isError($cells_array)) { |
| return $cells_array; |
| } |
| list($row1, $col1, $row2, $col2) = $cells_array; |
| } |
| // The ptg value depends on the class of the ptg. |
| if ($class == 0) { |
| $ptgArea = pack("C", $this->ptg['ptgArea3d']); |
| } |
| elseif ($class == 1) { |
| $ptgArea = pack("C", $this->ptg['ptgArea3dV']); |
| } |
| elseif ($class == 2) { |
| $ptgArea = pack("C", $this->ptg['ptgArea3dA']); |
| } |
| else { |
| $this->raiseError("Unknown class $class", 0, PEAR_ERROR_DIE); |
| } |
| return $ptgArea . $ext_ref . $row1 . $row2 . $col1. $col2; |
| } |
| /** |
| * Convert an Excel reference such as A1, $B2, C$3 or $D$4 to a ptgRefV. |
| * |
| * @access private |
| * @param string $cell An Excel cell reference |
| * @return string The cell in packed() format with the corresponding ptg |
| */ |
| function _convertRef2d($cell) |
| { |
| $class = 2; // as far as I know, this is magick. |
| // Convert the cell reference |
| $cell_array = $this->_cellToPackedRowcol($cell); |
| if($this->isError($cell_array)) { |
| return($cell_array); |
| } |
| list($row, $col) = $cell_array; |
| // The ptg value depends on the class of the ptg. |
| if ($class == 0) { |
| $ptgRef = pack("C", $this->ptg['ptgRef']); |
| } |
| elseif ($class == 1) { |
| $ptgRef = pack("C", $this->ptg['ptgRefV']); |
| } |
| elseif ($class == 2) { |
| $ptgRef = pack("C", $this->ptg['ptgRefA']); |
| } |
| else { |
| // TODO: use real error codes |
| $this->raiseError("Unknown class $class", 0, PEAR_ERROR_DIE); |
| } |
| return($ptgRef.$row.$col); |
| } |
| /** |
| * Convert an Excel 3d reference such as "Sheet1!A1" or "Sheet1:Sheet2!A1" to a |
| * ptgRef3dV. |
| * |
| * @access private |
| * @param string $cell An Excel cell reference |
| * @return string The cell in packed() format with the corresponding ptg |
| */ |
| function _convertRef3d($cell) |
| { |
| $class = 2; // as far as I know, this is magick. |
| // Split the ref at the ! symbol |
| list($ext_ref, $cell) = split('!', $cell); |
| // Convert the external reference part |
| $ext_ref = $this->_packExtRef($ext_ref); |
| if ($this->isError($ext_ref)) { |
| return $ext_ref; |
| } |
| // Convert the cell reference part |
| list($row, $col) = $this->_cellToPackedRowcol($cell); |
| // The ptg value depends on the class of the ptg. |
| if ($class == 0) { |
| $ptgRef = pack("C", $this->ptg['ptgRef3d']); |
| } |
| elseif ($class == 1) { |
| $ptgRef = pack("C", $this->ptg['ptgRef3dV']); |
| } |
| elseif ($class == 2) { |
| $ptgRef = pack("C", $this->ptg['ptgRef3dA']); |
| } |
| else { |
| $this->raiseError("Unknown class $class", 0, PEAR_ERROR_DIE); |
| } |
| return $ptgRef . $ext_ref. $row . $col; |
| } |
| /** |
| * Convert the sheet name part of an external reference, for example "Sheet1" or |
| * "Sheet1:Sheet2", to a packed structure. |
| * |
| * @access private |
| * @param string $ext_ref The name of the external reference |
| * @return string The reference index in packed() format |
| */ |
| function _packExtRef($ext_ref) |
| { |
| $ext_ref = preg_replace("/^'/", '', $ext_ref); // Remove leading ' if any. |
| $ext_ref = preg_replace("/'$/", '', $ext_ref); // Remove trailing ' if any. |
| // Check if there is a sheet range eg., Sheet1:Sheet2. |
| if (preg_match("/:/", $ext_ref)) |
| { |
| list($sheet_name1, $sheet_name2) = split(':', $ext_ref); |
| $sheet1 = $this->_getSheetIndex($sheet_name1); |
| if ($sheet1 == -1) { |
| return $this->raiseError("Unknown sheet name $sheet_name1 in formula"); |
| } |
| $sheet2 = $this->_getSheetIndex($sheet_name2); |
| if ($sheet2 == -1) { |
| return $this->raiseError("Unknown sheet name $sheet_name2 in formula"); |
| } |
| // Reverse max and min sheet numbers if necessary |
| if ($sheet1 > $sheet2) { |
| list($sheet1, $sheet2) = array($sheet2, $sheet1); |
| } |
| } |
| else // Single sheet name only. |
| { |
| $sheet1 = $this->_getSheetIndex($ext_ref); |
| if ($sheet1 == -1) { |
| return $this->raiseError("Unknown sheet name $ext_ref in formula"); |
| } |
| $sheet2 = $sheet1; |
| } |
| // References are stored relative to 0xFFFF. |
| $offset = -1 - $sheet1; |
| return pack('vdvv', $offset, 0x00, $sheet1, $sheet2); |
| } |
| /** |
| * Look up the index that corresponds to an external sheet name. The hash of |
| * sheet names is updated by the addworksheet() method of the |
| * Spreadsheet_Excel_Writer_Workbook class. |
| * |
| * @access private |
| * @return integer |
| */ |
| function _getSheetIndex($sheet_name) |
| { |
| if (!isset($this->_ext_sheets[$sheet_name])) { |
| return -1; |
| } |
| else { |
| return $this->_ext_sheets[$sheet_name]; |
| } |
| } |
| /** |
| * This method is used to update the array of sheet names. It is |
| * called by the addWorksheet() method of the Spreadsheet_Excel_Writer_Workbook class. |
| * |
| * @access private |
| * @param string $name The name of the worksheet being added |
| * @param integer $index The index of the worksheet being added |
| */ |
| function setExtSheet($name, $index) |
| { |
| $this->_ext_sheets[$name] = $index; |
| } |
| /** |
| * pack() row and column into the required 3 byte format. |
| * |
| * @access private |
| * @param string $cell The Excel cell reference to be packed |
| * @return array Array containing the row and column in packed() format |
| */ |
| function _cellToPackedRowcol($cell) |
| { |
| list($row, $col, $row_rel, $col_rel) = $this->_cellToRowcol($cell); |
| if ($col >= 256) { |
| return($this->raiseError("Column in: $cell greater than 255")); |
| } |
| if ($row >= 16384) { |
| return($this->raiseError("Row in: $cell greater than 16384 ")); |
| } |
| // Set the high bits to indicate if row or col are relative. |
| $row |= $col_rel << 14; |
| $row |= $row_rel << 15; |
| $row = pack('v', $row); |
| $col = pack('C', $col); |
| return(array($row, $col)); |
| } |
| /** |
| * pack() row range into the required 3 byte format. |
| * Just using maximun col/rows, which is probably not the correct solution |
| * |
| * @access private |
| * @param string $range The Excel range to be packed |
| * @return array Array containing (row1,col1,row2,col2) in packed() format |
| */ |
| function _rangeToPackedRange($range) |
| { |
| preg_match('/(\$)?(\d+)\:(\$)?(\d+)/', $range, $match); |
| // return absolute rows if there is a $ in the ref |
| $row1_rel = empty($match[1]) ? 1 : 0; |
| $row1 = $match[2]; |
| $row2_rel = empty($match[3]) ? 1 : 0; |
| $row2 = $match[4]; |
| // Convert 1-index to zero-index |
| $row1--; |
| $row2--; |
| // Trick poor inocent Excel |
| $col1 = 0; |
| $col2 = 16383; // maximum possible value for Excel 5 (change this!!!) |
| //list($row, $col, $row_rel, $col_rel) = $this->_cellToRowcol($cell); |
| if (($row1 >= 16384) or ($row2 >= 16384)) { |
| return new PEAR_Error("Row in: $range greater than 16384 "); |
| } |
| // Set the high bits to indicate if rows are relative. |
| $row1 |= $row1_rel << 14; |
| $row2 |= $row2_rel << 15; |
| $row1 = pack('v', $row1); |
| $row2 = pack('v', $row2); |
| $col1 = pack('C', $col1); |
| $col2 = pack('C', $col2); |
| return array($row1, $col1, $row2, $col2); |
| } |
| /** |
| * Convert an Excel cell reference such as A1 or $B2 or C$3 or $D$4 to a zero |
| * indexed row and column number. Also returns two (0,1) values to indicate |
| * whether the row or column are relative references. |
| * |
| * @access private |
| * @param string $cell The Excel cell reference in A1 format. |
| * @return array |
| */ |
| function _cellToRowcol($cell) |
| { |
| preg_match('/(\$)?([A-I]?[A-Z])(\$)?(\d+)/',$cell,$match); |
| // return absolute column if there is a $ in the ref |
| $col_rel = empty($match[1]) ? 1 : 0; |
| $col_ref = $match[2]; |
| $row_rel = empty($match[3]) ? 1 : 0; |
| $row = $match[4]; |
| // Convert base26 column string to a number. |
| $expn = strlen($col_ref) - 1; |
| $col = 0; |
| for($i=0; $i < strlen($col_ref); $i++) |
| { |
| $col += (ord($col_ref{$i}) - ord('A') + 1) * pow(26, $expn); |
| $expn--; |
| } |
| // Convert 1-index to zero-index |
| $row--; |
| $col--; |
| return(array($row, $col, $row_rel, $col_rel)); |
| } |
| /** |
| * Advance to the next valid token. |
| * |
| * @access private |
| */ |
| function _advance() |
| { |
| $i = $this->_current_char; |
| // eat up white spaces |
| if($i < strlen($this->_formula)) |
| { |
| while($this->_formula{$i} == " ") { |
| $i++; |
| } |
| if($i < strlen($this->_formula) - 1) { |
| $this->_lookahead = $this->_formula{$i+1}; |
| } |
| $token = ""; |
| } |
| while($i < strlen($this->_formula)) |
| { |
| $token .= $this->_formula{$i}; |
| if($this->_match($token) != '') |
| { |
| if($i < strlen($this->_formula) - 1) { |
| $this->_lookahead = $this->_formula{$i+1}; |
| } |
| $this->_current_char = $i + 1; |
| $this->_current_token = $token; |
| return(1); |
| } |
| if ($i < strlen($this->_formula) - 2) { |
| $this->_lookahead = $this->_formula{$i+2}; |
| } |
| // if we run out of characters _lookahead becomes empty |
| else { |
| $this->_lookahead = ''; |
| } |
| $i++; |
| } |
| //die("Lexical error ".$this->_current_char); |
| } |
| /** |
| * Checks if it's a valid token. |
| * |
| * @access private |
| * @param mixed $token The token to check. |
| * @return mixed The checked token or false on failure |
| */ |
| function _match($token) |
| { |
| switch($token) |
| { |
| case SPREADSHEET_EXCEL_WRITER_ADD: |
| return($token); |
| break; |
| case SPREADSHEET_EXCEL_WRITER_SUB: |
| return($token); |
| break; |
| case SPREADSHEET_EXCEL_WRITER_MUL: |
| return($token); |
| break; |
| case SPREADSHEET_EXCEL_WRITER_DIV: |
| return($token); |
| break; |
| case SPREADSHEET_EXCEL_WRITER_OPEN: |
| return($token); |
| break; |
| case SPREADSHEET_EXCEL_WRITER_CLOSE: |
| return($token); |
| break; |
| case SPREADSHEET_EXCEL_WRITER_COMA: |
| return($token); |
| break; |
| case SPREADSHEET_EXCEL_WRITER_GT: |
| if ($this->_lookahead == '=') { // it's a GE token |
| break; |
| } |
| return($token); |
| break; |
| case SPREADSHEET_EXCEL_WRITER_LT: |
| // it's a LE or a NE token |
| if (($this->_lookahead == '=') or ($this->_lookahead == '>')) { |
| break; |
| } |
| return($token); |
| break; |
| case SPREADSHEET_EXCEL_WRITER_GE: |
| return($token); |
| break; |
| case SPREADSHEET_EXCEL_WRITER_LE: |
| return($token); |
| break; |
| case SPREADSHEET_EXCEL_WRITER_EQ: |
| return($token); |
| break; |
| case SPREADSHEET_EXCEL_WRITER_NE: |
| return($token); |
| break; |
| default: |
| // if it's a reference |
| if (preg_match('/^\$?[A-I]?[A-Z]\$?[0-9]+$/',$token) and |
| !ereg("[0-9]",$this->_lookahead) and |
| ($this->_lookahead != ':') and ($this->_lookahead != '.') and |
| ($this->_lookahead != '!')) |
| { |
| return $token; |
| } |
| // If it's an external reference (Sheet1!A1 or Sheet1:Sheet2!A1) |
| elseif (preg_match("/^[A-Za-z0-9_]+(\:[A-Za-z0-9_]+)?\![A-I]?[A-Z][0-9]+$/",$token) and |
| !ereg("[0-9]",$this->_lookahead) and |
| ($this->_lookahead != ':') and ($this->_lookahead != '.')) |
| { |
| return $token; |
| } |
| // if it's a range (A1:A2) |
| elseif (preg_match("/^(\$)?[A-I]?[A-Z](\$)?[0-9]+:(\$)?[A-I]?[A-Z](\$)?[0-9]+$/",$token) and |
| !ereg("[0-9]",$this->_lookahead)) |
| { |
| return $token; |
| } |
| // if it's a range (A1..A2) |
| elseif (preg_match("/^(\$)?[A-I]?[A-Z](\$)?[0-9]+\.\.(\$)?[A-I]?[A-Z](\$)?[0-9]+$/",$token) and |
| !ereg("[0-9]",$this->_lookahead)) |
| { |
| return $token; |
| } |
| // If it's an external range |
| elseif (preg_match("/^[A-Za-z0-9_]+(\:[A-Za-z0-9_]+)?\!([A-I]?[A-Z])?[0-9]+:([A-I]?[A-Z])?[0-9]+$/",$token) and |
| !ereg("[0-9]",$this->_lookahead)) |
| { |
| return $token; |
| } |
| // If it's a number (check that it's not a sheet name or range) |
| elseif (is_numeric($token) and !is_numeric($token.$this->_lookahead) and |
| ($this->_lookahead != '!') and (($this->_lookahead != ':'))) |
| { |
| return $token; |
| } |
| // If it's a string (of maximum 255 characters) |
| elseif(ereg("^\"[^\"]{0,255}\"$",$token)) |
| { |
| return($token); |
| } |
| // if it's a function call |
| elseif(eregi("^[A-Z0-9\xc0-\xdc\.]+$",$token) and ($this->_lookahead == "(")) |
| { |
| return($token); |
| } |
| return ''; |
| } |
| } |
| /** |
| * The parsing method. It parses a formula. |
| * |
| * @access public |
| * @param string $formula The formula to parse, without the initial equal sign (=). |
| */ |
| function parse($formula) |
| { |
| $this->_current_char = 0; |
| $this->_formula = $formula; |
| $this->_lookahead = $formula{1}; |
| $this->_advance(); |
| $this->_parse_tree = $this->_condition(); |
| if ($this->isError($this->_parse_tree)) { |
| return $this->_parse_tree; |
| } |
| } |
| /** |
| * It parses a condition. It assumes the following rule: |
| * Cond -> Expr [(">" | "<") Expr] |
| * |
| * @access private |
| * @return mixed The parsed ptg'd tree |
| */ |
| function _condition() |
| { |
| $result = $this->_expression(); |
| if($this->isError($result)) { |
| return $result; |
| } |
| if ($this->_current_token == SPREADSHEET_EXCEL_WRITER_LT) |
| { |
| $this->_advance(); |
| $result2 = $this->_expression(); |
| if($this->isError($result2)) { |
| return $result2; |
| } |
| $result = $this->_createTree('ptgLT', $result, $result2); |
| } |
| elseif ($this->_current_token == SPREADSHEET_EXCEL_WRITER_GT) |
| { |
| $this->_advance(); |
| $result2 = $this->_expression(); |
| if($this->isError($result2)) { |
| return $result2; |
| } |
| $result = $this->_createTree('ptgGT', $result, $result2); |
| } |
| elseif ($this->_current_token == SPREADSHEET_EXCEL_WRITER_LE) |
| { |
| $this->_advance(); |
| $result2 = $this->_expression(); |
| if($this->isError($result2)) { |
| return $result2; |
| } |
| $result = $this->_createTree('ptgLE', $result, $result2); |
| } |
| elseif ($this->_current_token == SPREADSHEET_EXCEL_WRITER_GE) |
| { |
| $this->_advance(); |
| $result2 = $this->_expression(); |
| if($this->isError($result2)) { |
| return $result2; |
| } |
| $result = $this->_createTree('ptgGE', $result, $result2); |
| } |
| elseif ($this->_current_token == SPREADSHEET_EXCEL_WRITER_EQ) |
| { |
| $this->_advance(); |
| $result2 = $this->_expression(); |
| if($this->isError($result2)) { |
| return $result2; |
| } |
| $result = $this->_createTree('ptgEQ', $result, $result2); |
| } |
| elseif ($this->_current_token == SPREADSHEET_EXCEL_WRITER_NE) |
| { |
| $this->_advance(); |
| $result2 = $this->_expression(); |
| if($this->isError($result2)) { |
| return $result2; |
| } |
| $result = $this->_createTree('ptgNE', $result, $result2); |
| } |
| return $result; |
| } |
| /** |
| * It parses a expression. It assumes the following rule: |
| * Expr -> Term [("+" | "-") Term] |
| * |
| * @access private |
| * @return mixed The parsed ptg'd tree |
| */ |
| function _expression() |
| { |
| // If it's a string return a string node |
| if (ereg("^\"[^\"]{0,255}\"$", $this->_current_token)) |
| { |
| $result = $this->_createTree($this->_current_token, '', ''); |
| $this->_advance(); |
| return($result); |
| } |
| $result = $this->_term(); |
| if($this->isError($result)) { |
| return($result); |
| } |
| while (($this->_current_token == SPREADSHEET_EXCEL_WRITER_ADD) or |
| ($this->_current_token == SPREADSHEET_EXCEL_WRITER_SUB)) |
| { |
| if ($this->_current_token == SPREADSHEET_EXCEL_WRITER_ADD) |
| { |
| $this->_advance(); |
| $result2 = $this->_term(); |
| if($this->isError($result2)) { |
| return($result2); |
| } |
| $result = $this->_createTree('ptgAdd', $result, $result2); |
| } |
| else |
| { |
| $this->_advance(); |
| $result2 = $this->_term(); |
| if($this->isError($result2)) { |
| return($result2); |
| } |
| $result = $this->_createTree('ptgSub', $result, $result2); |
| } |
| } |
| return($result); |
| } |
| /** |
| * This function just introduces a ptgParen element in the tree, so that Excel |
| * doesn't get confused when working with a parenthesized formula afterwards. |
| * |
| * @access private |
| * @see _fact() |
| * @return mixed The parsed ptg'd tree |
| */ |
| function _parenthesizedExpression() |
| { |
| $result = $this->_createTree('ptgParen', $this->_expression(), ''); |
| return($result); |
| } |
| /** |
| * It parses a term. It assumes the following rule: |
| * Term -> Fact [("*" | "/") Fact] |
| * |
| * @access private |
| * @return mixed The parsed ptg'd tree |
| */ |
| function _term() |
| { |
| $result = $this->_fact(); |
| if($this->isError($result)) { |
| return($result); |
| } |
| while (($this->_current_token == SPREADSHEET_EXCEL_WRITER_MUL) or |
| ($this->_current_token == SPREADSHEET_EXCEL_WRITER_DIV)) |
| { |
| if ($this->_current_token == SPREADSHEET_EXCEL_WRITER_MUL) |
| { |
| $this->_advance(); |
| $result2 = $this->_fact(); |
| if($this->isError($result2)) { |
| return($result2); |
| } |
| $result = $this->_createTree('ptgMul', $result, $result2); |
| } |
| else |
| { |
| $this->_advance(); |
| $result2 = $this->_fact(); |
| if($this->isError($result2)) { |
| return($result2); |
| } |
| $result = $this->_createTree('ptgDiv', $result, $result2); |
| } |
| } |
| return($result); |
| } |
| /** |
| * It parses a factor. It assumes the following rule: |
| * Fact -> ( Expr ) |
| * | CellRef |
| * | CellRange |
| * | Number |
| * | Function |
| * |
| * @access private |
| * @return mixed The parsed ptg'd tree |
| */ |
| function _fact() |
| { |
| if ($this->_current_token == SPREADSHEET_EXCEL_WRITER_OPEN) |
| { |
| $this->_advance(); // eat the "(" |
| $result = $this->_parenthesizedExpression(); |
| if ($this->_current_token != SPREADSHEET_EXCEL_WRITER_CLOSE) { |
| return($this->raiseError("')' token expected.")); |
| } |
| $this->_advance(); // eat the ")" |
| return $result; |
| } |
| // if it's a reference |
| if (preg_match('/^\$?[A-I]?[A-Z]\$?[0-9]+$/',$this->_current_token)) |
| { |
| $result = $this->_createTree($this->_current_token, '', ''); |
| $this->_advance(); |
| return $result; |
| } |
| // If it's an external reference (Sheet1!A1 or Sheet1:Sheet2!A1) |
| elseif (preg_match("/^[A-Za-z0-9_]+(\:[A-Za-z0-9_]+)?\![A-I]?[A-Z][0-9]+$/",$this->_current_token)) |
| { |
| $result = $this->_createTree($this->_current_token, '', ''); |
| $this->_advance(); |
| return $result; |
| } |
| // if it's a range |
| elseif (preg_match("/^(\$)?[A-I]?[A-Z](\$)?[0-9]+:(\$)?[A-I]?[A-Z](\$)?[0-9]+$/",$this->_current_token) or |
| preg_match("/^(\$)?[A-I]?[A-Z](\$)?[0-9]+\.\.(\$)?[A-I]?[A-Z](\$)?[0-9]+$/",$this->_current_token)) |
| { |
| $result = $this->_current_token; |
| $this->_advance(); |
| return $result; |
| } |
| // If it's an external range (Sheet1!A1:B2) |
| elseif (preg_match("/^[A-Za-z0-9_]+(\:[A-Za-z0-9_]+)?\!([A-I]?[A-Z])?[0-9]+:([A-I]?[A-Z])?[0-9]+$/",$this->_current_token)) |
| { |
| $result = $this->_current_token; |
| $this->_advance(); |
| return($result); |
| } |
| elseif (is_numeric($this->_current_token)) |
| { |
| $result = $this->_createTree($this->_current_token, '', ''); |
| $this->_advance(); |
| return($result); |
| } |
| // if it's a function call |
| elseif (eregi("^[A-Z0-9\xc0-\xdc\.]+$",$this->_current_token)) |
| { |
| $result = $this->_func(); |
| return($result); |
| } |
| return($this->raiseError("Sintactic error: ".$this->_current_token.", lookahead: ". |
| $this->_lookahead.", current char: ".$this->_current_char)); |
| } |
| /** |
| * It parses a function call. It assumes the following rule: |
| * Func -> ( Expr [,Expr]* ) |
| * |
| * @access private |
| */ |
| function _func() |
| { |
| $num_args = 0; // number of arguments received |
| $function = $this->_current_token; |
| $this->_advance(); |
| $this->_advance(); // eat the "(" |
| while($this->_current_token != ')') |
| { |
| if($num_args > 0) |
| { |
| if($this->_current_token == SPREADSHEET_EXCEL_WRITER_COMA) { |
| $this->_advance(); // eat the "," |
| } |
| else { |
| return new PEAR_Error("Sintactic error: coma expected in ". |
| "function $function, {$num_args}º arg"); |
| } |
| $result2 = $this->_condition(); |
| if($this->isError($result2)) { |
| return($result2); |
| } |
| $result = $this->_createTree('arg', $result, $result2); |
| } |
| else // first argument |
| { |
| $result2 = $this->_condition(); |
| if($this->isError($result2)) { |
| return($result2); |
| } |
| $result = $this->_createTree('arg', '', $result2); |
| } |
| $num_args++; |
| } |
| $args = $this->_functions[$function][1]; |
| // If fixed number of args eg. TIME($i,$j,$k). Check that the number of args is valid. |
| if (($args >= 0) and ($args != $num_args)) |
| { |
| return($this->raiseError("Incorrect number of arguments in function $function() ")); |
| } |
| $result = $this->_createTree($function, $result, ''); |
| $this->_advance(); // eat the ")" |
| return($result); |
| } |
| /** |
| * Creates a tree. In fact an array which may have one or two arrays (sub-trees) |
| * as elements. |
| * |
| * @access private |
| * @param mixed $value The value of this node. |
| * @param mixed $left The left array (sub-tree) or a final node. |
| * @param mixed $right The right array (sub-tree) or a final node. |
| */ |
| function _createTree($value, $left, $right) |
| { |
| return(array('value' => $value, 'left' => $left, 'right' => $right)); |
| } |
| /** |
| * Builds a string containing the tree in reverse polish notation (What you |
| * would use in a HP calculator stack). |
| * The following tree: |
| * |
| * + |
| * / \ |
| * 2 3 |
| * |
| * produces: "23+" |
| * |
| * The following tree: |
| * |
| * + |
| * / \ |
| * 3 * |
| * / \ |
| * 6 A1 |
| * |
| * produces: "36A1*+" |
| * |
| * In fact all operands, functions, references, etc... are written as ptg's |
| * |
| * @access public |
| * @param array $tree The optional tree to convert. |
| * @return string The tree in reverse polish notation |
| */ |
| function toReversePolish($tree = array()) |
| { |
| $polish = ""; // the string we are going to return |
| if (empty($tree)) // If it's the first call use _parse_tree |
| { |
| $tree = $this->_parse_tree; |
| } |
| if (is_array($tree['left'])) |
| { |
| $converted_tree = $this->toReversePolish($tree['left']); |
| if($this->isError($converted_tree)) { |
| return($converted_tree); |
| } |
| $polish .= $converted_tree; |
| } |
| elseif($tree['left'] != '') // It's a final node |
| { |
| $converted_tree = $this->_convert($tree['left']); |
| if($this->isError($converted_tree)) { |
| return($converted_tree); |
| } |
| $polish .= $converted_tree; |
| } |
| if (is_array($tree['right'])) |
| { |
| $converted_tree = $this->toReversePolish($tree['right']); |
| if($this->isError($converted_tree)) { |
| return($converted_tree); |
| } |
| $polish .= $converted_tree; |
| } |
| elseif($tree['right'] != '') // It's a final node |
| { |
| $converted_tree = $this->_convert($tree['right']); |
| if($this->isError($converted_tree)) { |
| return($converted_tree); |
| } |
| $polish .= $converted_tree; |
| } |
| $converted_tree = $this->_convert($tree['value']); |
| if($this->isError($converted_tree)) { |
| return($converted_tree); |
| } |
| $polish .= $converted_tree; |
| return($polish); |
| } |
| } |
| ?> |
| /trunk/applications/jrest/lib/Spreadsheet/Excel/Writer.php |
|---|
| New file |
| 0,0 → 1,75 |
| <?php |
| /* |
| * Module written/ported by Xavier Noguer <xnoguer@rezebra.com> |
| * |
| * PERL Spreadsheet::WriteExcel module. |
| * |
| * The author of the Spreadsheet::WriteExcel module is John McNamara |
| * <jmcnamara@cpan.org> |
| * |
| * I _DO_ maintain this code, and John McNamara has nothing to do with the |
| * porting of this code to PHP. Any questions directly related to this |
| * class library should be directed to me. |
| * |
| * License Information: |
| * |
| * Spreadsheet_Excel_Writer: A library for generating Excel Spreadsheets |
| * Copyright (c) 2002-2003 Xavier Noguer xnoguer@rezebra.com |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| */ |
| require_once('PEAR.php'); |
| require_once('Writer/Workbook.php'); |
| /** |
| * Class for writing Excel Spreadsheets. This class should change COMPLETELY. |
| * |
| * @author Xavier Noguer <xnoguer@rezebra.com> |
| * @category FileFormats |
| * @package Spreadsheet_Excel_Writer |
| */ |
| class Spreadsheet_Excel_Writer extends Spreadsheet_Excel_Writer_Workbook |
| { |
| /** |
| * The constructor. It just creates a Workbook |
| * |
| * @param string $filename The optional filename for the Workbook. |
| * @return Spreadsheet_Excel_Writer_Workbook The Workbook created |
| */ |
| function Spreadsheet_Excel_Writer($filename = '') |
| { |
| $this->_filename = $filename; |
| $this->Spreadsheet_Excel_Writer_Workbook($filename); |
| } |
| /** |
| * Send HTTP headers for the Excel file. |
| * |
| * @param string $filename The filename to use for HTTP headers |
| * @access public |
| */ |
| function send($filename) |
| { |
| header("Content-type: application/vnd.ms-excel"); |
| header("Content-Disposition: attachment; filename=$filename"); |
| header("Expires: 0"); |
| header("Cache-Control: must-revalidate, post-check=0,pre-check=0"); |
| header("Pragma: public"); |
| } |
| } |
| ?> |
| /trunk/applications/jrest/lib/DB.php |
|---|
| New file |
| 0,0 → 1,1114 |
| <?php |
| /* vim: set expandtab tabstop=4 shiftwidth=4 foldmethod=marker: */ |
| // +----------------------------------------------------------------------+ |
| // | PHP Version 4 | |
| // +----------------------------------------------------------------------+ |
| // | Copyright (c) 1997-2004 The PHP Group | |
| // +----------------------------------------------------------------------+ |
| // | This source file is subject to version 2.02 of the PHP license, | |
| // | that is bundled with this package in the file LICENSE, and is | |
| // | available at through the world-wide-web at | |
| // | http://www.php.net/license/2_02.txt. | |
| // | If you did not receive a copy of the PHP license and are unable to | |
| // | obtain it through the world-wide-web, please send a note to | |
| // | license@php.net so we can mail you a copy immediately. | |
| // +----------------------------------------------------------------------+ |
| // | Authors: Stig Bakken <ssb@php.net> | |
| // | Tomas V.V.Cox <cox@idecnet.com> | |
| // | Maintainer: Daniel Convissor <danielc@php.net> | |
| // +----------------------------------------------------------------------+ |
| // |
| // $Id$ |
| // |
| // Database independent query interface. |
| require_once 'PEAR.php'; |
| // {{{ constants |
| // {{{ error codes |
| /* |
| * The method mapErrorCode in each DB_dbtype implementation maps |
| * native error codes to one of these. |
| * |
| * If you add an error code here, make sure you also add a textual |
| * version of it in DB::errorMessage(). |
| */ |
| define('DB_OK', 1); |
| define('DB_ERROR', -1); |
| define('DB_ERROR_SYNTAX', -2); |
| define('DB_ERROR_CONSTRAINT', -3); |
| define('DB_ERROR_NOT_FOUND', -4); |
| define('DB_ERROR_ALREADY_EXISTS', -5); |
| define('DB_ERROR_UNSUPPORTED', -6); |
| define('DB_ERROR_MISMATCH', -7); |
| define('DB_ERROR_INVALID', -8); |
| define('DB_ERROR_NOT_CAPABLE', -9); |
| define('DB_ERROR_TRUNCATED', -10); |
| define('DB_ERROR_INVALID_NUMBER', -11); |
| define('DB_ERROR_INVALID_DATE', -12); |
| define('DB_ERROR_DIVZERO', -13); |
| define('DB_ERROR_NODBSELECTED', -14); |
| define('DB_ERROR_CANNOT_CREATE', -15); |
| define('DB_ERROR_CANNOT_DELETE', -16); |
| define('DB_ERROR_CANNOT_DROP', -17); |
| define('DB_ERROR_NOSUCHTABLE', -18); |
| define('DB_ERROR_NOSUCHFIELD', -19); |
| define('DB_ERROR_NEED_MORE_DATA', -20); |
| define('DB_ERROR_NOT_LOCKED', -21); |
| define('DB_ERROR_VALUE_COUNT_ON_ROW', -22); |
| define('DB_ERROR_INVALID_DSN', -23); |
| define('DB_ERROR_CONNECT_FAILED', -24); |
| define('DB_ERROR_EXTENSION_NOT_FOUND',-25); |
| define('DB_ERROR_ACCESS_VIOLATION', -26); |
| define('DB_ERROR_NOSUCHDB', -27); |
| define('DB_ERROR_CONSTRAINT_NOT_NULL',-29); |
| // }}} |
| // {{{ prepared statement-related |
| /* |
| * These constants are used when storing information about prepared |
| * statements (using the "prepare" method in DB_dbtype). |
| * |
| * The prepare/execute model in DB is mostly borrowed from the ODBC |
| * extension, in a query the "?" character means a scalar parameter. |
| * There are two extensions though, a "&" character means an opaque |
| * parameter. An opaque parameter is simply a file name, the real |
| * data are in that file (useful for putting uploaded files into your |
| * database and such). The "!" char means a parameter that must be |
| * left as it is. |
| * They modify the quote behavoir: |
| * DB_PARAM_SCALAR (?) => 'original string quoted' |
| * DB_PARAM_OPAQUE (&) => 'string from file quoted' |
| * DB_PARAM_MISC (!) => original string |
| */ |
| define('DB_PARAM_SCALAR', 1); |
| define('DB_PARAM_OPAQUE', 2); |
| define('DB_PARAM_MISC', 3); |
| // }}} |
| // {{{ binary data-related |
| /* |
| * These constants define different ways of returning binary data |
| * from queries. Again, this model has been borrowed from the ODBC |
| * extension. |
| * |
| * DB_BINMODE_PASSTHRU sends the data directly through to the browser |
| * when data is fetched from the database. |
| * DB_BINMODE_RETURN lets you return data as usual. |
| * DB_BINMODE_CONVERT returns data as well, only it is converted to |
| * hex format, for example the string "123" would become "313233". |
| */ |
| define('DB_BINMODE_PASSTHRU', 1); |
| define('DB_BINMODE_RETURN', 2); |
| define('DB_BINMODE_CONVERT', 3); |
| // }}} |
| // {{{ fetch modes |
| /** |
| * This is a special constant that tells DB the user hasn't specified |
| * any particular get mode, so the default should be used. |
| */ |
| define('DB_FETCHMODE_DEFAULT', 0); |
| /** |
| * Column data indexed by numbers, ordered from 0 and up |
| */ |
| define('DB_FETCHMODE_ORDERED', 1); |
| /** |
| * Column data indexed by column names |
| */ |
| define('DB_FETCHMODE_ASSOC', 2); |
| /** |
| * Column data as object properties |
| */ |
| define('DB_FETCHMODE_OBJECT', 3); |
| /** |
| * For multi-dimensional results: normally the first level of arrays |
| * is the row number, and the second level indexed by column number or name. |
| * DB_FETCHMODE_FLIPPED switches this order, so the first level of arrays |
| * is the column name, and the second level the row number. |
| */ |
| define('DB_FETCHMODE_FLIPPED', 4); |
| /* for compatibility */ |
| define('DB_GETMODE_ORDERED', DB_FETCHMODE_ORDERED); |
| define('DB_GETMODE_ASSOC', DB_FETCHMODE_ASSOC); |
| define('DB_GETMODE_FLIPPED', DB_FETCHMODE_FLIPPED); |
| // }}} |
| // {{{ tableInfo() && autoPrepare()-related |
| /** |
| * these are constants for the tableInfo-function |
| * they are bitwised or'ed. so if there are more constants to be defined |
| * in the future, adjust DB_TABLEINFO_FULL accordingly |
| */ |
| define('DB_TABLEINFO_ORDER', 1); |
| define('DB_TABLEINFO_ORDERTABLE', 2); |
| define('DB_TABLEINFO_FULL', 3); |
| /* |
| * Used by autoPrepare() |
| */ |
| define('DB_AUTOQUERY_INSERT', 1); |
| define('DB_AUTOQUERY_UPDATE', 2); |
| // }}} |
| // {{{ portability modes |
| /** |
| * Portability: turn off all portability features. |
| * @see DB_common::setOption() |
| */ |
| define('DB_PORTABILITY_NONE', 0); |
| /** |
| * Portability: convert names of tables and fields to lower case |
| * when using the get*(), fetch*() and tableInfo() methods. |
| * @see DB_common::setOption() |
| */ |
| define('DB_PORTABILITY_LOWERCASE', 1); |
| /** |
| * Portability: right trim the data output by get*() and fetch*(). |
| * @see DB_common::setOption() |
| */ |
| define('DB_PORTABILITY_RTRIM', 2); |
| /** |
| * Portability: force reporting the number of rows deleted. |
| * @see DB_common::setOption() |
| */ |
| define('DB_PORTABILITY_DELETE_COUNT', 4); |
| /** |
| * Portability: enable hack that makes numRows() work in Oracle. |
| * @see DB_common::setOption() |
| */ |
| define('DB_PORTABILITY_NUMROWS', 8); |
| /** |
| * Portability: makes certain error messages in certain drivers compatible |
| * with those from other DBMS's. |
| * |
| * + mysql, mysqli: change unique/primary key constraints |
| * DB_ERROR_ALREADY_EXISTS -> DB_ERROR_CONSTRAINT |
| * |
| * + odbc(access): MS's ODBC driver reports 'no such field' as code |
| * 07001, which means 'too few parameters.' When this option is on |
| * that code gets mapped to DB_ERROR_NOSUCHFIELD. |
| * |
| * @see DB_common::setOption() |
| */ |
| define('DB_PORTABILITY_ERRORS', 16); |
| /** |
| * Portability: convert null values to empty strings in data output by |
| * get*() and fetch*(). |
| * @see DB_common::setOption() |
| */ |
| define('DB_PORTABILITY_NULL_TO_EMPTY', 32); |
| /** |
| * Portability: turn on all portability features. |
| * @see DB_common::setOption() |
| */ |
| define('DB_PORTABILITY_ALL', 63); |
| // }}} |
| // }}} |
| // {{{ class DB |
| /** |
| * The main "DB" class is simply a container class with some static |
| * methods for creating DB objects as well as some utility functions |
| * common to all parts of DB. |
| * |
| * The object model of DB is as follows (indentation means inheritance): |
| * |
| * DB The main DB class. This is simply a utility class |
| * with some "static" methods for creating DB objects as |
| * well as common utility functions for other DB classes. |
| * |
| * DB_common The base for each DB implementation. Provides default |
| * | implementations (in OO lingo virtual methods) for |
| * | the actual DB implementations as well as a bunch of |
| * | query utility functions. |
| * | |
| * +-DB_mysql The DB implementation for MySQL. Inherits DB_common. |
| * When calling DB::factory or DB::connect for MySQL |
| * connections, the object returned is an instance of this |
| * class. |
| * |
| * @package DB |
| * @author Stig Bakken <ssb@php.net> |
| * @author Tomas V.V.Cox <cox@idecnet.com> |
| * @since PHP 4.0 |
| * @version $Id$ |
| * @category Database |
| */ |
| class DB |
| { |
| // {{{ &factory() |
| /** |
| * Create a new DB object for the specified database type. |
| * |
| * Allows creation of a DB_<driver> object from which the object's |
| * methods can be utilized without actually connecting to a database. |
| * |
| * @param string $type database type, for example "mysql" |
| * @param array $options associative array of option names and values |
| * |
| * @return object a new DB object. On error, an error object. |
| * |
| * @see DB_common::setOption() |
| * @access public |
| */ |
| function &factory($type, $options = false) |
| { |
| if (!is_array($options)) { |
| $options = array('persistent' => $options); |
| } |
| if (isset($options['debug']) && $options['debug'] >= 2) { |
| // expose php errors with sufficient debug level |
| include_once "DB/{$type}.php"; |
| } else { |
| @include_once "DB/{$type}.php"; |
| } |
| $classname = "DB_${type}"; |
| if (!class_exists($classname)) { |
| $tmp = PEAR::raiseError(null, DB_ERROR_NOT_FOUND, null, null, |
| "Unable to include the DB/{$type}.php file", |
| 'DB_Error', true); |
| return $tmp; |
| } |
| @$obj =& new $classname; |
| foreach ($options as $option => $value) { |
| $test = $obj->setOption($option, $value); |
| if (DB::isError($test)) { |
| return $test; |
| } |
| } |
| return $obj; |
| } |
| // }}} |
| // {{{ &connect() |
| /** |
| * Create a new DB object and connect to the specified database. |
| * |
| * Example 1. |
| * <code> <?php |
| * require_once 'DB.php'; |
| * |
| * $dsn = 'mysql://user:password@host/database' |
| * $options = array( |
| * 'debug' => 2, |
| * 'portability' => DB_PORTABILITY_ALL, |
| * ); |
| * |
| * $dbh =& DB::connect($dsn, $options); |
| * if (DB::isError($dbh)) { |
| * die($dbh->getMessage()); |
| * } |
| * ?></code> |
| * |
| * @param mixed $dsn string "data source name" or an array in the |
| * format returned by DB::parseDSN() |
| * |
| * @param array $options an associative array of option names and |
| * their values |
| * |
| * @return object a newly created DB connection object, or a DB |
| * error object on error |
| * |
| * @see DB::parseDSN(), DB_common::setOption(), DB::isError() |
| * @access public |
| */ |
| function &connect($dsn, $options = array()) |
| { |
| $dsninfo = DB::parseDSN($dsn); |
| $type = $dsninfo['phptype']; |
| if (!is_array($options)) { |
| /* |
| * For backwards compatibility. $options used to be boolean, |
| * indicating whether the connection should be persistent. |
| */ |
| $options = array('persistent' => $options); |
| } |
| if (isset($options['debug']) && $options['debug'] >= 2) { |
| // expose php errors with sufficient debug level |
| include_once "DB/${type}.php"; |
| } else { |
| @include_once "DB/${type}.php"; |
| } |
| $classname = "DB_${type}"; |
| if (!class_exists($classname)) { |
| $tmp = PEAR::raiseError(null, DB_ERROR_NOT_FOUND, null, null, |
| "Unable to include the DB/{$type}.php file for `$dsn'", |
| 'DB_Error', true); |
| return $tmp; |
| } |
| @$obj =& new $classname; |
| foreach ($options as $option => $value) { |
| $test = $obj->setOption($option, $value); |
| if (DB::isError($test)) { |
| return $test; |
| } |
| } |
| $err = $obj->connect($dsninfo, $obj->getOption('persistent')); |
| if (DB::isError($err)) { |
| $err->addUserInfo($dsn); |
| return $err; |
| } |
| return $obj; |
| } |
| // }}} |
| // {{{ apiVersion() |
| /** |
| * Return the DB API version |
| * |
| * @return int the DB API version number |
| * |
| * @access public |
| */ |
| function apiVersion() |
| { |
| return 2; |
| } |
| // }}} |
| // {{{ isError() |
| /** |
| * Tell whether a result code from a DB method is an error |
| * |
| * @param int $value result code |
| * |
| * @return bool whether $value is an error |
| * |
| * @access public |
| */ |
| function isError($value) |
| { |
| return is_a($value, 'DB_Error'); |
| } |
| // }}} |
| // {{{ isConnection() |
| /** |
| * Tell whether a value is a DB connection |
| * |
| * @param mixed $value value to test |
| * |
| * @return bool whether $value is a DB connection |
| * |
| * @access public |
| */ |
| function isConnection($value) |
| { |
| return (is_object($value) && |
| is_subclass_of($value, 'db_common') && |
| method_exists($value, 'simpleQuery')); |
| } |
| // }}} |
| // {{{ isManip() |
| /** |
| * Tell whether a query is a data manipulation query (insert, |
| * update or delete) or a data definition query (create, drop, |
| * alter, grant, revoke). |
| * |
| * @access public |
| * |
| * @param string $query the query |
| * |
| * @return boolean whether $query is a data manipulation query |
| */ |
| function isManip($query) |
| { |
| $manips = 'INSERT|UPDATE|DELETE|LOAD DATA|'.'REPLACE|CREATE|DROP|'. |
| 'ALTER|GRANT|REVOKE|'.'LOCK|UNLOCK'; |
| if (preg_match('/^\s*"?('.$manips.')\s+/i', $query)) { |
| return true; |
| } |
| return false; |
| } |
| // }}} |
| // {{{ errorMessage() |
| /** |
| * Return a textual error message for a DB error code |
| * |
| * @param integer $value error code |
| * |
| * @return string error message, or false if the error code was |
| * not recognized |
| */ |
| function errorMessage($value) |
| { |
| static $errorMessages; |
| if (!isset($errorMessages)) { |
| $errorMessages = array( |
| DB_ERROR => 'unknown error', |
| DB_ERROR_ALREADY_EXISTS => 'already exists', |
| DB_ERROR_CANNOT_CREATE => 'can not create', |
| DB_ERROR_CANNOT_DELETE => 'can not delete', |
| DB_ERROR_CANNOT_DROP => 'can not drop', |
| DB_ERROR_CONSTRAINT => 'constraint violation', |
| DB_ERROR_CONSTRAINT_NOT_NULL=> 'null value violates not-null constraint', |
| DB_ERROR_DIVZERO => 'division by zero', |
| DB_ERROR_INVALID => 'invalid', |
| DB_ERROR_INVALID_DATE => 'invalid date or time', |
| DB_ERROR_INVALID_NUMBER => 'invalid number', |
| DB_ERROR_MISMATCH => 'mismatch', |
| DB_ERROR_NODBSELECTED => 'no database selected', |
| DB_ERROR_NOSUCHFIELD => 'no such field', |
| DB_ERROR_NOSUCHTABLE => 'no such table', |
| DB_ERROR_NOT_CAPABLE => 'DB backend not capable', |
| DB_ERROR_NOT_FOUND => 'not found', |
| DB_ERROR_NOT_LOCKED => 'not locked', |
| DB_ERROR_SYNTAX => 'syntax error', |
| DB_ERROR_UNSUPPORTED => 'not supported', |
| DB_ERROR_VALUE_COUNT_ON_ROW => 'value count on row', |
| DB_ERROR_INVALID_DSN => 'invalid DSN', |
| DB_ERROR_CONNECT_FAILED => 'connect failed', |
| DB_OK => 'no error', |
| DB_ERROR_NEED_MORE_DATA => 'insufficient data supplied', |
| DB_ERROR_EXTENSION_NOT_FOUND=> 'extension not found', |
| DB_ERROR_NOSUCHDB => 'no such database', |
| DB_ERROR_ACCESS_VIOLATION => 'insufficient permissions', |
| DB_ERROR_TRUNCATED => 'truncated' |
| ); |
| } |
| if (DB::isError($value)) { |
| $value = $value->getCode(); |
| } |
| return isset($errorMessages[$value]) ? $errorMessages[$value] : $errorMessages[DB_ERROR]; |
| } |
| // }}} |
| // {{{ parseDSN() |
| /** |
| * Parse a data source name. |
| * |
| * Additional keys can be added by appending a URI query string to the |
| * end of the DSN. |
| * |
| * The format of the supplied DSN is in its fullest form: |
| * <code> |
| * phptype(dbsyntax)://username:password@protocol+hostspec/database?option=8&another=true |
| * </code> |
| * |
| * Most variations are allowed: |
| * <code> |
| * phptype://username:password@protocol+hostspec:110//usr/db_file.db?mode=0644 |
| * phptype://username:password@hostspec/database_name |
| * phptype://username:password@hostspec |
| * phptype://username@hostspec |
| * phptype://hostspec/database |
| * phptype://hostspec |
| * phptype(dbsyntax) |
| * phptype |
| * </code> |
| * |
| * @param string $dsn Data Source Name to be parsed |
| * |
| * @return array an associative array with the following keys: |
| * + phptype: Database backend used in PHP (mysql, odbc etc.) |
| * + dbsyntax: Database used with regards to SQL syntax etc. |
| * + protocol: Communication protocol to use (tcp, unix etc.) |
| * + hostspec: Host specification (hostname[:port]) |
| * + database: Database to use on the DBMS server |
| * + username: User name for login |
| * + password: Password for login |
| * |
| * @author Tomas V.V.Cox <cox@idecnet.com> |
| */ |
| function parseDSN($dsn) |
| { |
| $parsed = array( |
| 'phptype' => false, |
| 'dbsyntax' => false, |
| 'username' => false, |
| 'password' => false, |
| 'protocol' => false, |
| 'hostspec' => false, |
| 'port' => false, |
| 'socket' => false, |
| 'database' => false, |
| ); |
| if (is_array($dsn)) { |
| $dsn = array_merge($parsed, $dsn); |
| if (!$dsn['dbsyntax']) { |
| $dsn['dbsyntax'] = $dsn['phptype']; |
| } |
| return $dsn; |
| } |
| // Find phptype and dbsyntax |
| if (($pos = strpos($dsn, '://')) !== false) { |
| $str = substr($dsn, 0, $pos); |
| $dsn = substr($dsn, $pos + 3); |
| } else { |
| $str = $dsn; |
| $dsn = null; |
| } |
| // Get phptype and dbsyntax |
| // $str => phptype(dbsyntax) |
| if (preg_match('|^(.+?)\((.*?)\)$|', $str, $arr)) { |
| $parsed['phptype'] = $arr[1]; |
| $parsed['dbsyntax'] = !$arr[2] ? $arr[1] : $arr[2]; |
| } else { |
| $parsed['phptype'] = $str; |
| $parsed['dbsyntax'] = $str; |
| } |
| if (!count($dsn)) { |
| return $parsed; |
| } |
| // Get (if found): username and password |
| // $dsn => username:password@protocol+hostspec/database |
| if (($at = strrpos($dsn,'@')) !== false) { |
| $str = substr($dsn, 0, $at); |
| $dsn = substr($dsn, $at + 1); |
| if (($pos = strpos($str, ':')) !== false) { |
| $parsed['username'] = rawurldecode(substr($str, 0, $pos)); |
| $parsed['password'] = rawurldecode(substr($str, $pos + 1)); |
| } else { |
| $parsed['username'] = rawurldecode($str); |
| } |
| } |
| // Find protocol and hostspec |
| // $dsn => proto(proto_opts)/database |
| if (preg_match('|^([^(]+)\((.*?)\)/?(.*?)$|', $dsn, $match)) { |
| $proto = $match[1]; |
| $proto_opts = $match[2] ? $match[2] : false; |
| $dsn = $match[3]; |
| // $dsn => protocol+hostspec/database (old format) |
| } else { |
| if (strpos($dsn, '+') !== false) { |
| list($proto, $dsn) = explode('+', $dsn, 2); |
| } |
| if (strpos($dsn, '/') !== false) { |
| list($proto_opts, $dsn) = explode('/', $dsn, 2); |
| } else { |
| $proto_opts = $dsn; |
| $dsn = null; |
| } |
| } |
| // process the different protocol options |
| $parsed['protocol'] = (!empty($proto)) ? $proto : 'tcp'; |
| $proto_opts = rawurldecode($proto_opts); |
| if ($parsed['protocol'] == 'tcp') { |
| if (strpos($proto_opts, ':') !== false) { |
| list($parsed['hostspec'], $parsed['port']) = explode(':', $proto_opts); |
| } else { |
| $parsed['hostspec'] = $proto_opts; |
| } |
| } elseif ($parsed['protocol'] == 'unix') { |
| $parsed['socket'] = $proto_opts; |
| } |
| // Get dabase if any |
| // $dsn => database |
| if ($dsn) { |
| // /database |
| if (($pos = strpos($dsn, '?')) === false) { |
| $parsed['database'] = $dsn; |
| // /database?param1=value1¶m2=value2 |
| } else { |
| $parsed['database'] = substr($dsn, 0, $pos); |
| $dsn = substr($dsn, $pos + 1); |
| if (strpos($dsn, '&') !== false) { |
| $opts = explode('&', $dsn); |
| } else { // database?param1=value1 |
| $opts = array($dsn); |
| } |
| foreach ($opts as $opt) { |
| list($key, $value) = explode('=', $opt); |
| if (!isset($parsed[$key])) { |
| // don't allow params overwrite |
| $parsed[$key] = rawurldecode($value); |
| } |
| } |
| } |
| } |
| return $parsed; |
| } |
| // }}} |
| // {{{ assertExtension() |
| /** |
| * Load a PHP database extension if it is not loaded already. |
| * |
| * @access public |
| * |
| * @param string $name the base name of the extension (without the .so or |
| * .dll suffix) |
| * |
| * @return boolean true if the extension was already or successfully |
| * loaded, false if it could not be loaded |
| */ |
| function assertExtension($name) |
| { |
| if (!extension_loaded($name)) { |
| $dlext = OS_WINDOWS ? '.dll' : '.so'; |
| $dlprefix = OS_WINDOWS ? 'php_' : ''; |
| @dl($dlprefix . $name . $dlext); |
| return extension_loaded($name); |
| } |
| return true; |
| } |
| // }}} |
| } |
| // }}} |
| // {{{ class DB_Error |
| /** |
| * DB_Error implements a class for reporting portable database error |
| * messages. |
| * |
| * @package DB |
| * @author Stig Bakken <ssb@php.net> |
| */ |
| class DB_Error extends PEAR_Error |
| { |
| // {{{ constructor |
| /** |
| * DB_Error constructor. |
| * |
| * @param mixed $code DB error code, or string with error message. |
| * @param integer $mode what "error mode" to operate in |
| * @param integer $level what error level to use for $mode & PEAR_ERROR_TRIGGER |
| * @param mixed $debuginfo additional debug info, such as the last query |
| * |
| * @access public |
| * |
| * @see PEAR_Error |
| */ |
| function DB_Error($code = DB_ERROR, $mode = PEAR_ERROR_RETURN, |
| $level = E_USER_NOTICE, $debuginfo = null) |
| { |
| if (is_int($code)) { |
| $this->PEAR_Error('DB Error: ' . DB::errorMessage($code), $code, $mode, $level, $debuginfo); |
| } else { |
| $this->PEAR_Error("DB Error: $code", DB_ERROR, $mode, $level, $debuginfo); |
| } |
| } |
| // }}} |
| } |
| // }}} |
| // {{{ class DB_result |
| /** |
| * This class implements a wrapper for a DB result set. |
| * A new instance of this class will be returned by the DB implementation |
| * after processing a query that returns data. |
| * |
| * @package DB |
| * @author Stig Bakken <ssb@php.net> |
| */ |
| class DB_result |
| { |
| // {{{ properties |
| var $dbh; |
| var $result; |
| var $row_counter = null; |
| /** |
| * for limit queries, the row to start fetching |
| * @var integer |
| */ |
| var $limit_from = null; |
| /** |
| * for limit queries, the number of rows to fetch |
| * @var integer |
| */ |
| var $limit_count = null; |
| // }}} |
| // {{{ constructor |
| /** |
| * DB_result constructor. |
| * @param resource &$dbh DB object reference |
| * @param resource $result result resource id |
| * @param array $options assoc array with optional result options |
| */ |
| function DB_result(&$dbh, $result, $options = array()) |
| { |
| $this->dbh = &$dbh; |
| $this->result = $result; |
| foreach ($options as $key => $value) { |
| $this->setOption($key, $value); |
| } |
| $this->limit_type = $dbh->features['limit']; |
| $this->autofree = $dbh->options['autofree']; |
| $this->fetchmode = $dbh->fetchmode; |
| $this->fetchmode_object_class = $dbh->fetchmode_object_class; |
| } |
| function setOption($key, $value = null) |
| { |
| switch ($key) { |
| case 'limit_from': |
| $this->limit_from = $value; break; |
| case 'limit_count': |
| $this->limit_count = $value; break; |
| } |
| } |
| // }}} |
| // {{{ fetchRow() |
| /** |
| * Fetch a row of data and return it by reference into an array. |
| * |
| * The type of array returned can be controlled either by setting this |
| * method's <var>$fetchmode</var> parameter or by changing the default |
| * fetch mode setFetchMode() before calling this method. |
| * |
| * There are two options for standardizing the information returned |
| * from databases, ensuring their values are consistent when changing |
| * DBMS's. These portability options can be turned on when creating a |
| * new DB object or by using setOption(). |
| * |
| * + <samp>DB_PORTABILITY_LOWERCASE</samp> |
| * convert names of fields to lower case |
| * |
| * + <samp>DB_PORTABILITY_RTRIM</samp> |
| * right trim the data |
| * |
| * @param int $fetchmode how the resulting array should be indexed |
| * @param int $rownum the row number to fetch |
| * |
| * @return array a row of data, null on no more rows or PEAR_Error |
| * object on error |
| * |
| * @see DB_common::setOption(), DB_common::setFetchMode() |
| * @access public |
| */ |
| function &fetchRow($fetchmode = DB_FETCHMODE_DEFAULT, $rownum=null) |
| { |
| if ($fetchmode === DB_FETCHMODE_DEFAULT) { |
| $fetchmode = $this->fetchmode; |
| } |
| if ($fetchmode === DB_FETCHMODE_OBJECT) { |
| $fetchmode = DB_FETCHMODE_ASSOC; |
| $object_class = $this->fetchmode_object_class; |
| } |
| if ($this->limit_from !== null) { |
| if ($this->row_counter === null) { |
| $this->row_counter = $this->limit_from; |
| // Skip rows |
| if ($this->limit_type == false) { |
| $i = 0; |
| while ($i++ < $this->limit_from) { |
| $this->dbh->fetchInto($this->result, $arr, $fetchmode); |
| } |
| } |
| } |
| if ($this->row_counter >= ( |
| $this->limit_from + $this->limit_count)) |
| { |
| if ($this->autofree) { |
| $this->free(); |
| } |
| $tmp = null; |
| return $tmp; |
| } |
| if ($this->limit_type == 'emulate') { |
| $rownum = $this->row_counter; |
| } |
| $this->row_counter++; |
| } |
| $res = $this->dbh->fetchInto($this->result, $arr, $fetchmode, $rownum); |
| if ($res === DB_OK) { |
| if (isset($object_class)) { |
| // default mode specified in DB_common::fetchmode_object_class property |
| if ($object_class == 'stdClass') { |
| $arr = (object) $arr; |
| } else { |
| $arr = &new $object_class($arr); |
| } |
| } |
| return $arr; |
| } |
| if ($res == null && $this->autofree) { |
| $this->free(); |
| } |
| return $res; |
| } |
| // }}} |
| // {{{ fetchInto() |
| /** |
| * Fetch a row of data into an array which is passed by reference. |
| * |
| * The type of array returned can be controlled either by setting this |
| * method's <var>$fetchmode</var> parameter or by changing the default |
| * fetch mode setFetchMode() before calling this method. |
| * |
| * There are two options for standardizing the information returned |
| * from databases, ensuring their values are consistent when changing |
| * DBMS's. These portability options can be turned on when creating a |
| * new DB object or by using setOption(). |
| * |
| * + <samp>DB_PORTABILITY_LOWERCASE</samp> |
| * convert names of fields to lower case |
| * |
| * + <samp>DB_PORTABILITY_RTRIM</samp> |
| * right trim the data |
| * |
| * @param array &$arr (reference) array where data from the row |
| * should be placed |
| * @param int $fetchmode how the resulting array should be indexed |
| * @param int $rownum the row number to fetch |
| * |
| * @return mixed DB_OK on success, null on no more rows or |
| * a DB_Error object on error |
| * |
| * @see DB_common::setOption(), DB_common::setFetchMode() |
| * @access public |
| */ |
| function fetchInto(&$arr, $fetchmode = DB_FETCHMODE_DEFAULT, $rownum=null) |
| { |
| if ($fetchmode === DB_FETCHMODE_DEFAULT) { |
| $fetchmode = $this->fetchmode; |
| } |
| if ($fetchmode === DB_FETCHMODE_OBJECT) { |
| $fetchmode = DB_FETCHMODE_ASSOC; |
| $object_class = $this->fetchmode_object_class; |
| } |
| if ($this->limit_from !== null) { |
| if ($this->row_counter === null) { |
| $this->row_counter = $this->limit_from; |
| // Skip rows |
| if ($this->limit_type == false) { |
| $i = 0; |
| while ($i++ < $this->limit_from) { |
| $this->dbh->fetchInto($this->result, $arr, $fetchmode); |
| } |
| } |
| } |
| if ($this->row_counter >= ( |
| $this->limit_from + $this->limit_count)) |
| { |
| if ($this->autofree) { |
| $this->free(); |
| } |
| return null; |
| } |
| if ($this->limit_type == 'emulate') { |
| $rownum = $this->row_counter; |
| } |
| $this->row_counter++; |
| } |
| $res = $this->dbh->fetchInto($this->result, $arr, $fetchmode, $rownum); |
| if ($res === DB_OK) { |
| if (isset($object_class)) { |
| // default mode specified in DB_common::fetchmode_object_class property |
| if ($object_class == 'stdClass') { |
| $arr = (object) $arr; |
| } else { |
| $arr = new $object_class($arr); |
| } |
| } |
| return DB_OK; |
| } |
| if ($res == null && $this->autofree) { |
| $this->free(); |
| } |
| return $res; |
| } |
| // }}} |
| // {{{ numCols() |
| /** |
| * Get the the number of columns in a result set. |
| * |
| * @return int the number of columns, or a DB error |
| * |
| * @access public |
| */ |
| function numCols() |
| { |
| return $this->dbh->numCols($this->result); |
| } |
| // }}} |
| // {{{ numRows() |
| /** |
| * Get the number of rows in a result set. |
| * |
| * @return int the number of rows, or a DB error |
| * |
| * @access public |
| */ |
| function numRows() |
| { |
| return $this->dbh->numRows($this->result); |
| } |
| // }}} |
| // {{{ nextResult() |
| /** |
| * Get the next result if a batch of queries was executed. |
| * |
| * @return bool true if a new result is available or false if not. |
| * |
| * @access public |
| */ |
| function nextResult() |
| { |
| return $this->dbh->nextResult($this->result); |
| } |
| // }}} |
| // {{{ free() |
| /** |
| * Frees the resources allocated for this result set. |
| * @return int error code |
| * |
| * @access public |
| */ |
| function free() |
| { |
| $err = $this->dbh->freeResult($this->result); |
| if (DB::isError($err)) { |
| return $err; |
| } |
| $this->result = false; |
| return true; |
| } |
| // }}} |
| // {{{ tableInfo() |
| /** |
| * @deprecated |
| * @internal |
| * @see DB_common::tableInfo() |
| */ |
| function tableInfo($mode = null) |
| { |
| if (is_string($mode)) { |
| return $this->dbh->raiseError(DB_ERROR_NEED_MORE_DATA); |
| } |
| return $this->dbh->tableInfo($this, $mode); |
| } |
| // }}} |
| // {{{ getRowCounter() |
| /** |
| * returns the actual row number |
| * @return integer |
| */ |
| function getRowCounter() |
| { |
| return $this->row_counter; |
| } |
| // }}} |
| } |
| // }}} |
| // {{{ class DB_row |
| /** |
| * Pear DB Row Object |
| * @see DB_common::setFetchMode() |
| */ |
| class DB_row |
| { |
| // {{{ constructor |
| /** |
| * constructor |
| * |
| * @param resource row data as array |
| */ |
| function DB_row(&$arr) |
| { |
| foreach ($arr as $key => $value) { |
| $this->$key = &$arr[$key]; |
| } |
| } |
| // }}} |
| } |
| // }}} |
| /* |
| * Local variables: |
| * tab-width: 4 |
| * c-basic-offset: 4 |
| * End: |
| */ |
| ?> |
| /trunk/applications/jrest/lib/PEAR.php |
|---|
| New file |
| 0,0 → 1,971 |
| <?php |
| // |
| // +----------------------------------------------------------------------+ |
| // | PEAR, the PHP Extension and Application Repository | |
| // +----------------------------------------------------------------------+ |
| // | Copyright (c) 1997-2004 The PHP Group | |
| // +----------------------------------------------------------------------+ |
| // | This source file is subject to version 2.0 of the PHP license, | |
| // | that is bundled with this package in the file LICENSE, and is | |
| // | available through the world-wide-web at the following url: | |
| // | http://www.php.net/license/3_0.txt. | |
| // | If you did not receive a copy of the PHP license and are unable to | |
| // | obtain it through the world-wide-web, please send a note to | |
| // | license@php.net so we can mail you a copy immediately. | |
| // +----------------------------------------------------------------------+ |
| // | Authors: Sterling Hughes <sterling@php.net> | |
| // | Stig Bakken <ssb@php.net> | |
| // | Tomas V.V.Cox <cox@idecnet.com> | |
| // +----------------------------------------------------------------------+ |
| // |
| // $Id$ |
| // |
| define('PEAR_ERROR_RETURN', 1); |
| define('PEAR_ERROR_PRINT', 2); |
| define('PEAR_ERROR_TRIGGER', 4); |
| define('PEAR_ERROR_DIE', 8); |
| define('PEAR_ERROR_CALLBACK', 16); |
| define('PEAR_ERROR_EXCEPTION', 32); |
| define('PEAR_ZE2', (function_exists('version_compare') && |
| version_compare(zend_version(), "2-dev", "ge"))); |
| if (substr(PHP_OS, 0, 3) == 'WIN') { |
| define('OS_WINDOWS', true); |
| define('OS_UNIX', false); |
| define('PEAR_OS', 'Windows'); |
| } else { |
| define('OS_WINDOWS', false); |
| define('OS_UNIX', true); |
| define('PEAR_OS', 'Unix'); // blatant assumption |
| } |
| // instant backwards compatibility |
| if (!defined('PATH_SEPARATOR')) { |
| if (OS_WINDOWS) { |
| define('PATH_SEPARATOR', ';'); |
| } else { |
| define('PATH_SEPARATOR', ':'); |
| } |
| } |
| $GLOBALS['_PEAR_default_error_mode'] = PEAR_ERROR_RETURN; |
| $GLOBALS['_PEAR_default_error_options'] = E_USER_NOTICE; |
| $GLOBALS['_PEAR_destructor_object_list'] = array(); |
| $GLOBALS['_PEAR_shutdown_funcs'] = array(); |
| $GLOBALS['_PEAR_error_handler_stack'] = array(); |
| ini_set('track_errors', true); |
| /** |
| * Base class for other PEAR classes. Provides rudimentary |
| * emulation of destructors. |
| * |
| * If you want a destructor in your class, inherit PEAR and make a |
| * destructor method called _yourclassname (same name as the |
| * constructor, but with a "_" prefix). Also, in your constructor you |
| * have to call the PEAR constructor: $this->PEAR();. |
| * The destructor method will be called without parameters. Note that |
| * at in some SAPI implementations (such as Apache), any output during |
| * the request shutdown (in which destructors are called) seems to be |
| * discarded. If you need to get any debug information from your |
| * destructor, use error_log(), syslog() or something similar. |
| * |
| * IMPORTANT! To use the emulated destructors you need to create the |
| * objects by reference: $obj =& new PEAR_child; |
| * |
| * @since PHP 4.0.2 |
| * @author Stig Bakken <ssb@php.net> |
| * @see http://pear.php.net/manual/ |
| */ |
| class PEAR |
| { |
| // {{{ properties |
| /** |
| * Whether to enable internal debug messages. |
| * |
| * @var bool |
| * @access private |
| */ |
| var $_debug = false; |
| /** |
| * Default error mode for this object. |
| * |
| * @var int |
| * @access private |
| */ |
| var $_default_error_mode = null; |
| /** |
| * Default error options used for this object when error mode |
| * is PEAR_ERROR_TRIGGER. |
| * |
| * @var int |
| * @access private |
| */ |
| var $_default_error_options = null; |
| /** |
| * Default error handler (callback) for this object, if error mode is |
| * PEAR_ERROR_CALLBACK. |
| * |
| * @var string |
| * @access private |
| */ |
| var $_default_error_handler = ''; |
| /** |
| * Which class to use for error objects. |
| * |
| * @var string |
| * @access private |
| */ |
| var $_error_class = 'PEAR_Error'; |
| /** |
| * An array of expected errors. |
| * |
| * @var array |
| * @access private |
| */ |
| var $_expected_errors = array(); |
| // }}} |
| // {{{ constructor |
| /** |
| * Constructor. Registers this object in |
| * $_PEAR_destructor_object_list for destructor emulation if a |
| * destructor object exists. |
| * |
| * @param string $error_class (optional) which class to use for |
| * error objects, defaults to PEAR_Error. |
| * @access public |
| * @return void |
| */ |
| function PEAR($error_class = null) |
| { |
| $classname = get_class($this); |
| if ($this->_debug) { |
| print "PEAR constructor called, class=$classname\n"; |
| } |
| if ($error_class !== null) { |
| $this->_error_class = $error_class; |
| } |
| while ($classname) { |
| $destructor = "_$classname"; |
| if (method_exists($this, $destructor)) { |
| global $_PEAR_destructor_object_list; |
| $_PEAR_destructor_object_list[] = &$this; |
| break; |
| } else { |
| $classname = get_parent_class($classname); |
| } |
| } |
| } |
| // }}} |
| // {{{ destructor |
| /** |
| * Destructor (the emulated type of...). Does nothing right now, |
| * but is included for forward compatibility, so subclass |
| * destructors should always call it. |
| * |
| * See the note in the class desciption about output from |
| * destructors. |
| * |
| * @access public |
| * @return void |
| */ |
| function _PEAR() { |
| if ($this->_debug) { |
| printf("PEAR destructor called, class=%s\n", get_class($this)); |
| } |
| } |
| // }}} |
| // {{{ getStaticProperty() |
| /** |
| * If you have a class that's mostly/entirely static, and you need static |
| * properties, you can use this method to simulate them. Eg. in your method(s) |
| * do this: $myVar = &PEAR::getStaticProperty('myVar'); |
| * You MUST use a reference, or they will not persist! |
| * |
| * @access public |
| * @param string $class The calling classname, to prevent clashes |
| * @param string $var The variable to retrieve. |
| * @return mixed A reference to the variable. If not set it will be |
| * auto initialised to NULL. |
| */ |
| function &getStaticProperty($class, $var) |
| { |
| static $properties; |
| return $properties[$class][$var]; |
| } |
| // }}} |
| // {{{ registerShutdownFunc() |
| /** |
| * Use this function to register a shutdown method for static |
| * classes. |
| * |
| * @access public |
| * @param mixed $func The function name (or array of class/method) to call |
| * @param mixed $args The arguments to pass to the function |
| * @return void |
| */ |
| function registerShutdownFunc($func, $args = array()) |
| { |
| $GLOBALS['_PEAR_shutdown_funcs'][] = array($func, $args); |
| } |
| // }}} |
| // {{{ isError() |
| /** |
| * Tell whether a value is a PEAR error. |
| * |
| * @param mixed $data the value to test |
| * @param int $code if $data is an error object, return true |
| * only if $code is a string and |
| * $obj->getMessage() == $code or |
| * $code is an integer and $obj->getCode() == $code |
| * @access public |
| * @return bool true if parameter is an error |
| */ |
| function isError($data, $code = null) |
| { |
| if (is_a($data, 'PEAR_Error')) { |
| if (is_null($code)) { |
| return true; |
| } elseif (is_string($code)) { |
| return $data->getMessage() == $code; |
| } else { |
| return $data->getCode() == $code; |
| } |
| } |
| return false; |
| } |
| // }}} |
| // {{{ setErrorHandling() |
| /** |
| * Sets how errors generated by this object should be handled. |
| * Can be invoked both in objects and statically. If called |
| * statically, setErrorHandling sets the default behaviour for all |
| * PEAR objects. If called in an object, setErrorHandling sets |
| * the default behaviour for that object. |
| * |
| * @param int $mode |
| * One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT, |
| * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE, |
| * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION. |
| * |
| * @param mixed $options |
| * When $mode is PEAR_ERROR_TRIGGER, this is the error level (one |
| * of E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR). |
| * |
| * When $mode is PEAR_ERROR_CALLBACK, this parameter is expected |
| * to be the callback function or method. A callback |
| * function is a string with the name of the function, a |
| * callback method is an array of two elements: the element |
| * at index 0 is the object, and the element at index 1 is |
| * the name of the method to call in the object. |
| * |
| * When $mode is PEAR_ERROR_PRINT or PEAR_ERROR_DIE, this is |
| * a printf format string used when printing the error |
| * message. |
| * |
| * @access public |
| * @return void |
| * @see PEAR_ERROR_RETURN |
| * @see PEAR_ERROR_PRINT |
| * @see PEAR_ERROR_TRIGGER |
| * @see PEAR_ERROR_DIE |
| * @see PEAR_ERROR_CALLBACK |
| * @see PEAR_ERROR_EXCEPTION |
| * |
| * @since PHP 4.0.5 |
| */ |
| function setErrorHandling($mode = null, $options = null) |
| { |
| if (isset($this) && is_a($this, 'PEAR')) { |
| $setmode = &$this->_default_error_mode; |
| $setoptions = &$this->_default_error_options; |
| } else { |
| $setmode = &$GLOBALS['_PEAR_default_error_mode']; |
| $setoptions = &$GLOBALS['_PEAR_default_error_options']; |
| } |
| switch ($mode) { |
| case PEAR_ERROR_RETURN: |
| case PEAR_ERROR_PRINT: |
| case PEAR_ERROR_TRIGGER: |
| case PEAR_ERROR_DIE: |
| case PEAR_ERROR_EXCEPTION: |
| case null: |
| $setmode = $mode; |
| $setoptions = $options; |
| break; |
| case PEAR_ERROR_CALLBACK: |
| $setmode = $mode; |
| // class/object method callback |
| if (is_callable($options)) { |
| $setoptions = $options; |
| } else { |
| trigger_error("invalid error callback", E_USER_WARNING); |
| } |
| break; |
| default: |
| trigger_error("invalid error mode", E_USER_WARNING); |
| break; |
| } |
| } |
| // }}} |
| // {{{ expectError() |
| /** |
| * This method is used to tell which errors you expect to get. |
| * Expected errors are always returned with error mode |
| * PEAR_ERROR_RETURN. Expected error codes are stored in a stack, |
| * and this method pushes a new element onto it. The list of |
| * expected errors are in effect until they are popped off the |
| * stack with the popExpect() method. |
| * |
| * Note that this method can not be called statically |
| * |
| * @param mixed $code a single error code or an array of error codes to expect |
| * |
| * @return int the new depth of the "expected errors" stack |
| * @access public |
| */ |
| function expectError($code = '*') |
| { |
| if (is_array($code)) { |
| array_push($this->_expected_errors, $code); |
| } else { |
| array_push($this->_expected_errors, array($code)); |
| } |
| return sizeof($this->_expected_errors); |
| } |
| // }}} |
| // {{{ popExpect() |
| /** |
| * This method pops one element off the expected error codes |
| * stack. |
| * |
| * @return array the list of error codes that were popped |
| */ |
| function popExpect() |
| { |
| return array_pop($this->_expected_errors); |
| } |
| // }}} |
| // {{{ _checkDelExpect() |
| /** |
| * This method checks unsets an error code if available |
| * |
| * @param mixed error code |
| * @return bool true if the error code was unset, false otherwise |
| * @access private |
| * @since PHP 4.3.0 |
| */ |
| function _checkDelExpect($error_code) |
| { |
| $deleted = false; |
| foreach ($this->_expected_errors AS $key => $error_array) { |
| if (in_array($error_code, $error_array)) { |
| unset($this->_expected_errors[$key][array_search($error_code, $error_array)]); |
| $deleted = true; |
| } |
| // clean up empty arrays |
| if (0 == count($this->_expected_errors[$key])) { |
| unset($this->_expected_errors[$key]); |
| } |
| } |
| return $deleted; |
| } |
| // }}} |
| // {{{ delExpect() |
| /** |
| * This method deletes all occurences of the specified element from |
| * the expected error codes stack. |
| * |
| * @param mixed $error_code error code that should be deleted |
| * @return mixed list of error codes that were deleted or error |
| * @access public |
| * @since PHP 4.3.0 |
| */ |
| function delExpect($error_code) |
| { |
| $deleted = false; |
| if ((is_array($error_code) && (0 != count($error_code)))) { |
| // $error_code is a non-empty array here; |
| // we walk through it trying to unset all |
| // values |
| foreach($error_code as $key => $error) { |
| if ($this->_checkDelExpect($error)) { |
| $deleted = true; |
| } else { |
| $deleted = false; |
| } |
| } |
| return $deleted ? true : PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME |
| } elseif (!empty($error_code)) { |
| // $error_code comes alone, trying to unset it |
| if ($this->_checkDelExpect($error_code)) { |
| return true; |
| } else { |
| return PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME |
| } |
| } else { |
| // $error_code is empty |
| return PEAR::raiseError("The expected error you submitted is empty"); // IMPROVE ME |
| } |
| } |
| // }}} |
| // {{{ raiseError() |
| /** |
| * This method is a wrapper that returns an instance of the |
| * configured error class with this object's default error |
| * handling applied. If the $mode and $options parameters are not |
| * specified, the object's defaults are used. |
| * |
| * @param mixed $message a text error message or a PEAR error object |
| * |
| * @param int $code a numeric error code (it is up to your class |
| * to define these if you want to use codes) |
| * |
| * @param int $mode One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT, |
| * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE, |
| * PEAR_ERROR_CALLBACK, PEAR_ERROR_EXCEPTION. |
| * |
| * @param mixed $options If $mode is PEAR_ERROR_TRIGGER, this parameter |
| * specifies the PHP-internal error level (one of |
| * E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR). |
| * If $mode is PEAR_ERROR_CALLBACK, this |
| * parameter specifies the callback function or |
| * method. In other error modes this parameter |
| * is ignored. |
| * |
| * @param string $userinfo If you need to pass along for example debug |
| * information, this parameter is meant for that. |
| * |
| * @param string $error_class The returned error object will be |
| * instantiated from this class, if specified. |
| * |
| * @param bool $skipmsg If true, raiseError will only pass error codes, |
| * the error message parameter will be dropped. |
| * |
| * @access public |
| * @return object a PEAR error object |
| * @see PEAR::setErrorHandling |
| * @since PHP 4.0.5 |
| */ |
| function raiseError($message = null, |
| $code = null, |
| $mode = null, |
| $options = null, |
| $userinfo = null, |
| $error_class = null, |
| $skipmsg = false) |
| { |
| // The error is yet a PEAR error object |
| if (is_object($message)) { |
| $code = $message->getCode(); |
| $userinfo = $message->getUserInfo(); |
| $error_class = $message->getType(); |
| $message->error_message_prefix = ''; |
| $message = $message->getMessage(); |
| } |
| if (isset($this) && isset($this->_expected_errors) && sizeof($this->_expected_errors) > 0 && sizeof($exp = end($this->_expected_errors))) { |
| if ($exp[0] == "*" || |
| (is_int(reset($exp)) && in_array($code, $exp)) || |
| (is_string(reset($exp)) && in_array($message, $exp))) { |
| $mode = PEAR_ERROR_RETURN; |
| } |
| } |
| // No mode given, try global ones |
| if ($mode === null) { |
| // Class error handler |
| if (isset($this) && isset($this->_default_error_mode)) { |
| $mode = $this->_default_error_mode; |
| $options = $this->_default_error_options; |
| // Global error handler |
| } elseif (isset($GLOBALS['_PEAR_default_error_mode'])) { |
| $mode = $GLOBALS['_PEAR_default_error_mode']; |
| $options = $GLOBALS['_PEAR_default_error_options']; |
| } |
| } |
| if ($error_class !== null) { |
| $ec = $error_class; |
| } elseif (isset($this) && isset($this->_error_class)) { |
| $ec = $this->_error_class; |
| } else { |
| $ec = 'PEAR_Error'; |
| } |
| if ($skipmsg) { |
| return new $ec($code, $mode, $options, $userinfo); |
| } else { |
| return new $ec($message, $code, $mode, $options, $userinfo); |
| } |
| } |
| // }}} |
| // {{{ throwError() |
| /** |
| * Simpler form of raiseError with fewer options. In most cases |
| * message, code and userinfo are enough. |
| * |
| * @param string $message |
| * |
| */ |
| function throwError($message = null, |
| $code = null, |
| $userinfo = null) |
| { |
| if (isset($this) && is_subclass_of($this, 'PEAR_Error')) { |
| return $this->raiseError($message, $code, null, null, $userinfo); |
| } else { |
| return PEAR::raiseError($message, $code, null, null, $userinfo); |
| } |
| } |
| // }}} |
| // {{{ pushErrorHandling() |
| /** |
| * Push a new error handler on top of the error handler options stack. With this |
| * you can easily override the actual error handler for some code and restore |
| * it later with popErrorHandling. |
| * |
| * @param mixed $mode (same as setErrorHandling) |
| * @param mixed $options (same as setErrorHandling) |
| * |
| * @return bool Always true |
| * |
| * @see PEAR::setErrorHandling |
| */ |
| function pushErrorHandling($mode, $options = null) |
| { |
| $stack = &$GLOBALS['_PEAR_error_handler_stack']; |
| if (isset($this) && is_a($this, 'PEAR')) { |
| $def_mode = &$this->_default_error_mode; |
| $def_options = &$this->_default_error_options; |
| } else { |
| $def_mode = &$GLOBALS['_PEAR_default_error_mode']; |
| $def_options = &$GLOBALS['_PEAR_default_error_options']; |
| } |
| $stack[] = array($def_mode, $def_options); |
| if (isset($this) && is_a($this, 'PEAR')) { |
| $this->setErrorHandling($mode, $options); |
| } else { |
| PEAR::setErrorHandling($mode, $options); |
| } |
| $stack[] = array($mode, $options); |
| return true; |
| } |
| // }}} |
| // {{{ popErrorHandling() |
| /** |
| * Pop the last error handler used |
| * |
| * @return bool Always true |
| * |
| * @see PEAR::pushErrorHandling |
| */ |
| function popErrorHandling() |
| { |
| $stack = &$GLOBALS['_PEAR_error_handler_stack']; |
| array_pop($stack); |
| list($mode, $options) = $stack[sizeof($stack) - 1]; |
| array_pop($stack); |
| if (isset($this) && is_a($this, 'PEAR')) { |
| $this->setErrorHandling($mode, $options); |
| } else { |
| PEAR::setErrorHandling($mode, $options); |
| } |
| return true; |
| } |
| // }}} |
| // {{{ loadExtension() |
| /** |
| * OS independant PHP extension load. Remember to take care |
| * on the correct extension name for case sensitive OSes. |
| * |
| * @param string $ext The extension name |
| * @return bool Success or not on the dl() call |
| */ |
| function loadExtension($ext) |
| { |
| if (!extension_loaded($ext)) { |
| // if either returns true dl() will produce a FATAL error, stop that |
| if ((ini_get('enable_dl') != 1) || (ini_get('safe_mode') == 1)) { |
| return false; |
| } |
| if (OS_WINDOWS) { |
| $suffix = '.dll'; |
| } elseif (PHP_OS == 'HP-UX') { |
| $suffix = '.sl'; |
| } elseif (PHP_OS == 'AIX') { |
| $suffix = '.a'; |
| } elseif (PHP_OS == 'OSX') { |
| $suffix = '.bundle'; |
| } else { |
| $suffix = '.so'; |
| } |
| return @dl('php_'.$ext.$suffix) || @dl($ext.$suffix); |
| } |
| return true; |
| } |
| // }}} |
| } |
| // {{{ _PEAR_call_destructors() |
| function _PEAR_call_destructors() |
| { |
| global $_PEAR_destructor_object_list; |
| if (is_array($_PEAR_destructor_object_list) && |
| sizeof($_PEAR_destructor_object_list)) |
| { |
| reset($_PEAR_destructor_object_list); |
| while (list($k, $objref) = each($_PEAR_destructor_object_list)) { |
| $classname = get_class($objref); |
| while ($classname) { |
| $destructor = "_$classname"; |
| if (method_exists($objref, $destructor)) { |
| $objref->$destructor(); |
| break; |
| } else { |
| $classname = get_parent_class($classname); |
| } |
| } |
| } |
| // Empty the object list to ensure that destructors are |
| // not called more than once. |
| $_PEAR_destructor_object_list = array(); |
| } |
| // Now call the shutdown functions |
| if (is_array($GLOBALS['_PEAR_shutdown_funcs']) AND !empty($GLOBALS['_PEAR_shutdown_funcs'])) { |
| foreach ($GLOBALS['_PEAR_shutdown_funcs'] as $value) { |
| call_user_func_array($value[0], $value[1]); |
| } |
| } |
| } |
| // }}} |
| class PEAR_Error |
| { |
| // {{{ properties |
| var $error_message_prefix = ''; |
| var $mode = PEAR_ERROR_RETURN; |
| var $level = E_USER_NOTICE; |
| var $code = -1; |
| var $message = ''; |
| var $userinfo = ''; |
| var $backtrace = null; |
| // }}} |
| // {{{ constructor |
| /** |
| * PEAR_Error constructor |
| * |
| * @param string $message message |
| * |
| * @param int $code (optional) error code |
| * |
| * @param int $mode (optional) error mode, one of: PEAR_ERROR_RETURN, |
| * PEAR_ERROR_PRINT, PEAR_ERROR_DIE, PEAR_ERROR_TRIGGER, |
| * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION |
| * |
| * @param mixed $options (optional) error level, _OR_ in the case of |
| * PEAR_ERROR_CALLBACK, the callback function or object/method |
| * tuple. |
| * |
| * @param string $userinfo (optional) additional user/debug info |
| * |
| * @access public |
| * |
| */ |
| function PEAR_Error($message = 'unknown error', $code = null, |
| $mode = null, $options = null, $userinfo = null) |
| { |
| if ($mode === null) { |
| $mode = PEAR_ERROR_RETURN; |
| } |
| $this->message = $message; |
| $this->code = $code; |
| $this->mode = $mode; |
| $this->userinfo = $userinfo; |
| if (function_exists("debug_backtrace")) { |
| $this->backtrace = debug_backtrace(); |
| } |
| if ($mode & PEAR_ERROR_CALLBACK) { |
| $this->level = E_USER_NOTICE; |
| $this->callback = $options; |
| } else { |
| if ($options === null) { |
| $options = E_USER_NOTICE; |
| } |
| $this->level = $options; |
| $this->callback = null; |
| } |
| if ($this->mode & PEAR_ERROR_PRINT) { |
| if (is_null($options) || is_int($options)) { |
| $format = "%s"; |
| } else { |
| $format = $options; |
| } |
| printf($format, $this->getMessage()); |
| } |
| if ($this->mode & PEAR_ERROR_TRIGGER) { |
| trigger_error($this->getMessage(), $this->level); |
| } |
| if ($this->mode & PEAR_ERROR_DIE) { |
| $msg = $this->getMessage(); |
| if (is_null($options) || is_int($options)) { |
| $format = "%s"; |
| if (substr($msg, -1) != "\n") { |
| $msg .= "\n"; |
| } |
| } else { |
| $format = $options; |
| } |
| die(sprintf($format, $msg)); |
| } |
| if ($this->mode & PEAR_ERROR_CALLBACK) { |
| if (is_callable($this->callback)) { |
| call_user_func($this->callback, $this); |
| } |
| } |
| if (PEAR_ZE2 && $this->mode & PEAR_ERROR_EXCEPTION) { |
| eval('throw $this;'); |
| } |
| } |
| // }}} |
| // {{{ getMode() |
| /** |
| * Get the error mode from an error object. |
| * |
| * @return int error mode |
| * @access public |
| */ |
| function getMode() { |
| return $this->mode; |
| } |
| // }}} |
| // {{{ getCallback() |
| /** |
| * Get the callback function/method from an error object. |
| * |
| * @return mixed callback function or object/method array |
| * @access public |
| */ |
| function getCallback() { |
| return $this->callback; |
| } |
| // }}} |
| // {{{ getMessage() |
| /** |
| * Get the error message from an error object. |
| * |
| * @return string full error message |
| * @access public |
| */ |
| function getMessage() |
| { |
| return ($this->error_message_prefix . $this->message); |
| } |
| // }}} |
| // {{{ getCode() |
| /** |
| * Get error code from an error object |
| * |
| * @return int error code |
| * @access public |
| */ |
| function getCode() |
| { |
| return $this->code; |
| } |
| // }}} |
| // {{{ getType() |
| /** |
| * Get the name of this error/exception. |
| * |
| * @return string error/exception name (type) |
| * @access public |
| */ |
| function getType() |
| { |
| return get_class($this); |
| } |
| // }}} |
| // {{{ getUserInfo() |
| /** |
| * Get additional user-supplied information. |
| * |
| * @return string user-supplied information |
| * @access public |
| */ |
| function getUserInfo() |
| { |
| return $this->userinfo; |
| } |
| // }}} |
| // {{{ getDebugInfo() |
| /** |
| * Get additional debug information supplied by the application. |
| * |
| * @return string debug information |
| * @access public |
| */ |
| function getDebugInfo() |
| { |
| return $this->getUserInfo(); |
| } |
| // }}} |
| // {{{ getBacktrace() |
| /** |
| * Get the call backtrace from where the error was generated. |
| * Supported with PHP 4.3.0 or newer. |
| * |
| * @param int $frame (optional) what frame to fetch |
| * @return array Backtrace, or NULL if not available. |
| * @access public |
| */ |
| function getBacktrace($frame = null) |
| { |
| if ($frame === null) { |
| return $this->backtrace; |
| } |
| return $this->backtrace[$frame]; |
| } |
| // }}} |
| // {{{ addUserInfo() |
| function addUserInfo($info) |
| { |
| if (empty($this->userinfo)) { |
| $this->userinfo = $info; |
| } else { |
| $this->userinfo .= " ** $info"; |
| } |
| } |
| // }}} |
| // {{{ toString() |
| /** |
| * Make a string representation of this object. |
| * |
| * @return string a string with an object summary |
| * @access public |
| */ |
| function toString() { |
| $modes = array(); |
| $levels = array(E_USER_NOTICE => 'notice', |
| E_USER_WARNING => 'warning', |
| E_USER_ERROR => 'error'); |
| if ($this->mode & PEAR_ERROR_CALLBACK) { |
| if (is_array($this->callback)) { |
| $callback = get_class($this->callback[0]) . '::' . |
| $this->callback[1]; |
| } else { |
| $callback = $this->callback; |
| } |
| return sprintf('[%s: message="%s" code=%d mode=callback '. |
| 'callback=%s prefix="%s" info="%s"]', |
| get_class($this), $this->message, $this->code, |
| $callback, $this->error_message_prefix, |
| $this->userinfo); |
| } |
| if ($this->mode & PEAR_ERROR_PRINT) { |
| $modes[] = 'print'; |
| } |
| if ($this->mode & PEAR_ERROR_TRIGGER) { |
| $modes[] = 'trigger'; |
| } |
| if ($this->mode & PEAR_ERROR_DIE) { |
| $modes[] = 'die'; |
| } |
| if ($this->mode & PEAR_ERROR_RETURN) { |
| $modes[] = 'return'; |
| } |
| return sprintf('[%s: message="%s" code=%d mode=%s level=%s '. |
| 'prefix="%s" info="%s"]', |
| get_class($this), $this->message, $this->code, |
| implode("|", $modes), $levels[$this->level], |
| $this->error_message_prefix, |
| $this->userinfo); |
| } |
| // }}} |
| } |
| register_shutdown_function("_PEAR_call_destructors"); |
| /* |
| * Local Variables: |
| * mode: php |
| * tab-width: 4 |
| * c-basic-offset: 4 |
| * End: |
| */ |
| ?> |
| /trunk/applications/jrest/lib/File/PDF/fonts/timesi.php |
|---|
| New file |
| 0,0 → 1,272 |
| <?php |
| /** |
| * @package File_PDF |
| */ |
| $font_widths['timesI'] = array( |
| chr(0) => 250, |
| chr(1) => 250, |
| chr(2) => 250, |
| chr(3) => 250, |
| chr(4) => 250, |
| chr(5) => 250, |
| chr(6) => 250, |
| chr(7) => 250, |
| chr(8) => 250, |
| chr(9) => 250, |
| chr(10) => 250, |
| chr(11) => 250, |
| chr(12) => 250, |
| chr(13) => 250, |
| chr(14) => 250, |
| chr(15) => 250, |
| chr(16) => 250, |
| chr(17) => 250, |
| chr(18) => 250, |
| chr(19) => 250, |
| chr(20) => 250, |
| chr(21) => 250, |
| chr(22) => 250, |
| chr(23) => 250, |
| chr(24) => 250, |
| chr(25) => 250, |
| chr(26) => 250, |
| chr(27) => 250, |
| chr(28) => 250, |
| chr(29) => 250, |
| chr(30) => 250, |
| chr(31) => 250, |
| ' ' => 250, |
| '!' => 333, |
| '"' => 420, |
| '#' => 500, |
| '$' => 500, |
| '%' => 833, |
| '&' => 778, |
| '\'' => 214, |
| '(' => 333, |
| ')' => 333, |
| '*' => 500, |
| '+' => 675, |
| ',' => 250, |
| '-' => 333, |
| '.' => 250, |
| '/' => 278, |
| '0' => 500, |
| '1' => 500, |
| '2' => 500, |
| '3' => 500, |
| '4' => 500, |
| '5' => 500, |
| '6' => 500, |
| '7' => 500, |
| '8' => 500, |
| '9' => 500, |
| ':' => 333, |
| ';' => 333, |
| '<' => 675, |
| '=' => 675, |
| '>' => 675, |
| '?' => 500, |
| '@' => 920, |
| 'A' => 611, |
| 'B' => 611, |
| 'C' => 667, |
| 'D' => 722, |
| 'E' => 611, |
| 'F' => 611, |
| 'G' => 722, |
| 'H' => 722, |
| 'I' => 333, |
| 'J' => 444, |
| 'K' => 667, |
| 'L' => 556, |
| 'M' => 833, |
| 'N' => 667, |
| 'O' => 722, |
| 'P' => 611, |
| 'Q' => 722, |
| 'R' => 611, |
| 'S' => 500, |
| 'T' => 556, |
| 'U' => 722, |
| 'V' => 611, |
| 'W' => 833, |
| 'X' => 611, |
| 'Y' => 556, |
| 'Z' => 556, |
| '[' => 389, |
| '\\' => 278, |
| ']' => 389, |
| '^' => 422, |
| '_' => 500, |
| '`' => 333, |
| 'a' => 500, |
| 'b' => 500, |
| 'c' => 444, |
| 'd' => 500, |
| 'e' => 444, |
| 'f' => 278, |
| 'g' => 500, |
| 'h' => 500, |
| 'i' => 278, |
| 'j' => 278, |
| 'k' => 444, |
| 'l' => 278, |
| 'm' => 722, |
| 'n' => 500, |
| 'o' => 500, |
| 'p' => 500, |
| 'q' => 500, |
| 'r' => 389, |
| 's' => 389, |
| 't' => 278, |
| 'u' => 500, |
| 'v' => 444, |
| 'w' => 667, |
| 'x' => 444, |
| 'y' => 444, |
| 'z' => 389, |
| '{' => 400, |
| '|' => 275, |
| '}' => 400, |
| '~' => 541, |
| chr(127) => 350, |
| chr(128) => 500, |
| chr(129) => 350, |
| chr(130) => 333, |
| chr(131) => 500, |
| chr(132) => 556, |
| chr(133) => 889, |
| chr(134) => 500, |
| chr(135) => 500, |
| chr(136) => 333, |
| chr(137) => 1000, |
| chr(138) => 500, |
| chr(139) => 333, |
| chr(140) => 944, |
| chr(141) => 350, |
| chr(142) => 556, |
| chr(143) => 350, |
| chr(144) => 350, |
| chr(145) => 333, |
| chr(146) => 333, |
| chr(147) => 556, |
| chr(148) => 556, |
| chr(149) => 350, |
| chr(150) => 500, |
| chr(151) => 889, |
| chr(152) => 333, |
| chr(153) => 980, |
| chr(154) => 389, |
| chr(155) => 333, |
| chr(156) => 667, |
| chr(157) => 350, |
| chr(158) => 389, |
| chr(159) => 556, |
| chr(160) => 250, |
| chr(161) => 389, |
| chr(162) => 500, |
| chr(163) => 500, |
| chr(164) => 500, |
| chr(165) => 500, |
| chr(166) => 275, |
| chr(167) => 500, |
| chr(168) => 333, |
| chr(169) => 760, |
| chr(170) => 276, |
| chr(171) => 500, |
| chr(172) => 675, |
| chr(173) => 333, |
| chr(174) => 760, |
| chr(175) => 333, |
| chr(176) => 400, |
| chr(177) => 675, |
| chr(178) => 300, |
| chr(179) => 300, |
| chr(180) => 333, |
| chr(181) => 500, |
| chr(182) => 523, |
| chr(183) => 250, |
| chr(184) => 333, |
| chr(185) => 300, |
| chr(186) => 310, |
| chr(187) => 500, |
| chr(188) => 750, |
| chr(189) => 750, |
| chr(190) => 750, |
| chr(191) => 500, |
| chr(192) => 611, |
| chr(193) => 611, |
| chr(194) => 611, |
| chr(195) => 611, |
| chr(196) => 611, |
| chr(197) => 611, |
| chr(198) => 889, |
| chr(199) => 667, |
| chr(200) => 611, |
| chr(201) => 611, |
| chr(202) => 611, |
| chr(203) => 611, |
| chr(204) => 333, |
| chr(205) => 333, |
| chr(206) => 333, |
| chr(207) => 333, |
| chr(208) => 722, |
| chr(209) => 667, |
| chr(210) => 722, |
| chr(211) => 722, |
| chr(212) => 722, |
| chr(213) => 722, |
| chr(214) => 722, |
| chr(215) => 675, |
| chr(216) => 722, |
| chr(217) => 722, |
| chr(218) => 722, |
| chr(219) => 722, |
| chr(220) => 722, |
| chr(221) => 556, |
| chr(222) => 611, |
| chr(223) => 500, |
| chr(224) => 500, |
| chr(225) => 500, |
| chr(226) => 500, |
| chr(227) => 500, |
| chr(228) => 500, |
| chr(229) => 500, |
| chr(230) => 667, |
| chr(231) => 444, |
| chr(232) => 444, |
| chr(233) => 444, |
| chr(234) => 444, |
| chr(235) => 444, |
| chr(236) => 278, |
| chr(237) => 278, |
| chr(238) => 278, |
| chr(239) => 278, |
| chr(240) => 500, |
| chr(241) => 500, |
| chr(242) => 500, |
| chr(243) => 500, |
| chr(244) => 500, |
| chr(245) => 500, |
| chr(246) => 500, |
| chr(247) => 675, |
| chr(248) => 500, |
| chr(249) => 500, |
| chr(250) => 500, |
| chr(251) => 500, |
| chr(252) => 500, |
| chr(253) => 444, |
| chr(254) => 500, |
| chr(255) => 444); |
| /trunk/applications/jrest/lib/File/PDF/fonts/timesbi.php |
|---|
| New file |
| 0,0 → 1,272 |
| <?php |
| /** |
| * @package File_PDF |
| */ |
| $font_widths['timesBI'] = array( |
| chr(0) => 250, |
| chr(1) => 250, |
| chr(2) => 250, |
| chr(3) => 250, |
| chr(4) => 250, |
| chr(5) => 250, |
| chr(6) => 250, |
| chr(7) => 250, |
| chr(8) => 250, |
| chr(9) => 250, |
| chr(10) => 250, |
| chr(11) => 250, |
| chr(12) => 250, |
| chr(13) => 250, |
| chr(14) => 250, |
| chr(15) => 250, |
| chr(16) => 250, |
| chr(17) => 250, |
| chr(18) => 250, |
| chr(19) => 250, |
| chr(20) => 250, |
| chr(21) => 250, |
| chr(22) => 250, |
| chr(23) => 250, |
| chr(24) => 250, |
| chr(25) => 250, |
| chr(26) => 250, |
| chr(27) => 250, |
| chr(28) => 250, |
| chr(29) => 250, |
| chr(30) => 250, |
| chr(31) => 250, |
| ' ' => 250, |
| '!' => 389, |
| '"' => 555, |
| '#' => 500, |
| '$' => 500, |
| '%' => 833, |
| '&' => 778, |
| '\'' => 278, |
| '(' => 333, |
| ')' => 333, |
| '*' => 500, |
| '+' => 570, |
| ',' => 250, |
| '-' => 333, |
| '.' => 250, |
| '/' => 278, |
| '0' => 500, |
| '1' => 500, |
| '2' => 500, |
| '3' => 500, |
| '4' => 500, |
| '5' => 500, |
| '6' => 500, |
| '7' => 500, |
| '8' => 500, |
| '9' => 500, |
| ':' => 333, |
| ';' => 333, |
| '<' => 570, |
| '=' => 570, |
| '>' => 570, |
| '?' => 500, |
| '@' => 832, |
| 'A' => 667, |
| 'B' => 667, |
| 'C' => 667, |
| 'D' => 722, |
| 'E' => 667, |
| 'F' => 667, |
| 'G' => 722, |
| 'H' => 778, |
| 'I' => 389, |
| 'J' => 500, |
| 'K' => 667, |
| 'L' => 611, |
| 'M' => 889, |
| 'N' => 722, |
| 'O' => 722, |
| 'P' => 611, |
| 'Q' => 722, |
| 'R' => 667, |
| 'S' => 556, |
| 'T' => 611, |
| 'U' => 722, |
| 'V' => 667, |
| 'W' => 889, |
| 'X' => 667, |
| 'Y' => 611, |
| 'Z' => 611, |
| '[' => 333, |
| '\\' => 278, |
| ']' => 333, |
| '^' => 570, |
| '_' => 500, |
| '`' => 333, |
| 'a' => 500, |
| 'b' => 500, |
| 'c' => 444, |
| 'd' => 500, |
| 'e' => 444, |
| 'f' => 333, |
| 'g' => 500, |
| 'h' => 556, |
| 'i' => 278, |
| 'j' => 278, |
| 'k' => 500, |
| 'l' => 278, |
| 'm' => 778, |
| 'n' => 556, |
| 'o' => 500, |
| 'p' => 500, |
| 'q' => 500, |
| 'r' => 389, |
| 's' => 389, |
| 't' => 278, |
| 'u' => 556, |
| 'v' => 444, |
| 'w' => 667, |
| 'x' => 500, |
| 'y' => 444, |
| 'z' => 389, |
| '{' => 348, |
| '|' => 220, |
| '}' => 348, |
| '~' => 570, |
| chr(127) => 350, |
| chr(128) => 500, |
| chr(129) => 350, |
| chr(130) => 333, |
| chr(131) => 500, |
| chr(132) => 500, |
| chr(133) => 1000, |
| chr(134) => 500, |
| chr(135) => 500, |
| chr(136) => 333, |
| chr(137) => 1000, |
| chr(138) => 556, |
| chr(139) => 333, |
| chr(140) => 944, |
| chr(141) => 350, |
| chr(142) => 611, |
| chr(143) => 350, |
| chr(144) => 350, |
| chr(145) => 333, |
| chr(146) => 333, |
| chr(147) => 500, |
| chr(148) => 500, |
| chr(149) => 350, |
| chr(150) => 500, |
| chr(151) => 1000, |
| chr(152) => 333, |
| chr(153) => 1000, |
| chr(154) => 389, |
| chr(155) => 333, |
| chr(156) => 722, |
| chr(157) => 350, |
| chr(158) => 389, |
| chr(159) => 611, |
| chr(160) => 250, |
| chr(161) => 389, |
| chr(162) => 500, |
| chr(163) => 500, |
| chr(164) => 500, |
| chr(165) => 500, |
| chr(166) => 220, |
| chr(167) => 500, |
| chr(168) => 333, |
| chr(169) => 747, |
| chr(170) => 266, |
| chr(171) => 500, |
| chr(172) => 606, |
| chr(173) => 333, |
| chr(174) => 747, |
| chr(175) => 333, |
| chr(176) => 400, |
| chr(177) => 570, |
| chr(178) => 300, |
| chr(179) => 300, |
| chr(180) => 333, |
| chr(181) => 576, |
| chr(182) => 500, |
| chr(183) => 250, |
| chr(184) => 333, |
| chr(185) => 300, |
| chr(186) => 300, |
| chr(187) => 500, |
| chr(188) => 750, |
| chr(189) => 750, |
| chr(190) => 750, |
| chr(191) => 500, |
| chr(192) => 667, |
| chr(193) => 667, |
| chr(194) => 667, |
| chr(195) => 667, |
| chr(196) => 667, |
| chr(197) => 667, |
| chr(198) => 944, |
| chr(199) => 667, |
| chr(200) => 667, |
| chr(201) => 667, |
| chr(202) => 667, |
| chr(203) => 667, |
| chr(204) => 389, |
| chr(205) => 389, |
| chr(206) => 389, |
| chr(207) => 389, |
| chr(208) => 722, |
| chr(209) => 722, |
| chr(210) => 722, |
| chr(211) => 722, |
| chr(212) => 722, |
| chr(213) => 722, |
| chr(214) => 722, |
| chr(215) => 570, |
| chr(216) => 722, |
| chr(217) => 722, |
| chr(218) => 722, |
| chr(219) => 722, |
| chr(220) => 722, |
| chr(221) => 611, |
| chr(222) => 611, |
| chr(223) => 500, |
| chr(224) => 500, |
| chr(225) => 500, |
| chr(226) => 500, |
| chr(227) => 500, |
| chr(228) => 500, |
| chr(229) => 500, |
| chr(230) => 722, |
| chr(231) => 444, |
| chr(232) => 444, |
| chr(233) => 444, |
| chr(234) => 444, |
| chr(235) => 444, |
| chr(236) => 278, |
| chr(237) => 278, |
| chr(238) => 278, |
| chr(239) => 278, |
| chr(240) => 500, |
| chr(241) => 556, |
| chr(242) => 500, |
| chr(243) => 500, |
| chr(244) => 500, |
| chr(245) => 500, |
| chr(246) => 500, |
| chr(247) => 570, |
| chr(248) => 500, |
| chr(249) => 556, |
| chr(250) => 556, |
| chr(251) => 556, |
| chr(252) => 556, |
| chr(253) => 444, |
| chr(254) => 500, |
| chr(255) => 444); |
| /trunk/applications/jrest/lib/File/PDF/fonts/zapfdingbats.php |
|---|
| New file |
| 0,0 → 1,272 |
| <?php |
| /** |
| * @package File_PDF |
| */ |
| $font_widths['zapfdingbats'] = array( |
| chr(0) => 0, |
| chr(1) => 0, |
| chr(2) => 0, |
| chr(3) => 0, |
| chr(4) => 0, |
| chr(5) => 0, |
| chr(6) => 0, |
| chr(7) => 0, |
| chr(8) => 0, |
| chr(9) => 0, |
| chr(10) => 0, |
| chr(11) => 0, |
| chr(12) => 0, |
| chr(13) => 0, |
| chr(14) => 0, |
| chr(15) => 0, |
| chr(16) => 0, |
| chr(17) => 0, |
| chr(18) => 0, |
| chr(19) => 0, |
| chr(20) => 0, |
| chr(21) => 0, |
| chr(22) => 0, |
| chr(23) => 0, |
| chr(24) => 0, |
| chr(25) => 0, |
| chr(26) => 0, |
| chr(27) => 0, |
| chr(28) => 0, |
| chr(29) => 0, |
| chr(30) => 0, |
| chr(31) => 0, |
| ' ' => 278, |
| '!' => 974, |
| '"' => 961, |
| '#' => 974, |
| '$' => 980, |
| '%' => 719, |
| '&' => 789, |
| '\'' => 790, |
| '(' => 791, |
| ')' => 690, |
| '*' => 960, |
| '+' => 939, |
| ',' => 549, |
| '-' => 855, |
| '.' => 911, |
| '/' => 933, |
| '0' => 911, |
| '1' => 945, |
| '2' => 974, |
| '3' => 755, |
| '4' => 846, |
| '5' => 762, |
| '6' => 761, |
| '7' => 571, |
| '8' => 677, |
| '9' => 763, |
| ':' => 760, |
| ';' => 759, |
| '<' => 754, |
| '=' => 494, |
| '>' => 552, |
| '?' => 537, |
| '@' => 577, |
| 'A' => 692, |
| 'B' => 786, |
| 'C' => 788, |
| 'D' => 788, |
| 'E' => 790, |
| 'F' => 793, |
| 'G' => 794, |
| 'H' => 816, |
| 'I' => 823, |
| 'J' => 789, |
| 'K' => 841, |
| 'L' => 823, |
| 'M' => 833, |
| 'N' => 816, |
| 'O' => 831, |
| 'P' => 923, |
| 'Q' => 744, |
| 'R' => 723, |
| 'S' => 749, |
| 'T' => 790, |
| 'U' => 792, |
| 'V' => 695, |
| 'W' => 776, |
| 'X' => 768, |
| 'Y' => 792, |
| 'Z' => 759, |
| '[' => 707, |
| '\\' => 708, |
| ']' => 682, |
| '^' => 701, |
| '_' => 826, |
| '`' => 815, |
| 'a' => 789, |
| 'b' => 789, |
| 'c' => 707, |
| 'd' => 687, |
| 'e' => 696, |
| 'f' => 689, |
| 'g' => 786, |
| 'h' => 787, |
| 'i' => 713, |
| 'j' => 791, |
| 'k' => 785, |
| 'l' => 791, |
| 'm' => 873, |
| 'n' => 761, |
| 'o' => 762, |
| 'p' => 762, |
| 'q' => 759, |
| 'r' => 759, |
| 's' => 892, |
| 't' => 892, |
| 'u' => 788, |
| 'v' => 784, |
| 'w' => 438, |
| 'x' => 138, |
| 'y' => 277, |
| 'z' => 415, |
| '{' => 392, |
| '|' => 392, |
| '}' => 668, |
| '~' => 668, |
| chr(127) => 0, |
| chr(128) => 390, |
| chr(129) => 390, |
| chr(130) => 317, |
| chr(131) => 317, |
| chr(132) => 276, |
| chr(133) => 276, |
| chr(134) => 509, |
| chr(135) => 509, |
| chr(136) => 410, |
| chr(137) => 410, |
| chr(138) => 234, |
| chr(139) => 234, |
| chr(140) => 334, |
| chr(141) => 334, |
| chr(142) => 0, |
| chr(143) => 0, |
| chr(144) => 0, |
| chr(145) => 0, |
| chr(146) => 0, |
| chr(147) => 0, |
| chr(148) => 0, |
| chr(149) => 0, |
| chr(150) => 0, |
| chr(151) => 0, |
| chr(152) => 0, |
| chr(153) => 0, |
| chr(154) => 0, |
| chr(155) => 0, |
| chr(156) => 0, |
| chr(157) => 0, |
| chr(158) => 0, |
| chr(159) => 0, |
| chr(160) => 0, |
| chr(161) => 732, |
| chr(162) => 544, |
| chr(163) => 544, |
| chr(164) => 910, |
| chr(165) => 667, |
| chr(166) => 760, |
| chr(167) => 760, |
| chr(168) => 776, |
| chr(169) => 595, |
| chr(170) => 694, |
| chr(171) => 626, |
| chr(172) => 788, |
| chr(173) => 788, |
| chr(174) => 788, |
| chr(175) => 788, |
| chr(176) => 788, |
| chr(177) => 788, |
| chr(178) => 788, |
| chr(179) => 788, |
| chr(180) => 788, |
| chr(181) => 788, |
| chr(182) => 788, |
| chr(183) => 788, |
| chr(184) => 788, |
| chr(185) => 788, |
| chr(186) => 788, |
| chr(187) => 788, |
| chr(188) => 788, |
| chr(189) => 788, |
| chr(190) => 788, |
| chr(191) => 788, |
| chr(192) => 788, |
| chr(193) => 788, |
| chr(194) => 788, |
| chr(195) => 788, |
| chr(196) => 788, |
| chr(197) => 788, |
| chr(198) => 788, |
| chr(199) => 788, |
| chr(200) => 788, |
| chr(201) => 788, |
| chr(202) => 788, |
| chr(203) => 788, |
| chr(204) => 788, |
| chr(205) => 788, |
| chr(206) => 788, |
| chr(207) => 788, |
| chr(208) => 788, |
| chr(209) => 788, |
| chr(210) => 788, |
| chr(211) => 788, |
| chr(212) => 894, |
| chr(213) => 838, |
| chr(214) => 1016, |
| chr(215) => 458, |
| chr(216) => 748, |
| chr(217) => 924, |
| chr(218) => 748, |
| chr(219) => 918, |
| chr(220) => 927, |
| chr(221) => 928, |
| chr(222) => 928, |
| chr(223) => 834, |
| chr(224) => 873, |
| chr(225) => 828, |
| chr(226) => 924, |
| chr(227) => 924, |
| chr(228) => 917, |
| chr(229) => 930, |
| chr(230) => 931, |
| chr(231) => 463, |
| chr(232) => 883, |
| chr(233) => 836, |
| chr(234) => 836, |
| chr(235) => 867, |
| chr(236) => 867, |
| chr(237) => 696, |
| chr(238) => 696, |
| chr(239) => 874, |
| chr(240) => 0, |
| chr(241) => 874, |
| chr(242) => 760, |
| chr(243) => 946, |
| chr(244) => 771, |
| chr(245) => 865, |
| chr(246) => 771, |
| chr(247) => 888, |
| chr(248) => 967, |
| chr(249) => 888, |
| chr(250) => 831, |
| chr(251) => 873, |
| chr(252) => 927, |
| chr(253) => 970, |
| chr(254) => 918, |
| chr(255) => 0); |
| /trunk/applications/jrest/lib/File/PDF/fonts/helveticai.php |
|---|
| New file |
| 0,0 → 1,272 |
| <?php |
| /** |
| * @package File_PDF |
| */ |
| $font_widths['helveticaI'] = array( |
| chr(0) => 278, |
| chr(1) => 278, |
| chr(2) => 278, |
| chr(3) => 278, |
| chr(4) => 278, |
| chr(5) => 278, |
| chr(6) => 278, |
| chr(7) => 278, |
| chr(8) => 278, |
| chr(9) => 278, |
| chr(10) => 278, |
| chr(11) => 278, |
| chr(12) => 278, |
| chr(13) => 278, |
| chr(14) => 278, |
| chr(15) => 278, |
| chr(16) => 278, |
| chr(17) => 278, |
| chr(18) => 278, |
| chr(19) => 278, |
| chr(20) => 278, |
| chr(21) => 278, |
| chr(22) => 278, |
| chr(23) => 278, |
| chr(24) => 278, |
| chr(25) => 278, |
| chr(26) => 278, |
| chr(27) => 278, |
| chr(28) => 278, |
| chr(29) => 278, |
| chr(30) => 278, |
| chr(31) => 278, |
| ' ' => 278, |
| '!' => 278, |
| '"' => 355, |
| '#' => 556, |
| '$' => 556, |
| '%' => 889, |
| '&' => 667, |
| '\'' => 191, |
| '(' => 333, |
| ')' => 333, |
| '*' => 389, |
| '+' => 584, |
| ',' => 278, |
| '-' => 333, |
| '.' => 278, |
| '/' => 278, |
| '0' => 556, |
| '1' => 556, |
| '2' => 556, |
| '3' => 556, |
| '4' => 556, |
| '5' => 556, |
| '6' => 556, |
| '7' => 556, |
| '8' => 556, |
| '9' => 556, |
| ':' => 278, |
| ';' => 278, |
| '<' => 584, |
| '=' => 584, |
| '>' => 584, |
| '?' => 556, |
| '@' => 1015, |
| 'A' => 667, |
| 'B' => 667, |
| 'C' => 722, |
| 'D' => 722, |
| 'E' => 667, |
| 'F' => 611, |
| 'G' => 778, |
| 'H' => 722, |
| 'I' => 278, |
| 'J' => 500, |
| 'K' => 667, |
| 'L' => 556, |
| 'M' => 833, |
| 'N' => 722, |
| 'O' => 778, |
| 'P' => 667, |
| 'Q' => 778, |
| 'R' => 722, |
| 'S' => 667, |
| 'T' => 611, |
| 'U' => 722, |
| 'V' => 667, |
| 'W' => 944, |
| 'X' => 667, |
| 'Y' => 667, |
| 'Z' => 611, |
| '[' => 278, |
| '\\' => 278, |
| ']' => 278, |
| '^' => 469, |
| '_' => 556, |
| '`' => 333, |
| 'a' => 556, |
| 'b' => 556, |
| 'c' => 500, |
| 'd' => 556, |
| 'e' => 556, |
| 'f' => 278, |
| 'g' => 556, |
| 'h' => 556, |
| 'i' => 222, |
| 'j' => 222, |
| 'k' => 500, |
| 'l' => 222, |
| 'm' => 833, |
| 'n' => 556, |
| 'o' => 556, |
| 'p' => 556, |
| 'q' => 556, |
| 'r' => 333, |
| 's' => 500, |
| 't' => 278, |
| 'u' => 556, |
| 'v' => 500, |
| 'w' => 722, |
| 'x' => 500, |
| 'y' => 500, |
| 'z' => 500, |
| '{' => 334, |
| '|' => 260, |
| '}' => 334, |
| '~' => 584, |
| chr(127) => 350, |
| chr(128) => 556, |
| chr(129) => 350, |
| chr(130) => 222, |
| chr(131) => 556, |
| chr(132) => 333, |
| chr(133) => 1000, |
| chr(134) => 556, |
| chr(135) => 556, |
| chr(136) => 333, |
| chr(137) => 1000, |
| chr(138) => 667, |
| chr(139) => 333, |
| chr(140) => 1000, |
| chr(141) => 350, |
| chr(142) => 611, |
| chr(143) => 350, |
| chr(144) => 350, |
| chr(145) => 222, |
| chr(146) => 222, |
| chr(147) => 333, |
| chr(148) => 333, |
| chr(149) => 350, |
| chr(150) => 556, |
| chr(151) => 1000, |
| chr(152) => 333, |
| chr(153) => 1000, |
| chr(154) => 500, |
| chr(155) => 333, |
| chr(156) => 944, |
| chr(157) => 350, |
| chr(158) => 500, |
| chr(159) => 667, |
| chr(160) => 278, |
| chr(161) => 333, |
| chr(162) => 556, |
| chr(163) => 556, |
| chr(164) => 556, |
| chr(165) => 556, |
| chr(166) => 260, |
| chr(167) => 556, |
| chr(168) => 333, |
| chr(169) => 737, |
| chr(170) => 370, |
| chr(171) => 556, |
| chr(172) => 584, |
| chr(173) => 333, |
| chr(174) => 737, |
| chr(175) => 333, |
| chr(176) => 400, |
| chr(177) => 584, |
| chr(178) => 333, |
| chr(179) => 333, |
| chr(180) => 333, |
| chr(181) => 556, |
| chr(182) => 537, |
| chr(183) => 278, |
| chr(184) => 333, |
| chr(185) => 333, |
| chr(186) => 365, |
| chr(187) => 556, |
| chr(188) => 834, |
| chr(189) => 834, |
| chr(190) => 834, |
| chr(191) => 611, |
| chr(192) => 667, |
| chr(193) => 667, |
| chr(194) => 667, |
| chr(195) => 667, |
| chr(196) => 667, |
| chr(197) => 667, |
| chr(198) => 1000, |
| chr(199) => 722, |
| chr(200) => 667, |
| chr(201) => 667, |
| chr(202) => 667, |
| chr(203) => 667, |
| chr(204) => 278, |
| chr(205) => 278, |
| chr(206) => 278, |
| chr(207) => 278, |
| chr(208) => 722, |
| chr(209) => 722, |
| chr(210) => 778, |
| chr(211) => 778, |
| chr(212) => 778, |
| chr(213) => 778, |
| chr(214) => 778, |
| chr(215) => 584, |
| chr(216) => 778, |
| chr(217) => 722, |
| chr(218) => 722, |
| chr(219) => 722, |
| chr(220) => 722, |
| chr(221) => 667, |
| chr(222) => 667, |
| chr(223) => 611, |
| chr(224) => 556, |
| chr(225) => 556, |
| chr(226) => 556, |
| chr(227) => 556, |
| chr(228) => 556, |
| chr(229) => 556, |
| chr(230) => 889, |
| chr(231) => 500, |
| chr(232) => 556, |
| chr(233) => 556, |
| chr(234) => 556, |
| chr(235) => 556, |
| chr(236) => 278, |
| chr(237) => 278, |
| chr(238) => 278, |
| chr(239) => 278, |
| chr(240) => 556, |
| chr(241) => 556, |
| chr(242) => 556, |
| chr(243) => 556, |
| chr(244) => 556, |
| chr(245) => 556, |
| chr(246) => 556, |
| chr(247) => 584, |
| chr(248) => 611, |
| chr(249) => 556, |
| chr(250) => 556, |
| chr(251) => 556, |
| chr(252) => 556, |
| chr(253) => 500, |
| chr(254) => 556, |
| chr(255) => 500); |
| /trunk/applications/jrest/lib/File/PDF/fonts/helveticabi.php |
|---|
| New file |
| 0,0 → 1,272 |
| <?php |
| /** |
| * @package File_PDF |
| */ |
| $font_widths['helveticaBI'] = array( |
| chr(0) => 278, |
| chr(1) => 278, |
| chr(2) => 278, |
| chr(3) => 278, |
| chr(4) => 278, |
| chr(5) => 278, |
| chr(6) => 278, |
| chr(7) => 278, |
| chr(8) => 278, |
| chr(9) => 278, |
| chr(10) => 278, |
| chr(11) => 278, |
| chr(12) => 278, |
| chr(13) => 278, |
| chr(14) => 278, |
| chr(15) => 278, |
| chr(16) => 278, |
| chr(17) => 278, |
| chr(18) => 278, |
| chr(19) => 278, |
| chr(20) => 278, |
| chr(21) => 278, |
| chr(22) => 278, |
| chr(23) => 278, |
| chr(24) => 278, |
| chr(25) => 278, |
| chr(26) => 278, |
| chr(27) => 278, |
| chr(28) => 278, |
| chr(29) => 278, |
| chr(30) => 278, |
| chr(31) => 278, |
| ' ' => 278, |
| '!' => 333, |
| '"' => 474, |
| '#' => 556, |
| '$' => 556, |
| '%' => 889, |
| '&' => 722, |
| '\'' => 238, |
| '(' => 333, |
| ')' => 333, |
| '*' => 389, |
| '+' => 584, |
| ',' => 278, |
| '-' => 333, |
| '.' => 278, |
| '/' => 278, |
| '0' => 556, |
| '1' => 556, |
| '2' => 556, |
| '3' => 556, |
| '4' => 556, |
| '5' => 556, |
| '6' => 556, |
| '7' => 556, |
| '8' => 556, |
| '9' => 556, |
| ':' => 333, |
| ';' => 333, |
| '<' => 584, |
| '=' => 584, |
| '>' => 584, |
| '?' => 611, |
| '@' => 975, |
| 'A' => 722, |
| 'B' => 722, |
| 'C' => 722, |
| 'D' => 722, |
| 'E' => 667, |
| 'F' => 611, |
| 'G' => 778, |
| 'H' => 722, |
| 'I' => 278, |
| 'J' => 556, |
| 'K' => 722, |
| 'L' => 611, |
| 'M' => 833, |
| 'N' => 722, |
| 'O' => 778, |
| 'P' => 667, |
| 'Q' => 778, |
| 'R' => 722, |
| 'S' => 667, |
| 'T' => 611, |
| 'U' => 722, |
| 'V' => 667, |
| 'W' => 944, |
| 'X' => 667, |
| 'Y' => 667, |
| 'Z' => 611, |
| '[' => 333, |
| '\\' => 278, |
| ']' => 333, |
| '^' => 584, |
| '_' => 556, |
| '`' => 333, |
| 'a' => 556, |
| 'b' => 611, |
| 'c' => 556, |
| 'd' => 611, |
| 'e' => 556, |
| 'f' => 333, |
| 'g' => 611, |
| 'h' => 611, |
| 'i' => 278, |
| 'j' => 278, |
| 'k' => 556, |
| 'l' => 278, |
| 'm' => 889, |
| 'n' => 611, |
| 'o' => 611, |
| 'p' => 611, |
| 'q' => 611, |
| 'r' => 389, |
| 's' => 556, |
| 't' => 333, |
| 'u' => 611, |
| 'v' => 556, |
| 'w' => 778, |
| 'x' => 556, |
| 'y' => 556, |
| 'z' => 500, |
| '{' => 389, |
| '|' => 280, |
| '}' => 389, |
| '~' => 584, |
| chr(127) => 350, |
| chr(128) => 556, |
| chr(129) => 350, |
| chr(130) => 278, |
| chr(131) => 556, |
| chr(132) => 500, |
| chr(133) => 1000, |
| chr(134) => 556, |
| chr(135) => 556, |
| chr(136) => 333, |
| chr(137) => 1000, |
| chr(138) => 667, |
| chr(139) => 333, |
| chr(140) => 1000, |
| chr(141) => 350, |
| chr(142) => 611, |
| chr(143) => 350, |
| chr(144) => 350, |
| chr(145) => 278, |
| chr(146) => 278, |
| chr(147) => 500, |
| chr(148) => 500, |
| chr(149) => 350, |
| chr(150) => 556, |
| chr(151) => 1000, |
| chr(152) => 333, |
| chr(153) => 1000, |
| chr(154) => 556, |
| chr(155) => 333, |
| chr(156) => 944, |
| chr(157) => 350, |
| chr(158) => 500, |
| chr(159) => 667, |
| chr(160) => 278, |
| chr(161) => 333, |
| chr(162) => 556, |
| chr(163) => 556, |
| chr(164) => 556, |
| chr(165) => 556, |
| chr(166) => 280, |
| chr(167) => 556, |
| chr(168) => 333, |
| chr(169) => 737, |
| chr(170) => 370, |
| chr(171) => 556, |
| chr(172) => 584, |
| chr(173) => 333, |
| chr(174) => 737, |
| chr(175) => 333, |
| chr(176) => 400, |
| chr(177) => 584, |
| chr(178) => 333, |
| chr(179) => 333, |
| chr(180) => 333, |
| chr(181) => 611, |
| chr(182) => 556, |
| chr(183) => 278, |
| chr(184) => 333, |
| chr(185) => 333, |
| chr(186) => 365, |
| chr(187) => 556, |
| chr(188) => 834, |
| chr(189) => 834, |
| chr(190) => 834, |
| chr(191) => 611, |
| chr(192) => 722, |
| chr(193) => 722, |
| chr(194) => 722, |
| chr(195) => 722, |
| chr(196) => 722, |
| chr(197) => 722, |
| chr(198) => 1000, |
| chr(199) => 722, |
| chr(200) => 667, |
| chr(201) => 667, |
| chr(202) => 667, |
| chr(203) => 667, |
| chr(204) => 278, |
| chr(205) => 278, |
| chr(206) => 278, |
| chr(207) => 278, |
| chr(208) => 722, |
| chr(209) => 722, |
| chr(210) => 778, |
| chr(211) => 778, |
| chr(212) => 778, |
| chr(213) => 778, |
| chr(214) => 778, |
| chr(215) => 584, |
| chr(216) => 778, |
| chr(217) => 722, |
| chr(218) => 722, |
| chr(219) => 722, |
| chr(220) => 722, |
| chr(221) => 667, |
| chr(222) => 667, |
| chr(223) => 611, |
| chr(224) => 556, |
| chr(225) => 556, |
| chr(226) => 556, |
| chr(227) => 556, |
| chr(228) => 556, |
| chr(229) => 556, |
| chr(230) => 889, |
| chr(231) => 556, |
| chr(232) => 556, |
| chr(233) => 556, |
| chr(234) => 556, |
| chr(235) => 556, |
| chr(236) => 278, |
| chr(237) => 278, |
| chr(238) => 278, |
| chr(239) => 278, |
| chr(240) => 611, |
| chr(241) => 611, |
| chr(242) => 611, |
| chr(243) => 611, |
| chr(244) => 611, |
| chr(245) => 611, |
| chr(246) => 611, |
| chr(247) => 584, |
| chr(248) => 611, |
| chr(249) => 611, |
| chr(250) => 611, |
| chr(251) => 611, |
| chr(252) => 611, |
| chr(253) => 556, |
| chr(254) => 611, |
| chr(255) => 556); |
| /trunk/applications/jrest/lib/File/PDF/fonts/times.php |
|---|
| New file |
| 0,0 → 1,272 |
| <?php |
| /** |
| * @package File_PDF |
| */ |
| $font_widths['times'] = array( |
| chr(0) => 250, |
| chr(1) => 250, |
| chr(2) => 250, |
| chr(3) => 250, |
| chr(4) => 250, |
| chr(5) => 250, |
| chr(6) => 250, |
| chr(7) => 250, |
| chr(8) => 250, |
| chr(9) => 250, |
| chr(10) => 250, |
| chr(11) => 250, |
| chr(12) => 250, |
| chr(13) => 250, |
| chr(14) => 250, |
| chr(15) => 250, |
| chr(16) => 250, |
| chr(17) => 250, |
| chr(18) => 250, |
| chr(19) => 250, |
| chr(20) => 250, |
| chr(21) => 250, |
| chr(22) => 250, |
| chr(23) => 250, |
| chr(24) => 250, |
| chr(25) => 250, |
| chr(26) => 250, |
| chr(27) => 250, |
| chr(28) => 250, |
| chr(29) => 250, |
| chr(30) => 250, |
| chr(31) => 250, |
| ' ' => 250, |
| '!' => 333, |
| '"' => 408, |
| '#' => 500, |
| '$' => 500, |
| '%' => 833, |
| '&' => 778, |
| '\'' => 180, |
| '(' => 333, |
| ')' => 333, |
| '*' => 500, |
| '+' => 564, |
| ',' => 250, |
| '-' => 333, |
| '.' => 250, |
| '/' => 278, |
| '0' => 500, |
| '1' => 500, |
| '2' => 500, |
| '3' => 500, |
| '4' => 500, |
| '5' => 500, |
| '6' => 500, |
| '7' => 500, |
| '8' => 500, |
| '9' => 500, |
| ':' => 278, |
| ';' => 278, |
| '<' => 564, |
| '=' => 564, |
| '>' => 564, |
| '?' => 444, |
| '@' => 921, |
| 'A' => 722, |
| 'B' => 667, |
| 'C' => 667, |
| 'D' => 722, |
| 'E' => 611, |
| 'F' => 556, |
| 'G' => 722, |
| 'H' => 722, |
| 'I' => 333, |
| 'J' => 389, |
| 'K' => 722, |
| 'L' => 611, |
| 'M' => 889, |
| 'N' => 722, |
| 'O' => 722, |
| 'P' => 556, |
| 'Q' => 722, |
| 'R' => 667, |
| 'S' => 556, |
| 'T' => 611, |
| 'U' => 722, |
| 'V' => 722, |
| 'W' => 944, |
| 'X' => 722, |
| 'Y' => 722, |
| 'Z' => 611, |
| '[' => 333, |
| '\\' => 278, |
| ']' => 333, |
| '^' => 469, |
| '_' => 500, |
| '`' => 333, |
| 'a' => 444, |
| 'b' => 500, |
| 'c' => 444, |
| 'd' => 500, |
| 'e' => 444, |
| 'f' => 333, |
| 'g' => 500, |
| 'h' => 500, |
| 'i' => 278, |
| 'j' => 278, |
| 'k' => 500, |
| 'l' => 278, |
| 'm' => 778, |
| 'n' => 500, |
| 'o' => 500, |
| 'p' => 500, |
| 'q' => 500, |
| 'r' => 333, |
| 's' => 389, |
| 't' => 278, |
| 'u' => 500, |
| 'v' => 500, |
| 'w' => 722, |
| 'x' => 500, |
| 'y' => 500, |
| 'z' => 444, |
| '{' => 480, |
| '|' => 200, |
| '}' => 480, |
| '~' => 541, |
| chr(127) => 350, |
| chr(128) => 500, |
| chr(129) => 350, |
| chr(130) => 333, |
| chr(131) => 500, |
| chr(132) => 444, |
| chr(133) => 1000, |
| chr(134) => 500, |
| chr(135) => 500, |
| chr(136) => 333, |
| chr(137) => 1000, |
| chr(138) => 556, |
| chr(139) => 333, |
| chr(140) => 889, |
| chr(141) => 350, |
| chr(142) => 611, |
| chr(143) => 350, |
| chr(144) => 350, |
| chr(145) => 333, |
| chr(146) => 333, |
| chr(147) => 444, |
| chr(148) => 444, |
| chr(149) => 350, |
| chr(150) => 500, |
| chr(151) => 1000, |
| chr(152) => 333, |
| chr(153) => 980, |
| chr(154) => 389, |
| chr(155) => 333, |
| chr(156) => 722, |
| chr(157) => 350, |
| chr(158) => 444, |
| chr(159) => 722, |
| chr(160) => 250, |
| chr(161) => 333, |
| chr(162) => 500, |
| chr(163) => 500, |
| chr(164) => 500, |
| chr(165) => 500, |
| chr(166) => 200, |
| chr(167) => 500, |
| chr(168) => 333, |
| chr(169) => 760, |
| chr(170) => 276, |
| chr(171) => 500, |
| chr(172) => 564, |
| chr(173) => 333, |
| chr(174) => 760, |
| chr(175) => 333, |
| chr(176) => 400, |
| chr(177) => 564, |
| chr(178) => 300, |
| chr(179) => 300, |
| chr(180) => 333, |
| chr(181) => 500, |
| chr(182) => 453, |
| chr(183) => 250, |
| chr(184) => 333, |
| chr(185) => 300, |
| chr(186) => 310, |
| chr(187) => 500, |
| chr(188) => 750, |
| chr(189) => 750, |
| chr(190) => 750, |
| chr(191) => 444, |
| chr(192) => 722, |
| chr(193) => 722, |
| chr(194) => 722, |
| chr(195) => 722, |
| chr(196) => 722, |
| chr(197) => 722, |
| chr(198) => 889, |
| chr(199) => 667, |
| chr(200) => 611, |
| chr(201) => 611, |
| chr(202) => 611, |
| chr(203) => 611, |
| chr(204) => 333, |
| chr(205) => 333, |
| chr(206) => 333, |
| chr(207) => 333, |
| chr(208) => 722, |
| chr(209) => 722, |
| chr(210) => 722, |
| chr(211) => 722, |
| chr(212) => 722, |
| chr(213) => 722, |
| chr(214) => 722, |
| chr(215) => 564, |
| chr(216) => 722, |
| chr(217) => 722, |
| chr(218) => 722, |
| chr(219) => 722, |
| chr(220) => 722, |
| chr(221) => 722, |
| chr(222) => 556, |
| chr(223) => 500, |
| chr(224) => 444, |
| chr(225) => 444, |
| chr(226) => 444, |
| chr(227) => 444, |
| chr(228) => 444, |
| chr(229) => 444, |
| chr(230) => 667, |
| chr(231) => 444, |
| chr(232) => 444, |
| chr(233) => 444, |
| chr(234) => 444, |
| chr(235) => 444, |
| chr(236) => 278, |
| chr(237) => 278, |
| chr(238) => 278, |
| chr(239) => 278, |
| chr(240) => 500, |
| chr(241) => 500, |
| chr(242) => 500, |
| chr(243) => 500, |
| chr(244) => 500, |
| chr(245) => 500, |
| chr(246) => 500, |
| chr(247) => 564, |
| chr(248) => 500, |
| chr(249) => 500, |
| chr(250) => 500, |
| chr(251) => 500, |
| chr(252) => 500, |
| chr(253) => 500, |
| chr(254) => 500, |
| chr(255) => 500); |
| /trunk/applications/jrest/lib/File/PDF/fonts/timesb.php |
|---|
| New file |
| 0,0 → 1,272 |
| <?php |
| /** |
| * @package File_PDF |
| */ |
| $font_widths['timesB'] = array( |
| chr(0) => 250, |
| chr(1) => 250, |
| chr(2) => 250, |
| chr(3) => 250, |
| chr(4) => 250, |
| chr(5) => 250, |
| chr(6) => 250, |
| chr(7) => 250, |
| chr(8) => 250, |
| chr(9) => 250, |
| chr(10) => 250, |
| chr(11) => 250, |
| chr(12) => 250, |
| chr(13) => 250, |
| chr(14) => 250, |
| chr(15) => 250, |
| chr(16) => 250, |
| chr(17) => 250, |
| chr(18) => 250, |
| chr(19) => 250, |
| chr(20) => 250, |
| chr(21) => 250, |
| chr(22) => 250, |
| chr(23) => 250, |
| chr(24) => 250, |
| chr(25) => 250, |
| chr(26) => 250, |
| chr(27) => 250, |
| chr(28) => 250, |
| chr(29) => 250, |
| chr(30) => 250, |
| chr(31) => 250, |
| ' ' => 250, |
| '!' => 333, |
| '"' => 555, |
| '#' => 500, |
| '$' => 500, |
| '%' => 1000, |
| '&' => 833, |
| '\'' => 278, |
| '(' => 333, |
| ')' => 333, |
| '*' => 500, |
| '+' => 570, |
| ',' => 250, |
| '-' => 333, |
| '.' => 250, |
| '/' => 278, |
| '0' => 500, |
| '1' => 500, |
| '2' => 500, |
| '3' => 500, |
| '4' => 500, |
| '5' => 500, |
| '6' => 500, |
| '7' => 500, |
| '8' => 500, |
| '9' => 500, |
| ':' => 333, |
| ';' => 333, |
| '<' => 570, |
| '=' => 570, |
| '>' => 570, |
| '?' => 500, |
| '@' => 930, |
| 'A' => 722, |
| 'B' => 667, |
| 'C' => 722, |
| 'D' => 722, |
| 'E' => 667, |
| 'F' => 611, |
| 'G' => 778, |
| 'H' => 778, |
| 'I' => 389, |
| 'J' => 500, |
| 'K' => 778, |
| 'L' => 667, |
| 'M' => 944, |
| 'N' => 722, |
| 'O' => 778, |
| 'P' => 611, |
| 'Q' => 778, |
| 'R' => 722, |
| 'S' => 556, |
| 'T' => 667, |
| 'U' => 722, |
| 'V' => 722, |
| 'W' => 1000, |
| 'X' => 722, |
| 'Y' => 722, |
| 'Z' => 667, |
| '[' => 333, |
| '\\' => 278, |
| ']' => 333, |
| '^' => 581, |
| '_' => 500, |
| '`' => 333, |
| 'a' => 500, |
| 'b' => 556, |
| 'c' => 444, |
| 'd' => 556, |
| 'e' => 444, |
| 'f' => 333, |
| 'g' => 500, |
| 'h' => 556, |
| 'i' => 278, |
| 'j' => 333, |
| 'k' => 556, |
| 'l' => 278, |
| 'm' => 833, |
| 'n' => 556, |
| 'o' => 500, |
| 'p' => 556, |
| 'q' => 556, |
| 'r' => 444, |
| 's' => 389, |
| 't' => 333, |
| 'u' => 556, |
| 'v' => 500, |
| 'w' => 722, |
| 'x' => 500, |
| 'y' => 500, |
| 'z' => 444, |
| '{' => 394, |
| '|' => 220, |
| '}' => 394, |
| '~' => 520, |
| chr(127) => 350, |
| chr(128) => 500, |
| chr(129) => 350, |
| chr(130) => 333, |
| chr(131) => 500, |
| chr(132) => 500, |
| chr(133) => 1000, |
| chr(134) => 500, |
| chr(135) => 500, |
| chr(136) => 333, |
| chr(137) => 1000, |
| chr(138) => 556, |
| chr(139) => 333, |
| chr(140) => 1000, |
| chr(141) => 350, |
| chr(142) => 667, |
| chr(143) => 350, |
| chr(144) => 350, |
| chr(145) => 333, |
| chr(146) => 333, |
| chr(147) => 500, |
| chr(148) => 500, |
| chr(149) => 350, |
| chr(150) => 500, |
| chr(151) => 1000, |
| chr(152) => 333, |
| chr(153) => 1000, |
| chr(154) => 389, |
| chr(155) => 333, |
| chr(156) => 722, |
| chr(157) => 350, |
| chr(158) => 444, |
| chr(159) => 722, |
| chr(160) => 250, |
| chr(161) => 333, |
| chr(162) => 500, |
| chr(163) => 500, |
| chr(164) => 500, |
| chr(165) => 500, |
| chr(166) => 220, |
| chr(167) => 500, |
| chr(168) => 333, |
| chr(169) => 747, |
| chr(170) => 300, |
| chr(171) => 500, |
| chr(172) => 570, |
| chr(173) => 333, |
| chr(174) => 747, |
| chr(175) => 333, |
| chr(176) => 400, |
| chr(177) => 570, |
| chr(178) => 300, |
| chr(179) => 300, |
| chr(180) => 333, |
| chr(181) => 556, |
| chr(182) => 540, |
| chr(183) => 250, |
| chr(184) => 333, |
| chr(185) => 300, |
| chr(186) => 330, |
| chr(187) => 500, |
| chr(188) => 750, |
| chr(189) => 750, |
| chr(190) => 750, |
| chr(191) => 500, |
| chr(192) => 722, |
| chr(193) => 722, |
| chr(194) => 722, |
| chr(195) => 722, |
| chr(196) => 722, |
| chr(197) => 722, |
| chr(198) => 1000, |
| chr(199) => 722, |
| chr(200) => 667, |
| chr(201) => 667, |
| chr(202) => 667, |
| chr(203) => 667, |
| chr(204) => 389, |
| chr(205) => 389, |
| chr(206) => 389, |
| chr(207) => 389, |
| chr(208) => 722, |
| chr(209) => 722, |
| chr(210) => 778, |
| chr(211) => 778, |
| chr(212) => 778, |
| chr(213) => 778, |
| chr(214) => 778, |
| chr(215) => 570, |
| chr(216) => 778, |
| chr(217) => 722, |
| chr(218) => 722, |
| chr(219) => 722, |
| chr(220) => 722, |
| chr(221) => 722, |
| chr(222) => 611, |
| chr(223) => 556, |
| chr(224) => 500, |
| chr(225) => 500, |
| chr(226) => 500, |
| chr(227) => 500, |
| chr(228) => 500, |
| chr(229) => 500, |
| chr(230) => 722, |
| chr(231) => 444, |
| chr(232) => 444, |
| chr(233) => 444, |
| chr(234) => 444, |
| chr(235) => 444, |
| chr(236) => 278, |
| chr(237) => 278, |
| chr(238) => 278, |
| chr(239) => 278, |
| chr(240) => 500, |
| chr(241) => 556, |
| chr(242) => 500, |
| chr(243) => 500, |
| chr(244) => 500, |
| chr(245) => 500, |
| chr(246) => 500, |
| chr(247) => 570, |
| chr(248) => 500, |
| chr(249) => 556, |
| chr(250) => 556, |
| chr(251) => 556, |
| chr(252) => 556, |
| chr(253) => 500, |
| chr(254) => 556, |
| chr(255) => 500); |
| /trunk/applications/jrest/lib/File/PDF/fonts/helvetica.php |
|---|
| New file |
| 0,0 → 1,272 |
| <?php |
| /** |
| * @package File_PDF |
| */ |
| $font_widths['helvetica'] = array( |
| chr(0) => 278, |
| chr(1) => 278, |
| chr(2) => 278, |
| chr(3) => 278, |
| chr(4) => 278, |
| chr(5) => 278, |
| chr(6) => 278, |
| chr(7) => 278, |
| chr(8) => 278, |
| chr(9) => 278, |
| chr(10) => 278, |
| chr(11) => 278, |
| chr(12) => 278, |
| chr(13) => 278, |
| chr(14) => 278, |
| chr(15) => 278, |
| chr(16) => 278, |
| chr(17) => 278, |
| chr(18) => 278, |
| chr(19) => 278, |
| chr(20) => 278, |
| chr(21) => 278, |
| chr(22) => 278, |
| chr(23) => 278, |
| chr(24) => 278, |
| chr(25) => 278, |
| chr(26) => 278, |
| chr(27) => 278, |
| chr(28) => 278, |
| chr(29) => 278, |
| chr(30) => 278, |
| chr(31) => 278, |
| ' ' => 278, |
| '!' => 278, |
| '"' => 355, |
| '#' => 556, |
| '$' => 556, |
| '%' => 889, |
| '&' => 667, |
| '\'' => 191, |
| '(' => 333, |
| ')' => 333, |
| '*' => 389, |
| '+' => 584, |
| ',' => 278, |
| '-' => 333, |
| '.' => 278, |
| '/' => 278, |
| '0' => 556, |
| '1' => 556, |
| '2' => 556, |
| '3' => 556, |
| '4' => 556, |
| '5' => 556, |
| '6' => 556, |
| '7' => 556, |
| '8' => 556, |
| '9' => 556, |
| ':' => 278, |
| ';' => 278, |
| '<' => 584, |
| '=' => 584, |
| '>' => 584, |
| '?' => 556, |
| '@' => 1015, |
| 'A' => 667, |
| 'B' => 667, |
| 'C' => 722, |
| 'D' => 722, |
| 'E' => 667, |
| 'F' => 611, |
| 'G' => 778, |
| 'H' => 722, |
| 'I' => 278, |
| 'J' => 500, |
| 'K' => 667, |
| 'L' => 556, |
| 'M' => 833, |
| 'N' => 722, |
| 'O' => 778, |
| 'P' => 667, |
| 'Q' => 778, |
| 'R' => 722, |
| 'S' => 667, |
| 'T' => 611, |
| 'U' => 722, |
| 'V' => 667, |
| 'W' => 944, |
| 'X' => 667, |
| 'Y' => 667, |
| 'Z' => 611, |
| '[' => 278, |
| '\\' => 278, |
| ']' => 278, |
| '^' => 469, |
| '_' => 556, |
| '`' => 333, |
| 'a' => 556, |
| 'b' => 556, |
| 'c' => 500, |
| 'd' => 556, |
| 'e' => 556, |
| 'f' => 278, |
| 'g' => 556, |
| 'h' => 556, |
| 'i' => 222, |
| 'j' => 222, |
| 'k' => 500, |
| 'l' => 222, |
| 'm' => 833, |
| 'n' => 556, |
| 'o' => 556, |
| 'p' => 556, |
| 'q' => 556, |
| 'r' => 333, |
| 's' => 500, |
| 't' => 278, |
| 'u' => 556, |
| 'v' => 500, |
| 'w' => 722, |
| 'x' => 500, |
| 'y' => 500, |
| 'z' => 500, |
| '{' => 334, |
| '|' => 260, |
| '}' => 334, |
| '~' => 584, |
| chr(127) => 350, |
| chr(128) => 556, |
| chr(129) => 350, |
| chr(130) => 222, |
| chr(131) => 556, |
| chr(132) => 333, |
| chr(133) => 1000, |
| chr(134) => 556, |
| chr(135) => 556, |
| chr(136) => 333, |
| chr(137) => 1000, |
| chr(138) => 667, |
| chr(139) => 333, |
| chr(140) => 1000, |
| chr(141) => 350, |
| chr(142) => 611, |
| chr(143) => 350, |
| chr(144) => 350, |
| chr(145) => 222, |
| chr(146) => 222, |
| chr(147) => 333, |
| chr(148) => 333, |
| chr(149) => 350, |
| chr(150) => 556, |
| chr(151) => 1000, |
| chr(152) => 333, |
| chr(153) => 1000, |
| chr(154) => 500, |
| chr(155) => 333, |
| chr(156) => 944, |
| chr(157) => 350, |
| chr(158) => 500, |
| chr(159) => 667, |
| chr(160) => 278, |
| chr(161) => 333, |
| chr(162) => 556, |
| chr(163) => 556, |
| chr(164) => 556, |
| chr(165) => 556, |
| chr(166) => 260, |
| chr(167) => 556, |
| chr(168) => 333, |
| chr(169) => 737, |
| chr(170) => 370, |
| chr(171) => 556, |
| chr(172) => 584, |
| chr(173) => 333, |
| chr(174) => 737, |
| chr(175) => 333, |
| chr(176) => 400, |
| chr(177) => 584, |
| chr(178) => 333, |
| chr(179) => 333, |
| chr(180) => 333, |
| chr(181) => 556, |
| chr(182) => 537, |
| chr(183) => 278, |
| chr(184) => 333, |
| chr(185) => 333, |
| chr(186) => 365, |
| chr(187) => 556, |
| chr(188) => 834, |
| chr(189) => 834, |
| chr(190) => 834, |
| chr(191) => 611, |
| chr(192) => 667, |
| chr(193) => 667, |
| chr(194) => 667, |
| chr(195) => 667, |
| chr(196) => 667, |
| chr(197) => 667, |
| chr(198) => 1000, |
| chr(199) => 722, |
| chr(200) => 667, |
| chr(201) => 667, |
| chr(202) => 667, |
| chr(203) => 667, |
| chr(204) => 278, |
| chr(205) => 278, |
| chr(206) => 278, |
| chr(207) => 278, |
| chr(208) => 722, |
| chr(209) => 722, |
| chr(210) => 778, |
| chr(211) => 778, |
| chr(212) => 778, |
| chr(213) => 778, |
| chr(214) => 778, |
| chr(215) => 584, |
| chr(216) => 778, |
| chr(217) => 722, |
| chr(218) => 722, |
| chr(219) => 722, |
| chr(220) => 722, |
| chr(221) => 667, |
| chr(222) => 667, |
| chr(223) => 611, |
| chr(224) => 556, |
| chr(225) => 556, |
| chr(226) => 556, |
| chr(227) => 556, |
| chr(228) => 556, |
| chr(229) => 556, |
| chr(230) => 889, |
| chr(231) => 500, |
| chr(232) => 556, |
| chr(233) => 556, |
| chr(234) => 556, |
| chr(235) => 556, |
| chr(236) => 278, |
| chr(237) => 278, |
| chr(238) => 278, |
| chr(239) => 278, |
| chr(240) => 556, |
| chr(241) => 556, |
| chr(242) => 556, |
| chr(243) => 556, |
| chr(244) => 556, |
| chr(245) => 556, |
| chr(246) => 556, |
| chr(247) => 584, |
| chr(248) => 611, |
| chr(249) => 556, |
| chr(250) => 556, |
| chr(251) => 556, |
| chr(252) => 556, |
| chr(253) => 500, |
| chr(254) => 556, |
| chr(255) => 500); |
| /trunk/applications/jrest/lib/File/PDF/fonts/symbol.php |
|---|
| New file |
| 0,0 → 1,272 |
| <?php |
| /** |
| * @package File_PDF |
| */ |
| $font_widths['symbol'] = array( |
| chr(0) => 250, |
| chr(1) => 250, |
| chr(2) => 250, |
| chr(3) => 250, |
| chr(4) => 250, |
| chr(5) => 250, |
| chr(6) => 250, |
| chr(7) => 250, |
| chr(8) => 250, |
| chr(9) => 250, |
| chr(10) => 250, |
| chr(11) => 250, |
| chr(12) => 250, |
| chr(13) => 250, |
| chr(14) => 250, |
| chr(15) => 250, |
| chr(16) => 250, |
| chr(17) => 250, |
| chr(18) => 250, |
| chr(19) => 250, |
| chr(20) => 250, |
| chr(21) => 250, |
| chr(22) => 250, |
| chr(23) => 250, |
| chr(24) => 250, |
| chr(25) => 250, |
| chr(26) => 250, |
| chr(27) => 250, |
| chr(28) => 250, |
| chr(29) => 250, |
| chr(30) => 250, |
| chr(31) => 250, |
| ' ' => 250, |
| '!' => 333, |
| '"' => 713, |
| '#' => 500, |
| '$' => 549, |
| '%' => 833, |
| '&' => 778, |
| '\'' => 439, |
| '(' => 333, |
| ')' => 333, |
| '*' => 500, |
| '+' => 549, |
| ',' => 250, |
| '-' => 549, |
| '.' => 250, |
| '/' => 278, |
| '0' => 500, |
| '1' => 500, |
| '2' => 500, |
| '3' => 500, |
| '4' => 500, |
| '5' => 500, |
| '6' => 500, |
| '7' => 500, |
| '8' => 500, |
| '9' => 500, |
| ':' => 278, |
| ';' => 278, |
| '<' => 549, |
| '=' => 549, |
| '>' => 549, |
| '?' => 444, |
| '@' => 549, |
| 'A' => 722, |
| 'B' => 667, |
| 'C' => 722, |
| 'D' => 612, |
| 'E' => 611, |
| 'F' => 763, |
| 'G' => 603, |
| 'H' => 722, |
| 'I' => 333, |
| 'J' => 631, |
| 'K' => 722, |
| 'L' => 686, |
| 'M' => 889, |
| 'N' => 722, |
| 'O' => 722, |
| 'P' => 768, |
| 'Q' => 741, |
| 'R' => 556, |
| 'S' => 592, |
| 'T' => 611, |
| 'U' => 690, |
| 'V' => 439, |
| 'W' => 768, |
| 'X' => 645, |
| 'Y' => 795, |
| 'Z' => 611, |
| '[' => 333, |
| '\\' => 863, |
| ']' => 333, |
| '^' => 658, |
| '_' => 500, |
| '`' => 500, |
| 'a' => 631, |
| 'b' => 549, |
| 'c' => 549, |
| 'd' => 494, |
| 'e' => 439, |
| 'f' => 521, |
| 'g' => 411, |
| 'h' => 603, |
| 'i' => 329, |
| 'j' => 603, |
| 'k' => 549, |
| 'l' => 549, |
| 'm' => 576, |
| 'n' => 521, |
| 'o' => 549, |
| 'p' => 549, |
| 'q' => 521, |
| 'r' => 549, |
| 's' => 603, |
| 't' => 439, |
| 'u' => 576, |
| 'v' => 713, |
| 'w' => 686, |
| 'x' => 493, |
| 'y' => 686, |
| 'z' => 494, |
| '{' => 480, |
| '|' => 200, |
| '}' => 480, |
| '~' => 549, |
| chr(127) => 0, |
| chr(128) => 0, |
| chr(129) => 0, |
| chr(130) => 0, |
| chr(131) => 0, |
| chr(132) => 0, |
| chr(133) => 0, |
| chr(134) => 0, |
| chr(135) => 0, |
| chr(136) => 0, |
| chr(137) => 0, |
| chr(138) => 0, |
| chr(139) => 0, |
| chr(140) => 0, |
| chr(141) => 0, |
| chr(142) => 0, |
| chr(143) => 0, |
| chr(144) => 0, |
| chr(145) => 0, |
| chr(146) => 0, |
| chr(147) => 0, |
| chr(148) => 0, |
| chr(149) => 0, |
| chr(150) => 0, |
| chr(151) => 0, |
| chr(152) => 0, |
| chr(153) => 0, |
| chr(154) => 0, |
| chr(155) => 0, |
| chr(156) => 0, |
| chr(157) => 0, |
| chr(158) => 0, |
| chr(159) => 0, |
| chr(160) => 750, |
| chr(161) => 620, |
| chr(162) => 247, |
| chr(163) => 549, |
| chr(164) => 167, |
| chr(165) => 713, |
| chr(166) => 500, |
| chr(167) => 753, |
| chr(168) => 753, |
| chr(169) => 753, |
| chr(170) => 753, |
| chr(171) => 1042, |
| chr(172) => 987, |
| chr(173) => 603, |
| chr(174) => 987, |
| chr(175) => 603, |
| chr(176) => 400, |
| chr(177) => 549, |
| chr(178) => 411, |
| chr(179) => 549, |
| chr(180) => 549, |
| chr(181) => 713, |
| chr(182) => 494, |
| chr(183) => 460, |
| chr(184) => 549, |
| chr(185) => 549, |
| chr(186) => 549, |
| chr(187) => 549, |
| chr(188) => 1000, |
| chr(189) => 603, |
| chr(190) => 1000, |
| chr(191) => 658, |
| chr(192) => 823, |
| chr(193) => 686, |
| chr(194) => 795, |
| chr(195) => 987, |
| chr(196) => 768, |
| chr(197) => 768, |
| chr(198) => 823, |
| chr(199) => 768, |
| chr(200) => 768, |
| chr(201) => 713, |
| chr(202) => 713, |
| chr(203) => 713, |
| chr(204) => 713, |
| chr(205) => 713, |
| chr(206) => 713, |
| chr(207) => 713, |
| chr(208) => 768, |
| chr(209) => 713, |
| chr(210) => 790, |
| chr(211) => 790, |
| chr(212) => 890, |
| chr(213) => 823, |
| chr(214) => 549, |
| chr(215) => 250, |
| chr(216) => 713, |
| chr(217) => 603, |
| chr(218) => 603, |
| chr(219) => 1042, |
| chr(220) => 987, |
| chr(221) => 603, |
| chr(222) => 987, |
| chr(223) => 603, |
| chr(224) => 494, |
| chr(225) => 329, |
| chr(226) => 790, |
| chr(227) => 790, |
| chr(228) => 786, |
| chr(229) => 713, |
| chr(230) => 384, |
| chr(231) => 384, |
| chr(232) => 384, |
| chr(233) => 384, |
| chr(234) => 384, |
| chr(235) => 384, |
| chr(236) => 494, |
| chr(237) => 494, |
| chr(238) => 494, |
| chr(239) => 494, |
| chr(240) => 0, |
| chr(241) => 329, |
| chr(242) => 274, |
| chr(243) => 686, |
| chr(244) => 686, |
| chr(245) => 686, |
| chr(246) => 384, |
| chr(247) => 384, |
| chr(248) => 384, |
| chr(249) => 384, |
| chr(250) => 384, |
| chr(251) => 384, |
| chr(252) => 494, |
| chr(253) => 494, |
| chr(254) => 494, |
| chr(255) => 0); |
| /trunk/applications/jrest/lib/File/PDF/fonts/helveticab.php |
|---|
| New file |
| 0,0 → 1,272 |
| <?php |
| /** |
| * @package File_PDF |
| */ |
| $font_widths['helveticaB'] = array( |
| chr(0) => 278, |
| chr(1) => 278, |
| chr(2) => 278, |
| chr(3) => 278, |
| chr(4) => 278, |
| chr(5) => 278, |
| chr(6) => 278, |
| chr(7) => 278, |
| chr(8) => 278, |
| chr(9) => 278, |
| chr(10) => 278, |
| chr(11) => 278, |
| chr(12) => 278, |
| chr(13) => 278, |
| chr(14) => 278, |
| chr(15) => 278, |
| chr(16) => 278, |
| chr(17) => 278, |
| chr(18) => 278, |
| chr(19) => 278, |
| chr(20) => 278, |
| chr(21) => 278, |
| chr(22) => 278, |
| chr(23) => 278, |
| chr(24) => 278, |
| chr(25) => 278, |
| chr(26) => 278, |
| chr(27) => 278, |
| chr(28) => 278, |
| chr(29) => 278, |
| chr(30) => 278, |
| chr(31) => 278, |
| ' ' => 278, |
| '!' => 333, |
| '"' => 474, |
| '#' => 556, |
| '$' => 556, |
| '%' => 889, |
| '&' => 722, |
| '\'' => 238, |
| '(' => 333, |
| ')' => 333, |
| '*' => 389, |
| '+' => 584, |
| ',' => 278, |
| '-' => 333, |
| '.' => 278, |
| '/' => 278, |
| '0' => 556, |
| '1' => 556, |
| '2' => 556, |
| '3' => 556, |
| '4' => 556, |
| '5' => 556, |
| '6' => 556, |
| '7' => 556, |
| '8' => 556, |
| '9' => 556, |
| ':' => 333, |
| ';' => 333, |
| '<' => 584, |
| '=' => 584, |
| '>' => 584, |
| '?' => 611, |
| '@' => 975, |
| 'A' => 722, |
| 'B' => 722, |
| 'C' => 722, |
| 'D' => 722, |
| 'E' => 667, |
| 'F' => 611, |
| 'G' => 778, |
| 'H' => 722, |
| 'I' => 278, |
| 'J' => 556, |
| 'K' => 722, |
| 'L' => 611, |
| 'M' => 833, |
| 'N' => 722, |
| 'O' => 778, |
| 'P' => 667, |
| 'Q' => 778, |
| 'R' => 722, |
| 'S' => 667, |
| 'T' => 611, |
| 'U' => 722, |
| 'V' => 667, |
| 'W' => 944, |
| 'X' => 667, |
| 'Y' => 667, |
| 'Z' => 611, |
| '[' => 333, |
| '\\' => 278, |
| ']' => 333, |
| '^' => 584, |
| '_' => 556, |
| '`' => 333, |
| 'a' => 556, |
| 'b' => 611, |
| 'c' => 556, |
| 'd' => 611, |
| 'e' => 556, |
| 'f' => 333, |
| 'g' => 611, |
| 'h' => 611, |
| 'i' => 278, |
| 'j' => 278, |
| 'k' => 556, |
| 'l' => 278, |
| 'm' => 889, |
| 'n' => 611, |
| 'o' => 611, |
| 'p' => 611, |
| 'q' => 611, |
| 'r' => 389, |
| 's' => 556, |
| 't' => 333, |
| 'u' => 611, |
| 'v' => 556, |
| 'w' => 778, |
| 'x' => 556, |
| 'y' => 556, |
| 'z' => 500, |
| '{' => 389, |
| '|' => 280, |
| '}' => 389, |
| '~' => 584, |
| chr(127) => 350, |
| chr(128) => 556, |
| chr(129) => 350, |
| chr(130) => 278, |
| chr(131) => 556, |
| chr(132) => 500, |
| chr(133) => 1000, |
| chr(134) => 556, |
| chr(135) => 556, |
| chr(136) => 333, |
| chr(137) => 1000, |
| chr(138) => 667, |
| chr(139) => 333, |
| chr(140) => 1000, |
| chr(141) => 350, |
| chr(142) => 611, |
| chr(143) => 350, |
| chr(144) => 350, |
| chr(145) => 278, |
| chr(146) => 278, |
| chr(147) => 500, |
| chr(148) => 500, |
| chr(149) => 350, |
| chr(150) => 556, |
| chr(151) => 1000, |
| chr(152) => 333, |
| chr(153) => 1000, |
| chr(154) => 556, |
| chr(155) => 333, |
| chr(156) => 944, |
| chr(157) => 350, |
| chr(158) => 500, |
| chr(159) => 667, |
| chr(160) => 278, |
| chr(161) => 333, |
| chr(162) => 556, |
| chr(163) => 556, |
| chr(164) => 556, |
| chr(165) => 556, |
| chr(166) => 280, |
| chr(167) => 556, |
| chr(168) => 333, |
| chr(169) => 737, |
| chr(170) => 370, |
| chr(171) => 556, |
| chr(172) => 584, |
| chr(173) => 333, |
| chr(174) => 737, |
| chr(175) => 333, |
| chr(176) => 400, |
| chr(177) => 584, |
| chr(178) => 333, |
| chr(179) => 333, |
| chr(180) => 333, |
| chr(181) => 611, |
| chr(182) => 556, |
| chr(183) => 278, |
| chr(184) => 333, |
| chr(185) => 333, |
| chr(186) => 365, |
| chr(187) => 556, |
| chr(188) => 834, |
| chr(189) => 834, |
| chr(190) => 834, |
| chr(191) => 611, |
| chr(192) => 722, |
| chr(193) => 722, |
| chr(194) => 722, |
| chr(195) => 722, |
| chr(196) => 722, |
| chr(197) => 722, |
| chr(198) => 1000, |
| chr(199) => 722, |
| chr(200) => 667, |
| chr(201) => 667, |
| chr(202) => 667, |
| chr(203) => 667, |
| chr(204) => 278, |
| chr(205) => 278, |
| chr(206) => 278, |
| chr(207) => 278, |
| chr(208) => 722, |
| chr(209) => 722, |
| chr(210) => 778, |
| chr(211) => 778, |
| chr(212) => 778, |
| chr(213) => 778, |
| chr(214) => 778, |
| chr(215) => 584, |
| chr(216) => 778, |
| chr(217) => 722, |
| chr(218) => 722, |
| chr(219) => 722, |
| chr(220) => 722, |
| chr(221) => 667, |
| chr(222) => 667, |
| chr(223) => 611, |
| chr(224) => 556, |
| chr(225) => 556, |
| chr(226) => 556, |
| chr(227) => 556, |
| chr(228) => 556, |
| chr(229) => 556, |
| chr(230) => 889, |
| chr(231) => 556, |
| chr(232) => 556, |
| chr(233) => 556, |
| chr(234) => 556, |
| chr(235) => 556, |
| chr(236) => 278, |
| chr(237) => 278, |
| chr(238) => 278, |
| chr(239) => 278, |
| chr(240) => 611, |
| chr(241) => 611, |
| chr(242) => 611, |
| chr(243) => 611, |
| chr(244) => 611, |
| chr(245) => 611, |
| chr(246) => 611, |
| chr(247) => 584, |
| chr(248) => 611, |
| chr(249) => 611, |
| chr(250) => 611, |
| chr(251) => 611, |
| chr(252) => 611, |
| chr(253) => 556, |
| chr(254) => 611, |
| chr(255) => 556); |
| /trunk/applications/jrest/lib/File/PDF/fonts/courier.php |
|---|
| New file |
| 0,0 → 1,10 |
| <?php |
| /** |
| * @package File_PDF |
| */ |
| for ($i = 0; $i <= 255; $i++) { |
| $font_widths['courier'][chr($i)] = 600; |
| } |
| $font_widths['courierB'] = $font_widths['courier']; |
| $font_widths['courierI'] = $font_widths['courier']; |
| $font_widths['courierBI'] = $font_widths['courier']; |
| /trunk/applications/jrest/lib/HTTP/Download.php |
|---|
| New file |
| 0,0 → 1,1034 |
| <?php |
| /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
| /** |
| * HTTP::Download |
| * |
| * PHP versions 4 and 5 |
| * |
| * @category HTTP |
| * @package HTTP_Download |
| * @author Michael Wallner <mike@php.net> |
| * @copyright 2003-2005 Michael Wallner |
| * @license BSD, revised |
| * @version CVS: $Id$ |
| * @link http://pear.php.net/package/HTTP_Download |
| */ |
| // {{{ includes |
| /** |
| * Requires PEAR |
| */ |
| require_once 'PEAR.php'; |
| /** |
| * Requires HTTP_Header |
| */ |
| require_once 'HTTP/Header.php'; |
| // }}} |
| // {{{ constants |
| /**#@+ Use with HTTP_Download::setContentDisposition() **/ |
| /** |
| * Send data as attachment |
| */ |
| define('HTTP_DOWNLOAD_ATTACHMENT', 'attachment'); |
| /** |
| * Send data inline |
| */ |
| define('HTTP_DOWNLOAD_INLINE', 'inline'); |
| /**#@-**/ |
| /**#@+ Use with HTTP_Download::sendArchive() **/ |
| /** |
| * Send as uncompressed tar archive |
| */ |
| define('HTTP_DOWNLOAD_TAR', 'TAR'); |
| /** |
| * Send as gzipped tar archive |
| */ |
| define('HTTP_DOWNLOAD_TGZ', 'TGZ'); |
| /** |
| * Send as bzip2 compressed tar archive |
| */ |
| define('HTTP_DOWNLOAD_BZ2', 'BZ2'); |
| /** |
| * Send as zip archive |
| */ |
| define('HTTP_DOWNLOAD_ZIP', 'ZIP'); |
| /**#@-**/ |
| /**#@+ |
| * Error constants |
| */ |
| define('HTTP_DOWNLOAD_E_HEADERS_SENT', -1); |
| define('HTTP_DOWNLOAD_E_NO_EXT_ZLIB', -2); |
| define('HTTP_DOWNLOAD_E_NO_EXT_MMAGIC', -3); |
| define('HTTP_DOWNLOAD_E_INVALID_FILE', -4); |
| define('HTTP_DOWNLOAD_E_INVALID_PARAM', -5); |
| define('HTTP_DOWNLOAD_E_INVALID_RESOURCE', -6); |
| define('HTTP_DOWNLOAD_E_INVALID_REQUEST', -7); |
| define('HTTP_DOWNLOAD_E_INVALID_CONTENT_TYPE', -8); |
| define('HTTP_DOWNLOAD_E_INVALID_ARCHIVE_TYPE', -9); |
| /**#@-**/ |
| // }}} |
| /** |
| * Send HTTP Downloads/Responses. |
| * |
| * With this package you can handle (hidden) downloads. |
| * It supports partial downloads, resuming and sending |
| * raw data ie. from database BLOBs. |
| * |
| * <i>ATTENTION:</i> |
| * You shouldn't use this package together with ob_gzhandler or |
| * zlib.output_compression enabled in your php.ini, especially |
| * if you want to send already gzipped data! |
| * |
| * @access public |
| * @version $Revision$ |
| */ |
| class HTTP_Download |
| { |
| // {{{ protected member variables |
| /** |
| * Path to file for download |
| * |
| * @see HTTP_Download::setFile() |
| * @access protected |
| * @var string |
| */ |
| var $file = ''; |
| /** |
| * Data for download |
| * |
| * @see HTTP_Download::setData() |
| * @access protected |
| * @var string |
| */ |
| var $data = null; |
| /** |
| * Resource handle for download |
| * |
| * @see HTTP_Download::setResource() |
| * @access protected |
| * @var int |
| */ |
| var $handle = null; |
| /** |
| * Whether to gzip the download |
| * |
| * @access protected |
| * @var bool |
| */ |
| var $gzip = false; |
| /** |
| * Whether to allow caching of the download on the clients side |
| * |
| * @access protected |
| * @var bool |
| */ |
| var $cache = true; |
| /** |
| * Size of download |
| * |
| * @access protected |
| * @var int |
| */ |
| var $size = 0; |
| /** |
| * Last modified |
| * |
| * @access protected |
| * @var int |
| */ |
| var $lastModified = 0; |
| /** |
| * HTTP headers |
| * |
| * @access protected |
| * @var array |
| */ |
| var $headers = array( |
| 'Content-Type' => 'application/x-octetstream', |
| 'Pragma' => 'cache', |
| 'Cache-Control' => 'public, must-revalidate, max-age=0', |
| 'Accept-Ranges' => 'bytes', |
| 'X-Sent-By' => 'PEAR::HTTP::Download' |
| ); |
| /** |
| * HTTP_Header |
| * |
| * @access protected |
| * @var object |
| */ |
| var $HTTP = null; |
| /** |
| * ETag |
| * |
| * @access protected |
| * @var string |
| */ |
| var $etag = ''; |
| /** |
| * Buffer Size |
| * |
| * @access protected |
| * @var int |
| */ |
| var $bufferSize = 2097152; |
| /** |
| * Throttle Delay |
| * |
| * @access protected |
| * @var float |
| */ |
| var $throttleDelay = 0; |
| /** |
| * Sent Bytes |
| * |
| * @access public |
| * @var int |
| */ |
| var $sentBytes = 0; |
| // }}} |
| // {{{ constructor |
| /** |
| * Constructor |
| * |
| * Set supplied parameters. |
| * |
| * @access public |
| * @param array $params associative array of parameters |
| * |
| * <b>one of:</b> |
| * o 'file' => path to file for download |
| * o 'data' => raw data for download |
| * o 'resource' => resource handle for download |
| * <br/> |
| * <b>and any of:</b> |
| * o 'cache' => whether to allow cs caching |
| * o 'gzip' => whether to gzip the download |
| * o 'lastmodified' => unix timestamp |
| * o 'contenttype' => content type of download |
| * o 'contentdisposition' => content disposition |
| * o 'buffersize' => amount of bytes to buffer |
| * o 'throttledelay' => amount of secs to sleep |
| * o 'cachecontrol' => cache privacy and validity |
| * |
| * <br /> |
| * 'Content-Disposition' is not HTTP compliant, but most browsers |
| * follow this header, so it was borrowed from MIME standard. |
| * |
| * It looks like this: <br /> |
| * "Content-Disposition: attachment; filename=example.tgz". |
| * |
| * @see HTTP_Download::setContentDisposition() |
| */ |
| function HTTP_Download($params = array()) |
| { |
| $this->HTTP = &new HTTP_Header; |
| $this->setParams($params); |
| } |
| // }}} |
| // {{{ public methods |
| /** |
| * Set parameters |
| * |
| * Set supplied parameters through its accessor methods. |
| * |
| * @access public |
| * @return mixed Returns true on success or PEAR_Error on failure. |
| * @param array $params associative array of parameters |
| * |
| * @see HTTP_Download::HTTP_Download() |
| */ |
| function setParams($params) |
| { |
| foreach((array) $params as $param => $value){ |
| $method = 'set'. $param; |
| if (!method_exists($this, $method)) { |
| return PEAR::raiseError( |
| "Method '$method' doesn't exist.", |
| HTTP_DOWNLOAD_E_INVALID_PARAM |
| ); |
| } |
| $e = call_user_func_array(array(&$this, $method), (array) $value); |
| if (PEAR::isError($e)) { |
| return $e; |
| } |
| } |
| return true; |
| } |
| /** |
| * Set path to file for download |
| * |
| * The Last-Modified header will be set to files filemtime(), actually. |
| * Returns PEAR_Error (HTTP_DOWNLOAD_E_INVALID_FILE) if file doesn't exist. |
| * Sends HTTP 404 status if $send_404 is set to true. |
| * |
| * @access public |
| * @return mixed Returns true on success or PEAR_Error on failure. |
| * @param string $file path to file for download |
| * @param bool $send_404 whether to send HTTP/404 if |
| * the file wasn't found |
| */ |
| function setFile($file, $send_404 = true) |
| { |
| $file = realpath($file); |
| if (!is_file($file)) { |
| if ($send_404) { |
| $this->HTTP->sendStatusCode(404); |
| } |
| return PEAR::raiseError( |
| "File '$file' not found.", |
| HTTP_DOWNLOAD_E_INVALID_FILE |
| ); |
| } |
| $this->setLastModified(filemtime($file)); |
| $this->file = $file; |
| $this->size = filesize($file); |
| return true; |
| } |
| /** |
| * Set data for download |
| * |
| * Set $data to null if you want to unset this. |
| * |
| * @access public |
| * @return void |
| * @param $data raw data to send |
| */ |
| function setData($data = null) |
| { |
| $this->data = $data; |
| $this->size = strlen($data); |
| } |
| /** |
| * Set resource for download |
| * |
| * The resource handle supplied will be closed after sending the download. |
| * Returns a PEAR_Error (HTTP_DOWNLOAD_E_INVALID_RESOURCE) if $handle |
| * is no valid resource. Set $handle to null if you want to unset this. |
| * |
| * @access public |
| * @return mixed Returns true on success or PEAR_Error on failure. |
| * @param int $handle resource handle |
| */ |
| function setResource($handle = null) |
| { |
| if (!isset($handle)) { |
| $this->handle = null; |
| $this->size = 0; |
| return true; |
| } |
| if (is_resource($handle)) { |
| $this->handle = $handle; |
| $filestats = fstat($handle); |
| $this->size = $filestats['size']; |
| return true; |
| } |
| return PEAR::raiseError( |
| "Handle '$handle' is no valid resource.", |
| HTTP_DOWNLOAD_E_INVALID_RESOURCE |
| ); |
| } |
| /** |
| * Whether to gzip the download |
| * |
| * Returns a PEAR_Error (HTTP_DOWNLOAD_E_NO_EXT_ZLIB) |
| * if ext/zlib is not available/loadable. |
| * |
| * @access public |
| * @return mixed Returns true on success or PEAR_Error on failure. |
| * @param bool $gzip whether to gzip the download |
| */ |
| function setGzip($gzip = false) |
| { |
| if ($gzip && !PEAR::loadExtension('zlib')){ |
| return PEAR::raiseError( |
| 'GZIP compression (ext/zlib) not available.', |
| HTTP_DOWNLOAD_E_NO_EXT_ZLIB |
| ); |
| } |
| $this->gzip = (bool) $gzip; |
| return true; |
| } |
| /** |
| * Whether to allow caching |
| * |
| * If set to true (default) we'll send some headers that are commonly |
| * used for caching purposes like ETag, Cache-Control and Last-Modified. |
| * |
| * If caching is disabled, we'll send the download no matter if it |
| * would actually be cached at the client side. |
| * |
| * @access public |
| * @return void |
| * @param bool $cache whether to allow caching |
| */ |
| function setCache($cache = true) |
| { |
| $this->cache = (bool) $cache; |
| } |
| /** |
| * Whether to allow proxies to cache |
| * |
| * If set to 'private' proxies shouldn't cache the response. |
| * This setting defaults to 'public' and affects only cached responses. |
| * |
| * @access public |
| * @return bool |
| * @param string $cache private or public |
| * @param int $maxage maximum age of the client cache entry |
| */ |
| function setCacheControl($cache = 'public', $maxage = 0) |
| { |
| switch ($cache = strToLower($cache)) |
| { |
| case 'private': |
| case 'public': |
| $this->headers['Cache-Control'] = |
| $cache .', must-revalidate, max-age='. abs($maxage); |
| return true; |
| break; |
| } |
| return false; |
| } |
| /** |
| * Set ETag |
| * |
| * Sets a user-defined ETag for cache-validation. The ETag is usually |
| * generated by HTTP_Download through its payload information. |
| * |
| * @access public |
| * @return void |
| * @param string $etag Entity tag used for strong cache validation. |
| */ |
| function setETag($etag = null) |
| { |
| $this->etag = (string) $etag; |
| } |
| /** |
| * Set Size of Buffer |
| * |
| * The amount of bytes specified as buffer size is the maximum amount |
| * of data read at once from resources or files. The default size is 2M |
| * (2097152 bytes). Be aware that if you enable gzip compression and |
| * you set a very low buffer size that the actual file size may grow |
| * due to added gzip headers for each sent chunk of the specified size. |
| * |
| * Returns PEAR_Error (HTTP_DOWNLOAD_E_INVALID_PARAM) if $size is not |
| * greater than 0 bytes. |
| * |
| * @access public |
| * @return mixed Returns true on success or PEAR_Error on failure. |
| * @param int $bytes Amount of bytes to use as buffer. |
| */ |
| function setBufferSize($bytes = 2097152) |
| { |
| if (0 >= $bytes) { |
| return PEAR::raiseError( |
| 'Buffer size must be greater than 0 bytes ('. $bytes .' given)', |
| HTTP_DOWNLOAD_E_INVALID_PARAM); |
| } |
| $this->bufferSize = abs($bytes); |
| return true; |
| } |
| /** |
| * Set Throttle Delay |
| * |
| * Set the amount of seconds to sleep after each chunck that has been |
| * sent. One can implement some sort of throttle through adjusting the |
| * buffer size and the throttle delay. With the following settings |
| * HTTP_Download will sleep a second after each 25 K of data sent. |
| * |
| * <code> |
| * Array( |
| * 'throttledelay' => 1, |
| * 'buffersize' => 1024 * 25, |
| * ) |
| * </code> |
| * |
| * Just be aware that if gzipp'ing is enabled, decreasing the chunk size |
| * too much leads to proportionally increased network traffic due to added |
| * gzip header and bottom bytes around each chunk. |
| * |
| * @access public |
| * @return void |
| * @param float $seconds Amount of seconds to sleep after each |
| * chunk that has been sent. |
| */ |
| function setThrottleDelay($seconds = 0) |
| { |
| $this->throttleDelay = abs($seconds) * 1000; |
| } |
| /** |
| * Set "Last-Modified" |
| * |
| * This is usually determined by filemtime() in HTTP_Download::setFile() |
| * If you set raw data for download with HTTP_Download::setData() and you |
| * want do send an appropiate "Last-Modified" header, you should call this |
| * method. |
| * |
| * @access public |
| * @return void |
| * @param int unix timestamp |
| */ |
| function setLastModified($last_modified) |
| { |
| $this->lastModified = $this->headers['Last-Modified'] = (int) $last_modified; |
| } |
| /** |
| * Set Content-Disposition header |
| * |
| * @see HTTP_Download::HTTP_Download |
| * |
| * @access public |
| * @return void |
| * @param string $disposition whether to send the download |
| * inline or as attachment |
| * @param string $file_name the filename to display in |
| * the browser's download window |
| * |
| * <b>Example:</b> |
| * <code> |
| * $HTTP_Download->setContentDisposition( |
| * HTTP_DOWNLOAD_ATTACHMENT, |
| * 'download.tgz' |
| * ); |
| * </code> |
| */ |
| function setContentDisposition( $disposition = HTTP_DOWNLOAD_ATTACHMENT, |
| $file_name = null) |
| { |
| $cd = $disposition; |
| if (isset($file_name)) { |
| $cd .= '; filename="' . $file_name . '"'; |
| } elseif ($this->file) { |
| $cd .= '; filename="' . basename($this->file) . '"'; |
| } |
| $this->headers['Content-Disposition'] = $cd; |
| } |
| /** |
| * Set content type of the download |
| * |
| * Default content type of the download will be 'application/x-octetstream'. |
| * Returns PEAR_Error (HTTP_DOWNLOAD_E_INVALID_CONTENT_TYPE) if |
| * $content_type doesn't seem to be valid. |
| * |
| * @access public |
| * @return mixed Returns true on success or PEAR_Error on failure. |
| * @param string $content_type content type of file for download |
| */ |
| function setContentType($content_type = 'application/x-octetstream') |
| { |
| if (!preg_match('/^[a-z]+\w*\/[a-z]+[\w.;= -]*$/', $content_type)) { |
| return PEAR::raiseError( |
| "Invalid content type '$content_type' supplied.", |
| HTTP_DOWNLOAD_E_INVALID_CONTENT_TYPE |
| ); |
| } |
| $this->headers['Content-Type'] = $content_type; |
| return true; |
| } |
| /** |
| * Guess content type of file |
| * |
| * First we try to use PEAR::MIME_Type, if installed, to detect the content |
| * type, else we check if ext/mime_magic is loaded and properly configured. |
| * |
| * Returns PEAR_Error if: |
| * o if PEAR::MIME_Type failed to detect a proper content type |
| * (HTTP_DOWNLOAD_E_INVALID_CONTENT_TYPE) |
| * o ext/magic.mime is not installed, or not properly configured |
| * (HTTP_DOWNLOAD_E_NO_EXT_MMAGIC) |
| * o mime_content_type() couldn't guess content type or returned |
| * a content type considered to be bogus by setContentType() |
| * (HTTP_DOWNLOAD_E_INVALID_CONTENT_TYPE) |
| * |
| * @access public |
| * @return mixed Returns true on success or PEAR_Error on failure. |
| */ |
| function guessContentType() |
| { |
| if (class_exists('MIME_Type') || @include_once 'MIME/Type.php') { |
| if (PEAR::isError($mime_type = MIME_Type::autoDetect($this->file))) { |
| return PEAR::raiseError($mime_type->getMessage(), |
| HTTP_DOWNLOAD_E_INVALID_CONTENT_TYPE); |
| } |
| return $this->setContentType($mime_type); |
| } |
| if (!function_exists('mime_content_type')) { |
| return PEAR::raiseError( |
| 'This feature requires ext/mime_magic!', |
| HTTP_DOWNLOAD_E_NO_EXT_MMAGIC |
| ); |
| } |
| if (!is_file(ini_get('mime_magic.magicfile'))) { |
| return PEAR::raiseError( |
| 'ext/mime_magic is loaded but not properly configured!', |
| HTTP_DOWNLOAD_E_NO_EXT_MMAGIC |
| ); |
| } |
| if (!$content_type = @mime_content_type($this->file)) { |
| return PEAR::raiseError( |
| 'Couldn\'t guess content type with mime_content_type().', |
| HTTP_DOWNLOAD_E_INVALID_CONTENT_TYPE |
| ); |
| } |
| return $this->setContentType($content_type); |
| } |
| /** |
| * Send |
| * |
| * Returns PEAR_Error if: |
| * o HTTP headers were already sent (HTTP_DOWNLOAD_E_HEADERS_SENT) |
| * o HTTP Range was invalid (HTTP_DOWNLOAD_E_INVALID_REQUEST) |
| * |
| * @access public |
| * @return mixed Returns true on success or PEAR_Error on failure. |
| * @param bool $autoSetContentDisposition Whether to set the |
| * Content-Disposition header if it isn't already. |
| */ |
| function send($autoSetContentDisposition = true) |
| { |
| if (headers_sent()) { |
| return PEAR::raiseError( |
| 'Headers already sent.', |
| HTTP_DOWNLOAD_E_HEADERS_SENT |
| ); |
| } |
| if (!ini_get('safe_mode')) { |
| @set_time_limit(0); |
| } |
| if ($autoSetContentDisposition && |
| !isset($this->headers['Content-Disposition'])) { |
| $this->setContentDisposition(); |
| } |
| if ($this->cache) { |
| $this->headers['ETag'] = $this->generateETag(); |
| if ($this->isCached()) { |
| $this->HTTP->sendStatusCode(304); |
| $this->sendHeaders(); |
| return true; |
| } |
| } else { |
| unset($this->headers['Last-Modified']); |
| } |
| if (ob_get_level()) { |
| while (@ob_end_clean()); |
| } |
| if ($this->gzip) { |
| @ob_start('ob_gzhandler'); |
| } else { |
| ob_start(); |
| } |
| $this->sentBytes = 0; |
| if ($this->isRangeRequest()) { |
| $this->HTTP->sendStatusCode(206); |
| $chunks = $this->getChunks(); |
| } else { |
| $this->HTTP->sendStatusCode(200); |
| $chunks = array(array(0, $this->size)); |
| if (!$this->gzip && count(ob_list_handlers()) < 2) { |
| $this->headers['Content-Length'] = $this->size; |
| } |
| } |
| if (PEAR::isError($e = $this->sendChunks($chunks))) { |
| ob_end_clean(); |
| $this->HTTP->sendStatusCode(416); |
| return $e; |
| } |
| ob_end_flush(); |
| flush(); |
| return true; |
| } |
| /** |
| * Static send |
| * |
| * @see HTTP_Download::HTTP_Download() |
| * @see HTTP_Download::send() |
| * |
| * @static |
| * @access public |
| * @return mixed Returns true on success or PEAR_Error on failure. |
| * @param array $params associative array of parameters |
| * @param bool $guess whether HTTP_Download::guessContentType() |
| * should be called |
| */ |
| function staticSend($params, $guess = false) |
| { |
| $d = &new HTTP_Download(); |
| $e = $d->setParams($params); |
| if (PEAR::isError($e)) { |
| return $e; |
| } |
| if ($guess) { |
| $e = $d->guessContentType(); |
| if (PEAR::isError($e)) { |
| return $e; |
| } |
| } |
| return $d->send(); |
| } |
| /** |
| * Send a bunch of files or directories as an archive |
| * |
| * Example: |
| * <code> |
| * require_once 'HTTP/Download.php'; |
| * HTTP_Download::sendArchive( |
| * 'myArchive.tgz', |
| * '/var/ftp/pub/mike', |
| * HTTP_DOWNLOAD_TGZ, |
| * '', |
| * '/var/ftp/pub' |
| * ); |
| * </code> |
| * |
| * @see Archive_Tar::createModify() |
| * @deprecated use HTTP_Download_Archive::send() |
| * @static |
| * @access public |
| * @return mixed Returns true on success or PEAR_Error on failure. |
| * @param string $name name the sent archive should have |
| * @param mixed $files files/directories |
| * @param string $type archive type |
| * @param string $add_path path that should be prepended to the files |
| * @param string $strip_path path that should be stripped from the files |
| */ |
| function sendArchive( $name, |
| $files, |
| $type = HTTP_DOWNLOAD_TGZ, |
| $add_path = '', |
| $strip_path = '') |
| { |
| require_once 'HTTP/Download/Archive.php'; |
| return HTTP_Download_Archive::send($name, $files, $type, |
| $add_path, $strip_path); |
| } |
| // }}} |
| // {{{ protected methods |
| /** |
| * Generate ETag |
| * |
| * @access protected |
| * @return string |
| */ |
| function generateETag() |
| { |
| if (!$this->etag) { |
| if ($this->data) { |
| $md5 = md5($this->data); |
| } else { |
| $fst = is_resource($this->handle) ? |
| fstat($this->handle) : stat($this->file); |
| $md5 = md5($fst['mtime'] .'='. $fst['ino'] .'='. $fst['size']); |
| } |
| $this->etag = '"' . $md5 . '-' . crc32($md5) . '"'; |
| } |
| return $this->etag; |
| } |
| /** |
| * Send multiple chunks |
| * |
| * @access protected |
| * @return mixed Returns true on success or PEAR_Error on failure. |
| * @param array $chunks |
| */ |
| function sendChunks($chunks) |
| { |
| if (count($chunks) == 1) { |
| return $this->sendChunk(current($chunks)); |
| } |
| $bound = uniqid('HTTP_DOWNLOAD-', true); |
| $cType = $this->headers['Content-Type']; |
| $this->headers['Content-Type'] = |
| 'multipart/byteranges; boundary=' . $bound; |
| $this->sendHeaders(); |
| foreach ($chunks as $chunk){ |
| if (PEAR::isError($e = $this->sendChunk($chunk, $cType, $bound))) { |
| return $e; |
| } |
| } |
| #echo "\r\n--$bound--\r\n"; |
| return true; |
| } |
| /** |
| * Send chunk of data |
| * |
| * @access protected |
| * @return mixed Returns true on success or PEAR_Error on failure. |
| * @param array $chunk start and end offset of the chunk to send |
| * @param string $cType actual content type |
| * @param string $bound boundary for multipart/byteranges |
| */ |
| function sendChunk($chunk, $cType = null, $bound = null) |
| { |
| list($offset, $lastbyte) = $chunk; |
| $length = ($lastbyte - $offset) + 1; |
| if ($length < 1) { |
| return PEAR::raiseError( |
| "Error processing range request: $offset-$lastbyte/$length", |
| HTTP_DOWNLOAD_E_INVALID_REQUEST |
| ); |
| } |
| $range = $offset . '-' . $lastbyte . '/' . $this->size; |
| if (isset($cType, $bound)) { |
| echo "\r\n--$bound\r\n", |
| "Content-Type: $cType\r\n", |
| "Content-Range: bytes $range\r\n\r\n"; |
| } else { |
| if ($this->isRangeRequest()) { |
| $this->headers['Content-Length'] = $length; |
| $this->headers['Content-Range'] = 'bytes '. $range; |
| } |
| $this->sendHeaders(); |
| } |
| if ($this->data) { |
| while (($length -= $this->bufferSize) > 0) { |
| $this->flush(substr($this->data, $offset, $this->bufferSize)); |
| $this->throttleDelay and $this->sleep(); |
| $offset += $this->bufferSize; |
| } |
| if ($length) { |
| $this->flush(substr($this->data, $offset, $this->bufferSize + $length)); |
| } |
| } else { |
| if (!is_resource($this->handle)) { |
| $this->handle = fopen($this->file, 'rb'); |
| } |
| fseek($this->handle, $offset); |
| while (($length -= $this->bufferSize) > 0) { |
| $this->flush(fread($this->handle, $this->bufferSize)); |
| $this->throttleDelay and $this->sleep(); |
| } |
| if ($length) { |
| $this->flush(fread($this->handle, $this->bufferSize + $length)); |
| } |
| } |
| return true; |
| } |
| /** |
| * Get chunks to send |
| * |
| * @access protected |
| * @return array |
| */ |
| function getChunks() |
| { |
| $parts = array(); |
| foreach (explode(',', $this->getRanges()) as $chunk){ |
| list($o, $e) = explode('-', $chunk); |
| if ($e >= $this->size || (empty($e) && $e !== 0 && $e !== '0')) { |
| $e = $this->size - 1; |
| } |
| if (empty($o) && $o !== 0 && $o !== '0') { |
| $o = $this->size - $e; |
| $e = $this->size - 1; |
| } |
| $parts[] = array($o, $e); |
| } |
| return $parts; |
| } |
| /** |
| * Check if range is requested |
| * |
| * @access protected |
| * @return bool |
| */ |
| function isRangeRequest() |
| { |
| if (!isset($_SERVER['HTTP_RANGE'])) { |
| return false; |
| } |
| return $this->isValidRange(); |
| } |
| /** |
| * Get range request |
| * |
| * @access protected |
| * @return array |
| */ |
| function getRanges() |
| { |
| return preg_match('/^bytes=((\d*-\d*,? ?)+)$/', |
| @$_SERVER['HTTP_RANGE'], $matches) ? $matches[1] : array(); |
| } |
| /** |
| * Check if entity is cached |
| * |
| * @access protected |
| * @return bool |
| */ |
| function isCached() |
| { |
| return ( |
| (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && |
| $this->lastModified == strtotime(current($a = explode( |
| ';', $_SERVER['HTTP_IF_MODIFIED_SINCE'])))) || |
| (isset($_SERVER['HTTP_IF_NONE_MATCH']) && |
| $this->compareAsterisk('HTTP_IF_NONE_MATCH', $this->etag)) |
| ); |
| } |
| /** |
| * Check if entity hasn't changed |
| * |
| * @access protected |
| * @return bool |
| */ |
| function isValidRange() |
| { |
| if (isset($_SERVER['HTTP_IF_MATCH']) && |
| !$this->compareAsterisk('HTTP_IF_MATCH', $this->etag)) { |
| return false; |
| } |
| if (isset($_SERVER['HTTP_IF_RANGE']) && |
| $_SERVER['HTTP_IF_RANGE'] !== $this->etag && |
| strtotime($_SERVER['HTTP_IF_RANGE']) !== $this->lastModified) { |
| return false; |
| } |
| if (isset($_SERVER['HTTP_IF_UNMODIFIED_SINCE'])) { |
| $lm = current($a = explode(';', $_SERVER['HTTP_IF_UNMODIFIED_SINCE'])); |
| if (strtotime($lm) !== $this->lastModified) { |
| return false; |
| } |
| } |
| if (isset($_SERVER['HTTP_UNLESS_MODIFIED_SINCE'])) { |
| $lm = current($a = explode(';', $_SERVER['HTTP_UNLESS_MODIFIED_SINCE'])); |
| if (strtotime($lm) !== $this->lastModified) { |
| return false; |
| } |
| } |
| return true; |
| } |
| /** |
| * Compare against an asterisk or check for equality |
| * |
| * @access protected |
| * @return bool |
| * @param string key for the $_SERVER array |
| * @param string string to compare |
| */ |
| function compareAsterisk($svar, $compare) |
| { |
| foreach (array_map('trim', explode(',', $_SERVER[$svar])) as $request) { |
| if ($request === '*' || $request === $compare) { |
| return true; |
| } |
| } |
| return false; |
| } |
| /** |
| * Send HTTP headers |
| * |
| * @access protected |
| * @return void |
| */ |
| function sendHeaders() |
| { |
| foreach ($this->headers as $header => $value) { |
| $this->HTTP->setHeader($header, $value); |
| } |
| $this->HTTP->sendHeaders(); |
| /* NSAPI won't output anything if we did this */ |
| if (strncasecmp(PHP_SAPI, 'nsapi', 5)) { |
| ob_flush(); |
| flush(); |
| } |
| } |
| /** |
| * Flush |
| * |
| * @access protected |
| * @return void |
| * @param string $data |
| */ |
| function flush($data = '') |
| { |
| if ($dlen = strlen($data)) { |
| $this->sentBytes += $dlen; |
| echo $data; |
| } |
| ob_flush(); |
| flush(); |
| } |
| /** |
| * Sleep |
| * |
| * @access protected |
| * @return void |
| */ |
| function sleep() |
| { |
| if (OS_WINDOWS) { |
| com_message_pump($this->throttleDelay); |
| } else { |
| usleep($this->throttleDelay * 1000); |
| } |
| } |
| // }}} |
| } |
| ?> |
| /trunk/applications/jrest/lib/HTTP/HTTP/Header.php |
|---|
| New file |
| 0,0 → 1,531 |
| <?php |
| /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
| /** |
| * HTTP::Header |
| * |
| * PHP versions 4 and 5 |
| * |
| * @category HTTP |
| * @package HTTP_Header |
| * @author Wolfram Kriesing <wk@visionp.de> |
| * @author Davey Shafik <davey@php.net> |
| * @author Michael Wallner <mike@php.net> |
| * @copyright 2003-2005 The Authors |
| * @license BSD, revised |
| * @version CVS: $Id$ |
| * @link http://pear.php.net/package/HTTP_Header |
| */ |
| /** |
| * Requires HTTP |
| */ |
| require_once 'HTTP.php'; |
| /**#@+ |
| * Information Codes |
| */ |
| define('HTTP_HEADER_STATUS_100', '100 Continue'); |
| define('HTTP_HEADER_STATUS_101', '101 Switching Protocols'); |
| define('HTTP_HEADER_STATUS_102', '102 Processing'); |
| define('HTTP_HEADER_STATUS_INFORMATIONAL',1); |
| /**#@-*/ |
| /**#+ |
| * Success Codes |
| */ |
| define('HTTP_HEADER_STATUS_200', '200 OK'); |
| define('HTTP_HEADER_STATUS_201', '201 Created'); |
| define('HTTP_HEADER_STATUS_202', '202 Accepted'); |
| define('HTTP_HEADER_STATUS_203', '203 Non-Authoritative Information'); |
| define('HTTP_HEADER_STATUS_204', '204 No Content'); |
| define('HTTP_HEADER_STATUS_205', '205 Reset Content'); |
| define('HTTP_HEADER_STATUS_206', '206 Partial Content'); |
| define('HTTP_HEADER_STATUS_207', '207 Multi-Status'); |
| define('HTTP_HEADER_STATUS_SUCCESSFUL',2); |
| /**#@-*/ |
| /**#@+ |
| * Redirection Codes |
| */ |
| define('HTTP_HEADER_STATUS_300', '300 Multiple Choices'); |
| define('HTTP_HEADER_STATUS_301', '301 Moved Permanently'); |
| define('HTTP_HEADER_STATUS_302', '302 Found'); |
| define('HTTP_HEADER_STATUS_303', '303 See Other'); |
| define('HTTP_HEADER_STATUS_304', '304 Not Modified'); |
| define('HTTP_HEADER_STATUS_305', '305 Use Proxy'); |
| define('HTTP_HEADER_STATUS_306', '306 (Unused)'); |
| define('HTTP_HEADER_STATUS_307', '307 Temporary Redirect'); |
| define('HTTP_HEADER_STATUS_REDIRECT',3); |
| /**#@-*/ |
| /**#@+ |
| * Error Codes |
| */ |
| define('HTTP_HEADER_STATUS_400', '400 Bad Request'); |
| define('HTTP_HEADER_STATUS_401', '401 Unauthorized'); |
| define('HTTP_HEADER_STATUS_402', '402 Payment Granted'); |
| define('HTTP_HEADER_STATUS_403', '403 Forbidden'); |
| define('HTTP_HEADER_STATUS_404', '404 File Not Found'); |
| define('HTTP_HEADER_STATUS_405', '405 Method Not Allowed'); |
| define('HTTP_HEADER_STATUS_406', '406 Not Acceptable'); |
| define('HTTP_HEADER_STATUS_407', '407 Proxy Authentication Required'); |
| define('HTTP_HEADER_STATUS_408', '408 Request Time-out'); |
| define('HTTP_HEADER_STATUS_409', '409 Conflict'); |
| define('HTTP_HEADER_STATUS_410', '410 Gone'); |
| define('HTTP_HEADER_STATUS_411', '411 Length Required'); |
| define('HTTP_HEADER_STATUS_412', '412 Precondition Failed'); |
| define('HTTP_HEADER_STATUS_413', '413 Request Entity Too Large'); |
| define('HTTP_HEADER_STATUS_414', '414 Request-URI Too Large'); |
| define('HTTP_HEADER_STATUS_415', '415 Unsupported Media Type'); |
| define('HTTP_HEADER_STATUS_416', '416 Requested range not satisfiable'); |
| define('HTTP_HEADER_STATUS_417', '417 Expectation Failed'); |
| define('HTTP_HEADER_STATUS_422', '422 Unprocessable Entity'); |
| define('HTTP_HEADER_STATUS_423', '423 Locked'); |
| define('HTTP_HEADER_STATUS_424', '424 Failed Dependency'); |
| define('HTTP_HEADER_STATUS_CLIENT_ERROR',4); |
| /**#@-*/ |
| /**#@+ |
| * Server Errors |
| */ |
| define('HTTP_HEADER_STATUS_500', '500 Internal Server Error'); |
| define('HTTP_HEADER_STATUS_501', '501 Not Implemented'); |
| define('HTTP_HEADER_STATUS_502', '502 Bad Gateway'); |
| define('HTTP_HEADER_STATUS_503', '503 Service Unavailable'); |
| define('HTTP_HEADER_STATUS_504', '504 Gateway Time-out'); |
| define('HTTP_HEADER_STATUS_505', '505 HTTP Version not supported'); |
| define('HTTP_HEADER_STATUS_507', '507 Insufficient Storage'); |
| define('HTTP_HEADER_STATUS_SERVER_ERROR',5); |
| /**#@-*/ |
| /** |
| * HTTP_Header |
| * |
| * @package HTTP_Header |
| * @category HTTP |
| * @access public |
| * @version $Revision$ |
| */ |
| class HTTP_Header extends HTTP |
| { |
| /** |
| * Default Headers |
| * |
| * The values that are set as default, are the same as PHP sends by default. |
| * |
| * @var array |
| * @access private |
| */ |
| var $_headers = array( |
| 'content-type' => 'text/html', |
| 'pragma' => 'no-cache', |
| 'cache-control' => 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0' |
| ); |
| /** |
| * HTTP version |
| * |
| * @var string |
| * @access private |
| */ |
| var $_httpVersion = '1.0'; |
| /** |
| * Constructor |
| * |
| * Sets HTTP version. |
| * |
| * @access public |
| * @return object HTTP_Header |
| */ |
| function HTTP_Header() |
| { |
| if (isset($_SERVER['SERVER_PROTOCOL'])) { |
| $this->setHttpVersion(substr($_SERVER['SERVER_PROTOCOL'], -3)); |
| } |
| } |
| /** |
| * Set HTTP version |
| * |
| * @access public |
| * @return bool Returns true on success or false if version doesn't |
| * match 1.0 or 1.1 (note: 1 will result in 1.0) |
| * @param mixed $version HTTP version, either 1.0 or 1.1 |
| */ |
| function setHttpVersion($version) |
| { |
| $version = round((float) $version, 1); |
| if ($version < 1.0 || $version > 1.1) { |
| return false; |
| } |
| $this->_httpVersion = sprintf('%0.1f', $version); |
| return true; |
| } |
| /** |
| * Get HTTP version |
| * |
| * @access public |
| * @return string |
| */ |
| function getHttpVersion() |
| { |
| return $this->_httpVersion; |
| } |
| /** |
| * Set Header |
| * |
| * The default value for the Last-Modified header will be current |
| * date and atime if $value is omitted. |
| * |
| * @access public |
| * @return bool Returns true on success or false if $key was empty or |
| * $value was not of an scalar type. |
| * @param string $key The name of the header. |
| * @param string $value The value of the header. (NULL to unset header) |
| */ |
| function setHeader($key, $value = null) |
| { |
| if (empty($key) || (isset($value) && !is_scalar($value))) { |
| return false; |
| } |
| $key = strToLower($key); |
| if ($key == 'last-modified') { |
| if (!isset($value)) { |
| $value = HTTP::Date(time()); |
| } elseif (is_numeric($value)) { |
| $value = HTTP::Date($value); |
| } |
| } |
| if (isset($value)) { |
| $this->_headers[$key] = $value; |
| } else { |
| unset($this->_headers[$key]); |
| } |
| return true; |
| } |
| /** |
| * Get Header |
| * |
| * If $key is omitted, all stored headers will be returned. |
| * |
| * @access public |
| * @return mixed Returns string value of the requested header, |
| * array values of all headers or false if header $key |
| * is not set. |
| * @param string $key The name of the header to fetch. |
| */ |
| function getHeader($key = null) |
| { |
| if (!isset($key)) { |
| return $this->_headers; |
| } |
| $key = strToLower($key); |
| if (!isset($this->_headers[$key])) { |
| return false; |
| } |
| return $this->_headers[$key]; |
| } |
| /** |
| * Send Headers |
| * |
| * Send out the header that you set via setHeader(). |
| * |
| * @access public |
| * @return bool Returns true on success or false if headers are already |
| * sent. |
| * @param array $keys Headers to (not) send, see $include. |
| * @param array $include If true only $keys matching headers will be |
| * sent, if false only header not matching $keys will be |
| * sent. |
| */ |
| function sendHeaders($keys = array(), $include = true) |
| { |
| if (headers_sent()) { |
| return false; |
| } |
| if (count($keys)) { |
| array_change_key_case($keys, CASE_LOWER); |
| foreach ($this->_headers as $key => $value) { |
| if ($include ? in_array($key, $keys) : !in_array($key, $keys)) { |
| header($key .': '. $value); |
| } |
| } |
| } else { |
| foreach ($this->_headers as $header => $value) { |
| header($header .': '. $value); |
| } |
| } |
| return true; |
| } |
| /** |
| * Send Satus Code |
| * |
| * Send out the given HTTP-Status code. Use this for example when you |
| * want to tell the client this page is cached, then you would call |
| * sendStatusCode(304). |
| * |
| * @see HTTP_Header_Cache::exitIfCached() |
| * |
| * @access public |
| * @return bool Returns true on success or false if headers are already |
| * sent. |
| * @param int $code The status code to send, i.e. 404, 304, 200, etc. |
| */ |
| function sendStatusCode($code) |
| { |
| if (headers_sent()) { |
| return false; |
| } |
| if ($code == (int) $code && defined('HTTP_HEADER_STATUS_'. $code)) { |
| $code = constant('HTTP_HEADER_STATUS_'. $code); |
| } |
| if (strncasecmp(PHP_SAPI, 'cgi', 3)) { |
| header('HTTP/'. $this->_httpVersion .' '. $code); |
| } else { |
| header('Status: '. $code); |
| } |
| return true; |
| } |
| /** |
| * Date to Timestamp |
| * |
| * Converts dates like |
| * Mon, 31 Mar 2003 15:26:34 GMT |
| * Tue, 15 Nov 1994 12:45:26 GMT |
| * into a timestamp, strtotime() didn't do it in older versions. |
| * |
| * @deprecated Use PHPs strtotime() instead. |
| * @access public |
| * @return mixed Returns int unix timestamp or false if the date doesn't |
| * seem to be a valid GMT date. |
| * @param string $date The GMT date. |
| */ |
| function dateToTimestamp($date) |
| { |
| static $months = array( |
| null => 0, 'Jan' => 1, 'Feb' => 2, 'Mar' => 3, 'Apr' => 4, |
| 'May' => 5, 'Jun' => 6, 'Jul' => 7, 'Aug' => 8, 'Sep' => 9, |
| 'Oct' => 10, 'Nov' => 11, 'Dec' => 12 |
| ); |
| if (-1 < $timestamp = strToTime($date)) { |
| return $timestamp; |
| } |
| if (!preg_match('~[^,]*,\s(\d+)\s(\w+)\s(\d+)\s(\d+):(\d+):(\d+).*~', |
| $date, $m)) { |
| return false; |
| } |
| // [0] => Mon, 31 Mar 2003 15:42:55 GMT |
| // [1] => 31 [2] => Mar [3] => 2003 [4] => 15 [5] => 42 [6] => 55 |
| return mktime($m[4], $m[5], $m[6], $months[$m[2]], $m[1], $m[3]); |
| } |
| /** |
| * Redirect |
| * |
| * This function redirects the client. This is done by issuing a Location |
| * header and exiting. Additionally to HTTP::redirect() you can also add |
| * parameters to the url. |
| * |
| * If you dont need parameters to be added, simply use HTTP::redirect() |
| * otherwise use HTTP_Header::redirect(). |
| * |
| * @see HTTP::redirect() |
| * @author Wolfram Kriesing <wk@visionp.de> |
| * @access public |
| * @return void |
| * @param string $url The URL to redirect to, if none is given it |
| * redirects to the current page. |
| * @param array $param Array of query string parameters to add; usually |
| * a set of key => value pairs; if an array entry consists |
| * only of an value it is used as key and the respective |
| * value is fetched from $GLOBALS[$value] |
| * @param bool $session Whether the session name/id should be added |
| */ |
| function redirect($url = null, $param = array(), $session = false) |
| { |
| if (!isset($url)) { |
| $url = $_SERVER['PHP_SELF']; |
| } |
| $qs = array(); |
| if ($session) { |
| $qs[] = session_name() .'='. session_id(); |
| } |
| if (is_array($param) && count($param)) { |
| if (count($param)) { |
| foreach ($param as $key => $val) { |
| if (is_string($key)) { |
| $qs[] = urlencode($key) .'='. urlencode($val); |
| } else { |
| $qs[] = urlencode($val) .'='. urlencode(@$GLOBALS[$val]); |
| } |
| } |
| } |
| } |
| if ($qstr = implode('&', $qs)) { |
| $purl = parse_url($url); |
| $url .= (isset($purl['query']) ? '&' : '?') . $qstr; |
| } |
| parent::redirect($url); |
| } |
| /**#@+ |
| * @author Davey Shafik <davey@php.net> |
| * @param int $http_code HTTP Code to check |
| * @access public |
| */ |
| /** |
| * Return HTTP Status Code Type |
| * |
| * @return int|false |
| */ |
| function getStatusType($http_code) |
| { |
| if(is_int($http_code) && defined('HTTP_HEADER_STATUS_' .$http_code) || defined($http_code)) { |
| $type = substr($http_code,0,1); |
| switch ($type) { |
| case HTTP_HEADER_STATUS_INFORMATIONAL: |
| case HTTP_HEADER_STATUS_SUCCESSFUL: |
| case HTTP_HEADER_STATUS_REDIRECT: |
| case HTTP_HEADER_STATUS_CLIENT_ERROR: |
| case HTTP_HEADER_STATUS_SERVER_ERROR: |
| return $type; |
| break; |
| default: |
| return false; |
| break; |
| } |
| } else { |
| return false; |
| } |
| } |
| /** |
| * Return Status Code Message |
| * |
| * @return string|false |
| */ |
| function getStatusText($http_code) |
| { |
| if ($this->getStatusType($http_code)) { |
| if (is_int($http_code) && defined('HTTP_HEADER_STATUS_' .$http_code)) { |
| return substr(constant('HTTP_HEADER_STATUS_' .$http_code),4); |
| } else { |
| return substr($http_code,4); |
| } |
| } else { |
| return false; |
| } |
| } |
| /** |
| * Checks if HTTP Status code is Information (1xx) |
| * |
| * @return boolean |
| */ |
| function isInformational($http_code) |
| { |
| if ($status_type = $this->getStatusType($http_code)) { |
| return $status_type{0} == HTTP_HEADER_STATUS_INFORMATIONAL; |
| } else { |
| return false; |
| } |
| } |
| /** |
| * Checks if HTTP Status code is Successful (2xx) |
| * |
| * @return boolean |
| */ |
| function isSuccessful($http_code) |
| { |
| if ($status_type = $this->getStatusType($http_code)) { |
| return $status_type{0} == HTTP_HEADER_STATUS_SUCCESSFUL; |
| } else { |
| return false; |
| } |
| } |
| /** |
| * Checks if HTTP Status code is a Redirect (3xx) |
| * |
| * @return boolean |
| */ |
| function isRedirect($http_code) |
| { |
| if ($status_type = $this->getStatusType($http_code)) { |
| return $status_type{0} == HTTP_HEADER_STATUS_REDIRECT; |
| } else { |
| return false; |
| } |
| } |
| /** |
| * Checks if HTTP Status code is a Client Error (4xx) |
| * |
| * @return boolean |
| */ |
| function isClientError($http_code) |
| { |
| if ($status_type = $this->getStatusType($http_code)) { |
| return $status_type{0} == HTTP_HEADER_STATUS_CLIENT_ERROR; |
| } else { |
| return false; |
| } |
| } |
| /** |
| * Checks if HTTP Status code is Server Error (5xx) |
| * |
| * @return boolean |
| */ |
| function isServerError($http_code) |
| { |
| if ($status_type = $this->getStatusType($http_code)) { |
| return $status_type{0} == HTTP_HEADER_STATUS_SERVER_ERROR; |
| } else { |
| return false; |
| } |
| } |
| /** |
| * Checks if HTTP Status code is Server OR Client Error (4xx or 5xx) |
| * |
| * @return boolean |
| */ |
| function isError($http_code) |
| { |
| if ($status_type = $this->getStatusType($http_code)) { |
| return (($status_type == HTTP_HEADER_STATUS_CLIENT_ERROR) || ($status_type == HTTP_HEADER_STATUS_SERVER_ERROR)) ? true : false; |
| } else { |
| return false; |
| } |
| } |
| /**#@-*/ |
| } |
| ?> |
| /trunk/applications/jrest/lib/.directory |
|---|
| New file |
| 0,0 → 1,5 |
| [Dolphin] |
| Timestamp=2010,10,19,15,1,12 |
| [Settings] |
| ShowDotFiles=true |
| /trunk/applications/jrest/lib/DB/mysql.php |
|---|
| New file |
| 0,0 → 1,916 |
| <?php |
| /* vim: set expandtab tabstop=4 shiftwidth=4 foldmethod=marker: */ |
| // +----------------------------------------------------------------------+ |
| // | PHP Version 4 | |
| // +----------------------------------------------------------------------+ |
| // | Copyright (c) 1997-2004 The PHP Group | |
| // +----------------------------------------------------------------------+ |
| // | This source file is subject to version 2.02 of the PHP license, | |
| // | that is bundled with this package in the file LICENSE, and is | |
| // | available at through the world-wide-web at | |
| // | http://www.php.net/license/2_02.txt. | |
| // | If you did not receive a copy of the PHP license and are unable to | |
| // | obtain it through the world-wide-web, please send a note to | |
| // | license@php.net so we can mail you a copy immediately. | |
| // +----------------------------------------------------------------------+ |
| // | Author: Stig Bakken <ssb@php.net> | |
| // | Maintainer: Daniel Convissor <danielc@php.net> | |
| // +----------------------------------------------------------------------+ |
| // |
| // $Id$ |
| // XXX legend: |
| // |
| // XXX ERRORMSG: The error message from the mysql function should |
| // be registered here. |
| // |
| // TODO/wishlist: |
| // longReadlen |
| // binmode |
| require_once 'DB/common.php'; |
| /** |
| * Database independent query interface definition for PHP's MySQL |
| * extension. |
| * |
| * This is for MySQL versions 4.0 and below. |
| * |
| * @package DB |
| * @version $Id$ |
| * @category Database |
| * @author Stig Bakken <ssb@php.net> |
| */ |
| class DB_mysql extends DB_common |
| { |
| // {{{ properties |
| var $connection; |
| var $phptype, $dbsyntax; |
| var $prepare_tokens = array(); |
| var $prepare_types = array(); |
| var $num_rows = array(); |
| var $transaction_opcount = 0; |
| var $autocommit = true; |
| var $fetchmode = DB_FETCHMODE_ORDERED; /* Default fetch mode */ |
| var $_db = false; |
| // }}} |
| // {{{ constructor |
| /** |
| * DB_mysql constructor. |
| * |
| * @access public |
| */ |
| function DB_mysql() |
| { |
| $this->DB_common(); |
| $this->phptype = 'mysql'; |
| $this->dbsyntax = 'mysql'; |
| $this->features = array( |
| 'prepare' => false, |
| 'pconnect' => true, |
| 'transactions' => true, |
| 'limit' => 'alter' |
| ); |
| $this->errorcode_map = array( |
| 1004 => DB_ERROR_CANNOT_CREATE, |
| 1005 => DB_ERROR_CANNOT_CREATE, |
| 1006 => DB_ERROR_CANNOT_CREATE, |
| 1007 => DB_ERROR_ALREADY_EXISTS, |
| 1008 => DB_ERROR_CANNOT_DROP, |
| 1022 => DB_ERROR_ALREADY_EXISTS, |
| 1046 => DB_ERROR_NODBSELECTED, |
| 1048 => DB_ERROR_CONSTRAINT, |
| 1050 => DB_ERROR_ALREADY_EXISTS, |
| 1051 => DB_ERROR_NOSUCHTABLE, |
| 1054 => DB_ERROR_NOSUCHFIELD, |
| 1062 => DB_ERROR_ALREADY_EXISTS, |
| 1064 => DB_ERROR_SYNTAX, |
| 1100 => DB_ERROR_NOT_LOCKED, |
| 1136 => DB_ERROR_VALUE_COUNT_ON_ROW, |
| 1146 => DB_ERROR_NOSUCHTABLE, |
| 1216 => DB_ERROR_CONSTRAINT, |
| 1217 => DB_ERROR_CONSTRAINT, |
| ); |
| } |
| // }}} |
| // {{{ connect() |
| /** |
| * Connect to a database and log in as the specified user. |
| * |
| * @param $dsn the data source name (see DB::parseDSN for syntax) |
| * @param $persistent (optional) whether the connection should |
| * be persistent |
| * @access public |
| * @return int DB_OK on success, a DB error on failure |
| */ |
| function connect($dsninfo, $persistent = false) |
| { |
| if (!DB::assertExtension('mysql')) { |
| return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND); |
| } |
| $this->dsn = $dsninfo; |
| if ($dsninfo['protocol'] && $dsninfo['protocol'] == 'unix') { |
| $dbhost = ':' . $dsninfo['socket']; |
| } else { |
| $dbhost = $dsninfo['hostspec'] ? $dsninfo['hostspec'] : 'localhost'; |
| if ($dsninfo['port']) { |
| $dbhost .= ':' . $dsninfo['port']; |
| } |
| } |
| $connect_function = $persistent ? 'mysql_pconnect' : 'mysql_connect'; |
| if ($dbhost && $dsninfo['username'] && isset($dsninfo['password'])) { |
| $conn = @$connect_function($dbhost, $dsninfo['username'], |
| $dsninfo['password']); |
| } elseif ($dbhost && $dsninfo['username']) { |
| $conn = @$connect_function($dbhost, $dsninfo['username']); |
| } elseif ($dbhost) { |
| $conn = @$connect_function($dbhost); |
| } else { |
| $conn = false; |
| } |
| if (!$conn) { |
| if (($err = @mysql_error()) != '') { |
| return $this->raiseError(DB_ERROR_CONNECT_FAILED, null, null, |
| null, $err); |
| } elseif (empty($php_errormsg)) { |
| return $this->raiseError(DB_ERROR_CONNECT_FAILED); |
| } else { |
| return $this->raiseError(DB_ERROR_CONNECT_FAILED, null, null, |
| null, $php_errormsg); |
| } |
| } |
| if ($dsninfo['database']) { |
| if (!@mysql_select_db($dsninfo['database'], $conn)) { |
| switch(mysql_errno($conn)) { |
| case 1049: |
| return $this->raiseError(DB_ERROR_NOSUCHDB, null, null, |
| null, @mysql_error($conn)); |
| case 1044: |
| return $this->raiseError(DB_ERROR_ACCESS_VIOLATION, null, null, |
| null, @mysql_error($conn)); |
| default: |
| return $this->raiseError(DB_ERROR, null, null, |
| null, @mysql_error($conn)); |
| } |
| } |
| // fix to allow calls to different databases in the same script |
| $this->_db = $dsninfo['database']; |
| } |
| $this->connection = $conn; |
| return DB_OK; |
| } |
| // }}} |
| // {{{ disconnect() |
| /** |
| * Log out and disconnect from the database. |
| * |
| * @access public |
| * |
| * @return bool true on success, false if not connected. |
| */ |
| function disconnect() |
| { |
| $ret = @mysql_close($this->connection); |
| $this->connection = null; |
| return $ret; |
| } |
| // }}} |
| // {{{ simpleQuery() |
| /** |
| * Send a query to MySQL and return the results as a MySQL resource |
| * identifier. |
| * |
| * @param the SQL query |
| * |
| * @access public |
| * |
| * @return mixed returns a valid MySQL result for successful SELECT |
| * queries, DB_OK for other successful queries. A DB error is |
| * returned on failure. |
| */ |
| function simpleQuery($query) |
| { |
| $ismanip = DB::isManip($query); |
| $this->last_query = $query; |
| $query = $this->modifyQuery($query); |
| if ($this->_db) { |
| if (!@mysql_select_db($this->_db, $this->connection)) { |
| return $this->mysqlRaiseError(DB_ERROR_NODBSELECTED); |
| } |
| } |
| if (!$this->autocommit && $ismanip) { |
| if ($this->transaction_opcount == 0) { |
| $result = @mysql_query('SET AUTOCOMMIT=0', $this->connection); |
| $result = @mysql_query('BEGIN', $this->connection); |
| if (!$result) { |
| return $this->mysqlRaiseError(); |
| } |
| } |
| $this->transaction_opcount++; |
| } |
| $result = @mysql_query($query, $this->connection); |
| if (!$result) { |
| return $this->mysqlRaiseError(); |
| } |
| if (is_resource($result)) { |
| $numrows = $this->numrows($result); |
| if (is_object($numrows)) { |
| return $numrows; |
| } |
| $this->num_rows[(int)$result] = $numrows; |
| return $result; |
| } |
| return DB_OK; |
| } |
| // }}} |
| // {{{ nextResult() |
| /** |
| * Move the internal mysql result pointer to the next available result |
| * |
| * This method has not been implemented yet. |
| * |
| * @param a valid sql result resource |
| * |
| * @access public |
| * |
| * @return false |
| */ |
| function nextResult($result) |
| { |
| return false; |
| } |
| // }}} |
| // {{{ fetchInto() |
| /** |
| * Fetch a row and insert the data into an existing array. |
| * |
| * Formating of the array and the data therein are configurable. |
| * See DB_result::fetchInto() for more information. |
| * |
| * @param resource $result query result identifier |
| * @param array $arr (reference) array where data from the row |
| * should be placed |
| * @param int $fetchmode how the resulting array should be indexed |
| * @param int $rownum the row number to fetch |
| * |
| * @return mixed DB_OK on success, null when end of result set is |
| * reached or on failure |
| * |
| * @see DB_result::fetchInto() |
| * @access private |
| */ |
| function fetchInto($result, &$arr, $fetchmode, $rownum=null) |
| { |
| if ($rownum !== null) { |
| if (!@mysql_data_seek($result, $rownum)) { |
| return null; |
| } |
| } |
| if ($fetchmode & DB_FETCHMODE_ASSOC) { |
| $arr = @mysql_fetch_array($result, MYSQL_ASSOC); |
| if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) { |
| $arr = array_change_key_case($arr, CASE_LOWER); |
| } |
| } else { |
| $arr = @mysql_fetch_row($result); |
| } |
| if (!$arr) { |
| // See: http://bugs.php.net/bug.php?id=22328 |
| // for why we can't check errors on fetching |
| return null; |
| /* |
| $errno = @mysql_errno($this->connection); |
| if (!$errno) { |
| return null; |
| } |
| return $this->mysqlRaiseError($errno); |
| */ |
| } |
| if ($this->options['portability'] & DB_PORTABILITY_RTRIM) { |
| /* |
| * Even though this DBMS already trims output, we do this because |
| * a field might have intentional whitespace at the end that |
| * gets removed by DB_PORTABILITY_RTRIM under another driver. |
| */ |
| $this->_rtrimArrayValues($arr); |
| } |
| if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) { |
| $this->_convertNullArrayValuesToEmpty($arr); |
| } |
| return DB_OK; |
| } |
| // }}} |
| // {{{ freeResult() |
| /** |
| * Free the internal resources associated with $result. |
| * |
| * @param $result MySQL result identifier |
| * |
| * @access public |
| * |
| * @return bool true on success, false if $result is invalid |
| */ |
| function freeResult($result) |
| { |
| unset($this->num_rows[(int)$result]); |
| return @mysql_free_result($result); |
| } |
| // }}} |
| // {{{ numCols() |
| /** |
| * Get the number of columns in a result set. |
| * |
| * @param $result MySQL result identifier |
| * |
| * @access public |
| * |
| * @return int the number of columns per row in $result |
| */ |
| function numCols($result) |
| { |
| $cols = @mysql_num_fields($result); |
| if (!$cols) { |
| return $this->mysqlRaiseError(); |
| } |
| return $cols; |
| } |
| // }}} |
| // {{{ numRows() |
| /** |
| * Get the number of rows in a result set. |
| * |
| * @param $result MySQL result identifier |
| * |
| * @access public |
| * |
| * @return int the number of rows in $result |
| */ |
| function numRows($result) |
| { |
| $rows = @mysql_num_rows($result); |
| if ($rows === null) { |
| return $this->mysqlRaiseError(); |
| } |
| return $rows; |
| } |
| // }}} |
| // {{{ autoCommit() |
| /** |
| * Enable/disable automatic commits |
| */ |
| function autoCommit($onoff = false) |
| { |
| // XXX if $this->transaction_opcount > 0, we should probably |
| // issue a warning here. |
| $this->autocommit = $onoff ? true : false; |
| return DB_OK; |
| } |
| // }}} |
| // {{{ commit() |
| /** |
| * Commit the current transaction. |
| */ |
| function commit() |
| { |
| if ($this->transaction_opcount > 0) { |
| if ($this->_db) { |
| if (!@mysql_select_db($this->_db, $this->connection)) { |
| return $this->mysqlRaiseError(DB_ERROR_NODBSELECTED); |
| } |
| } |
| $result = @mysql_query('COMMIT', $this->connection); |
| $result = @mysql_query('SET AUTOCOMMIT=1', $this->connection); |
| $this->transaction_opcount = 0; |
| if (!$result) { |
| return $this->mysqlRaiseError(); |
| } |
| } |
| return DB_OK; |
| } |
| // }}} |
| // {{{ rollback() |
| /** |
| * Roll back (undo) the current transaction. |
| */ |
| function rollback() |
| { |
| if ($this->transaction_opcount > 0) { |
| if ($this->_db) { |
| if (!@mysql_select_db($this->_db, $this->connection)) { |
| return $this->mysqlRaiseError(DB_ERROR_NODBSELECTED); |
| } |
| } |
| $result = @mysql_query('ROLLBACK', $this->connection); |
| $result = @mysql_query('SET AUTOCOMMIT=1', $this->connection); |
| $this->transaction_opcount = 0; |
| if (!$result) { |
| return $this->mysqlRaiseError(); |
| } |
| } |
| return DB_OK; |
| } |
| // }}} |
| // {{{ affectedRows() |
| /** |
| * Gets the number of rows affected by the data manipulation |
| * query. For other queries, this function returns 0. |
| * |
| * @return number of rows affected by the last query |
| */ |
| function affectedRows() |
| { |
| if (DB::isManip($this->last_query)) { |
| return @mysql_affected_rows($this->connection); |
| } else { |
| return 0; |
| } |
| } |
| // }}} |
| // {{{ errorNative() |
| /** |
| * Get the native error code of the last error (if any) that |
| * occured on the current connection. |
| * |
| * @access public |
| * |
| * @return int native MySQL error code |
| */ |
| function errorNative() |
| { |
| return @mysql_errno($this->connection); |
| } |
| // }}} |
| // {{{ nextId() |
| /** |
| * Returns the next free id in a sequence |
| * |
| * @param string $seq_name name of the sequence |
| * @param boolean $ondemand when true, the seqence is automatically |
| * created if it does not exist |
| * |
| * @return int the next id number in the sequence. DB_Error if problem. |
| * |
| * @internal |
| * @see DB_common::nextID() |
| * @access public |
| */ |
| function nextId($seq_name, $ondemand = true) |
| { |
| $seqname = $this->getSequenceName($seq_name); |
| do { |
| $repeat = 0; |
| $this->pushErrorHandling(PEAR_ERROR_RETURN); |
| $result = $this->query("UPDATE ${seqname} ". |
| 'SET id=LAST_INSERT_ID(id+1)'); |
| $this->popErrorHandling(); |
| if ($result === DB_OK) { |
| /** COMMON CASE **/ |
| $id = @mysql_insert_id($this->connection); |
| if ($id != 0) { |
| return $id; |
| } |
| /** EMPTY SEQ TABLE **/ |
| // Sequence table must be empty for some reason, so fill it and return 1 |
| // Obtain a user-level lock |
| $result = $this->getOne("SELECT GET_LOCK('${seqname}_lock',10)"); |
| if (DB::isError($result)) { |
| return $this->raiseError($result); |
| } |
| if ($result == 0) { |
| // Failed to get the lock, bail with a DB_ERROR_NOT_LOCKED error |
| return $this->mysqlRaiseError(DB_ERROR_NOT_LOCKED); |
| } |
| // add the default value |
| $result = $this->query("REPLACE INTO ${seqname} (id) VALUES (0)"); |
| if (DB::isError($result)) { |
| return $this->raiseError($result); |
| } |
| // Release the lock |
| $result = $this->getOne("SELECT RELEASE_LOCK('${seqname}_lock')"); |
| if (DB::isError($result)) { |
| return $this->raiseError($result); |
| } |
| // We know what the result will be, so no need to try again |
| return 1; |
| /** ONDEMAND TABLE CREATION **/ |
| } elseif ($ondemand && DB::isError($result) && |
| $result->getCode() == DB_ERROR_NOSUCHTABLE) |
| { |
| $result = $this->createSequence($seq_name); |
| if (DB::isError($result)) { |
| return $this->raiseError($result); |
| } else { |
| $repeat = 1; |
| } |
| /** BACKWARDS COMPAT **/ |
| } elseif (DB::isError($result) && |
| $result->getCode() == DB_ERROR_ALREADY_EXISTS) |
| { |
| // see _BCsequence() comment |
| $result = $this->_BCsequence($seqname); |
| if (DB::isError($result)) { |
| return $this->raiseError($result); |
| } |
| $repeat = 1; |
| } |
| } while ($repeat); |
| return $this->raiseError($result); |
| } |
| // }}} |
| // {{{ createSequence() |
| /** |
| * Creates a new sequence |
| * |
| * @param string $seq_name name of the new sequence |
| * |
| * @return int DB_OK on success. A DB_Error object is returned if |
| * problems arise. |
| * |
| * @internal |
| * @see DB_common::createSequence() |
| * @access public |
| */ |
| function createSequence($seq_name) |
| { |
| $seqname = $this->getSequenceName($seq_name); |
| $res = $this->query("CREATE TABLE ${seqname} ". |
| '(id INTEGER UNSIGNED AUTO_INCREMENT NOT NULL,'. |
| ' PRIMARY KEY(id))'); |
| if (DB::isError($res)) { |
| return $res; |
| } |
| // insert yields value 1, nextId call will generate ID 2 |
| $res = $this->query("INSERT INTO ${seqname} (id) VALUES (0)"); |
| if (DB::isError($res)) { |
| return $res; |
| } |
| // so reset to zero |
| return $this->query("UPDATE ${seqname} SET id = 0;"); |
| } |
| // }}} |
| // {{{ dropSequence() |
| /** |
| * Deletes a sequence |
| * |
| * @param string $seq_name name of the sequence to be deleted |
| * |
| * @return int DB_OK on success. DB_Error if problems. |
| * |
| * @internal |
| * @see DB_common::dropSequence() |
| * @access public |
| */ |
| function dropSequence($seq_name) |
| { |
| return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name)); |
| } |
| // }}} |
| // {{{ _BCsequence() |
| /** |
| * Backwards compatibility with old sequence emulation implementation |
| * (clean up the dupes) |
| * |
| * @param string $seqname The sequence name to clean up |
| * @return mixed DB_Error or true |
| */ |
| function _BCsequence($seqname) |
| { |
| // Obtain a user-level lock... this will release any previous |
| // application locks, but unlike LOCK TABLES, it does not abort |
| // the current transaction and is much less frequently used. |
| $result = $this->getOne("SELECT GET_LOCK('${seqname}_lock',10)"); |
| if (DB::isError($result)) { |
| return $result; |
| } |
| if ($result == 0) { |
| // Failed to get the lock, can't do the conversion, bail |
| // with a DB_ERROR_NOT_LOCKED error |
| return $this->mysqlRaiseError(DB_ERROR_NOT_LOCKED); |
| } |
| $highest_id = $this->getOne("SELECT MAX(id) FROM ${seqname}"); |
| if (DB::isError($highest_id)) { |
| return $highest_id; |
| } |
| // This should kill all rows except the highest |
| // We should probably do something if $highest_id isn't |
| // numeric, but I'm at a loss as how to handle that... |
| $result = $this->query("DELETE FROM ${seqname} WHERE id <> $highest_id"); |
| if (DB::isError($result)) { |
| return $result; |
| } |
| // If another thread has been waiting for this lock, |
| // it will go thru the above procedure, but will have no |
| // real effect |
| $result = $this->getOne("SELECT RELEASE_LOCK('${seqname}_lock')"); |
| if (DB::isError($result)) { |
| return $result; |
| } |
| return true; |
| } |
| // }}} |
| // {{{ quoteIdentifier() |
| /** |
| * Quote a string so it can be safely used as a table or column name |
| * |
| * Quoting style depends on which database driver is being used. |
| * |
| * MySQL can't handle the backtick character (<kbd>`</kbd>) in |
| * table or column names. |
| * |
| * @param string $str identifier name to be quoted |
| * |
| * @return string quoted identifier string |
| * |
| * @since 1.6.0 |
| * @access public |
| * @internal |
| */ |
| function quoteIdentifier($str) |
| { |
| return '`' . $str . '`'; |
| } |
| // }}} |
| // {{{ quote() |
| /** |
| * @deprecated Deprecated in release 1.6.0 |
| * @internal |
| */ |
| function quote($str) { |
| return $this->quoteSmart($str); |
| } |
| // }}} |
| // {{{ escapeSimple() |
| /** |
| * Escape a string according to the current DBMS's standards |
| * |
| * @param string $str the string to be escaped |
| * |
| * @return string the escaped string |
| * |
| * @internal |
| */ |
| function escapeSimple($str) { |
| if (function_exists('mysql_real_escape_string')) { |
| return @mysql_real_escape_string($str, $this->connection); |
| } else { |
| return @mysql_escape_string($str); |
| } |
| } |
| // }}} |
| // {{{ modifyQuery() |
| function modifyQuery($query) |
| { |
| if ($this->options['portability'] & DB_PORTABILITY_DELETE_COUNT) { |
| // "DELETE FROM table" gives 0 affected rows in MySQL. |
| // This little hack lets you know how many rows were deleted. |
| if (preg_match('/^\s*DELETE\s+FROM\s+(\S+)\s*$/i', $query)) { |
| $query = preg_replace('/^\s*DELETE\s+FROM\s+(\S+)\s*$/', |
| 'DELETE FROM \1 WHERE 1=1', $query); |
| } |
| } |
| return $query; |
| } |
| // }}} |
| // {{{ modifyLimitQuery() |
| function modifyLimitQuery($query, $from, $count, $params = array()) |
| { |
| if (DB::isManip($query)) { |
| return $query . " LIMIT $count"; |
| } else { |
| return $query . " LIMIT $from, $count"; |
| } |
| } |
| // }}} |
| // {{{ mysqlRaiseError() |
| /** |
| * Gather information about an error, then use that info to create a |
| * DB error object and finally return that object. |
| * |
| * @param integer $errno PEAR error number (usually a DB constant) if |
| * manually raising an error |
| * @return object DB error object |
| * @see DB_common::errorCode() |
| * @see DB_common::raiseError() |
| */ |
| function mysqlRaiseError($errno = null) |
| { |
| if ($errno === null) { |
| if ($this->options['portability'] & DB_PORTABILITY_ERRORS) { |
| $this->errorcode_map[1022] = DB_ERROR_CONSTRAINT; |
| $this->errorcode_map[1048] = DB_ERROR_CONSTRAINT_NOT_NULL; |
| $this->errorcode_map[1062] = DB_ERROR_CONSTRAINT; |
| } else { |
| // Doing this in case mode changes during runtime. |
| $this->errorcode_map[1022] = DB_ERROR_ALREADY_EXISTS; |
| $this->errorcode_map[1048] = DB_ERROR_CONSTRAINT; |
| $this->errorcode_map[1062] = DB_ERROR_ALREADY_EXISTS; |
| } |
| $errno = $this->errorCode(mysql_errno($this->connection)); |
| } |
| return $this->raiseError($errno, null, null, null, |
| @mysql_errno($this->connection) . ' ** ' . |
| @mysql_error($this->connection)); |
| } |
| // }}} |
| // {{{ tableInfo() |
| /** |
| * Returns information about a table or a result set. |
| * |
| * @param object|string $result DB_result object from a query or a |
| * string containing the name of a table |
| * @param int $mode a valid tableInfo mode |
| * @return array an associative array with the information requested |
| * or an error object if something is wrong |
| * @access public |
| * @internal |
| * @see DB_common::tableInfo() |
| */ |
| function tableInfo($result, $mode = null) { |
| if (isset($result->result)) { |
| /* |
| * Probably received a result object. |
| * Extract the result resource identifier. |
| */ |
| $id = $result->result; |
| $got_string = false; |
| } elseif (is_string($result)) { |
| /* |
| * Probably received a table name. |
| * Create a result resource identifier. |
| */ |
| $id = @mysql_list_fields($this->dsn['database'], |
| $result, $this->connection); |
| $got_string = true; |
| } else { |
| /* |
| * Probably received a result resource identifier. |
| * Copy it. |
| * Deprecated. Here for compatibility only. |
| */ |
| $id = $result; |
| $got_string = false; |
| } |
| if (!is_resource($id)) { |
| return $this->mysqlRaiseError(DB_ERROR_NEED_MORE_DATA); |
| } |
| if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) { |
| $case_func = 'strtolower'; |
| } else { |
| $case_func = 'strval'; |
| } |
| $count = @mysql_num_fields($id); |
| // made this IF due to performance (one if is faster than $count if's) |
| if (!$mode) { |
| for ($i=0; $i<$count; $i++) { |
| $res[$i]['table'] = $case_func(@mysql_field_table($id, $i)); |
| $res[$i]['name'] = $case_func(@mysql_field_name($id, $i)); |
| $res[$i]['type'] = @mysql_field_type($id, $i); |
| $res[$i]['len'] = @mysql_field_len($id, $i); |
| $res[$i]['flags'] = @mysql_field_flags($id, $i); |
| } |
| } else { // full |
| $res['num_fields']= $count; |
| for ($i=0; $i<$count; $i++) { |
| $res[$i]['table'] = $case_func(@mysql_field_table($id, $i)); |
| $res[$i]['name'] = $case_func(@mysql_field_name($id, $i)); |
| $res[$i]['type'] = @mysql_field_type($id, $i); |
| $res[$i]['len'] = @mysql_field_len($id, $i); |
| $res[$i]['flags'] = @mysql_field_flags($id, $i); |
| if ($mode & DB_TABLEINFO_ORDER) { |
| $res['order'][$res[$i]['name']] = $i; |
| } |
| if ($mode & DB_TABLEINFO_ORDERTABLE) { |
| $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; |
| } |
| } |
| } |
| // free the result only if we were called on a table |
| if ($got_string) { |
| @mysql_free_result($id); |
| } |
| return $res; |
| } |
| // }}} |
| // {{{ getSpecialQuery() |
| /** |
| * Returns the query needed to get some backend info |
| * @param string $type What kind of info you want to retrieve |
| * @return string The SQL query string |
| */ |
| function getSpecialQuery($type) |
| { |
| switch ($type) { |
| case 'tables': |
| return 'SHOW TABLES'; |
| case 'views': |
| return DB_ERROR_NOT_CAPABLE; |
| case 'users': |
| $sql = 'select distinct User from user'; |
| if ($this->dsn['database'] != 'mysql') { |
| $dsn = $this->dsn; |
| $dsn['database'] = 'mysql'; |
| if (DB::isError($db = DB::connect($dsn))) { |
| return $db; |
| } |
| $sql = $db->getCol($sql); |
| $db->disconnect(); |
| // XXX Fixme the mysql driver should take care of this |
| if (!@mysql_select_db($this->dsn['database'], $this->connection)) { |
| return $this->mysqlRaiseError(DB_ERROR_NODBSELECTED); |
| } |
| } |
| return $sql; |
| case 'databases': |
| return 'SHOW DATABASES'; |
| default: |
| return null; |
| } |
| } |
| // }}} |
| } |
| /* |
| * Local variables: |
| * tab-width: 4 |
| * c-basic-offset: 4 |
| * End: |
| */ |
| ?> |
| /trunk/applications/jrest/lib/DB/common.php |
|---|
| New file |
| 0,0 → 1,2040 |
| <?php |
| /* vim: set expandtab tabstop=4 shiftwidth=4 foldmethod=marker: */ |
| // +----------------------------------------------------------------------+ |
| // | PHP Version 4 | |
| // +----------------------------------------------------------------------+ |
| // | Copyright (c) 1997-2004 The PHP Group | |
| // +----------------------------------------------------------------------+ |
| // | This source file is subject to version 2.02 of the PHP license, | |
| // | that is bundled with this package in the file LICENSE, and is | |
| // | available at through the world-wide-web at | |
| // | http://www.php.net/license/2_02.txt. | |
| // | If you did not receive a copy of the PHP license and are unable to | |
| // | obtain it through the world-wide-web, please send a note to | |
| // | license@php.net so we can mail you a copy immediately. | |
| // +----------------------------------------------------------------------+ |
| // | Author: Stig Bakken <ssb@php.net> | |
| // | Tomas V.V.Cox <cox@idecnet.com> | |
| // | Maintainer: Daniel Convissor <danielc@php.net> | |
| // +----------------------------------------------------------------------+ |
| // |
| // $Id$ |
| require_once 'PEAR.php'; |
| /** |
| * DB_common is a base class for DB implementations, and must be |
| * inherited by all such |
| * |
| * @package DB |
| * @version $Id$ |
| * @category Database |
| * @author Stig Bakken <ssb@php.net> |
| * @author Tomas V.V.Cox <cox@idecnet.com> |
| */ |
| class DB_common extends PEAR |
| { |
| // {{{ properties |
| /** |
| * assoc of capabilities for this DB implementation |
| * $features['limit'] => 'emulate' => emulate with fetch row by number |
| * 'alter' => alter the query |
| * false => skip rows |
| * @var array |
| */ |
| var $features = array(); |
| /** |
| * assoc mapping native error codes to DB ones |
| * @var array |
| */ |
| var $errorcode_map = array(); |
| /** |
| * DB type (mysql, oci8, odbc etc.) |
| * @var string |
| */ |
| var $phptype; |
| /** |
| * @var string |
| */ |
| var $prepare_tokens; |
| /** |
| * @var string |
| */ |
| var $prepare_types; |
| /** |
| * @var string |
| */ |
| var $prepared_queries; |
| /** |
| * @var integer |
| */ |
| var $prepare_maxstmt = 0; |
| /** |
| * @var string |
| */ |
| var $last_query = ''; |
| /** |
| * @var integer |
| */ |
| var $fetchmode = DB_FETCHMODE_ORDERED; |
| /** |
| * @var string |
| */ |
| var $fetchmode_object_class = 'stdClass'; |
| /** |
| * Run-time configuration options. |
| * |
| * The 'optimize' option has been deprecated. Use the 'portability' |
| * option instead. |
| * |
| * @see DB_common::setOption() |
| * @var array |
| */ |
| var $options = array( |
| 'persistent' => false, |
| 'ssl' => false, |
| 'debug' => 0, |
| 'seqname_format' => '%s_seq', |
| 'autofree' => false, |
| 'portability' => DB_PORTABILITY_NONE, |
| 'optimize' => 'performance', // Deprecated. Use 'portability'. |
| ); |
| /** |
| * DB handle |
| * @var resource |
| */ |
| var $dbh; |
| // }}} |
| // {{{ toString() |
| /** |
| * String conversation |
| * |
| * @return string |
| * @access private |
| */ |
| function toString() |
| { |
| $info = strtolower(get_class($this)); |
| $info .= ': (phptype=' . $this->phptype . |
| ', dbsyntax=' . $this->dbsyntax . |
| ')'; |
| if ($this->connection) { |
| $info .= ' [connected]'; |
| } |
| return $info; |
| } |
| // }}} |
| // {{{ constructor |
| /** |
| * Constructor |
| */ |
| function DB_common() |
| { |
| $this->PEAR('DB_Error'); |
| } |
| // }}} |
| // {{{ quoteString() |
| /** |
| * DEPRECATED: Quotes a string so it can be safely used within string |
| * delimiters in a query |
| * |
| * @return string quoted string |
| * |
| * @see DB_common::quoteSmart(), DB_common::escapeSimple() |
| * @deprecated Deprecated in release 1.2 or lower |
| * @internal |
| */ |
| function quoteString($string) |
| { |
| $string = $this->quote($string); |
| if ($string{0} == "'") { |
| return substr($string, 1, -1); |
| } |
| return $string; |
| } |
| // }}} |
| // {{{ quote() |
| /** |
| * DEPRECATED: Quotes a string so it can be safely used in a query |
| * |
| * @param string $string the input string to quote |
| * |
| * @return string The NULL string or the string quotes |
| * in magic_quote_sybase style |
| * |
| * @see DB_common::quoteSmart(), DB_common::escapeSimple() |
| * @deprecated Deprecated in release 1.6.0 |
| * @internal |
| */ |
| function quote($string = null) |
| { |
| return ($string === null) ? 'NULL' : "'".str_replace("'", "''", $string)."'"; |
| } |
| // }}} |
| // {{{ quoteIdentifier() |
| /** |
| * Quote a string so it can be safely used as a table or column name |
| * |
| * Delimiting style depends on which database driver is being used. |
| * |
| * NOTE: just because you CAN use delimited identifiers doesn't mean |
| * you SHOULD use them. In general, they end up causing way more |
| * problems than they solve. |
| * |
| * Portability is broken by using the following characters inside |
| * delimited identifiers: |
| * + backtick (<kbd>`</kbd>) -- due to MySQL |
| * + double quote (<kbd>"</kbd>) -- due to Oracle |
| * + brackets (<kbd>[</kbd> or <kbd>]</kbd>) -- due to Access |
| * |
| * Delimited identifiers are known to generally work correctly under |
| * the following drivers: |
| * + mssql |
| * + mysql |
| * + mysqli |
| * + oci8 |
| * + odbc(access) |
| * + odbc(db2) |
| * + pgsql |
| * + sqlite |
| * + sybase |
| * |
| * InterBase doesn't seem to be able to use delimited identifiers |
| * via PHP 4. They work fine under PHP 5. |
| * |
| * @param string $str identifier name to be quoted |
| * |
| * @return string quoted identifier string |
| * |
| * @since 1.6.0 |
| * @access public |
| */ |
| function quoteIdentifier($str) |
| { |
| return '"' . str_replace('"', '""', $str) . '"'; |
| } |
| // }}} |
| // {{{ quoteSmart() |
| /** |
| * Format input so it can be safely used in a query |
| * |
| * The output depends on the PHP data type of input and the database |
| * type being used. |
| * |
| * @param mixed $in data to be quoted |
| * |
| * @return mixed the format of the results depends on the input's |
| * PHP type: |
| * |
| * <ul> |
| * <li> |
| * <kbd>input</kbd> -> <samp>returns</samp> |
| * </li> |
| * <li> |
| * <kbd>null</kbd> -> the string <samp>NULL</samp> |
| * </li> |
| * <li> |
| * <kbd>integer</kbd> or <kbd>double</kbd> -> the unquoted number |
| * </li> |
| * <li> |
| * &type.bool; -> output depends on the driver in use |
| * Most drivers return integers: <samp>1</samp> if |
| * <kbd>true</kbd> or <samp>0</samp> if |
| * <kbd>false</kbd>. |
| * Some return strings: <samp>TRUE</samp> if |
| * <kbd>true</kbd> or <samp>FALSE</samp> if |
| * <kbd>false</kbd>. |
| * Finally one returns strings: <samp>T</samp> if |
| * <kbd>true</kbd> or <samp>F</samp> if |
| * <kbd>false</kbd>. Here is a list of each DBMS, |
| * the values returned and the suggested column type: |
| * <ul> |
| * <li> |
| * <kbd>dbase</kbd> -> <samp>T/F</samp> |
| * (<kbd>Logical</kbd>) |
| * </li> |
| * <li> |
| * <kbd>fbase</kbd> -> <samp>TRUE/FALSE</samp> |
| * (<kbd>BOOLEAN</kbd>) |
| * </li> |
| * <li> |
| * <kbd>ibase</kbd> -> <samp>1/0</samp> |
| * (<kbd>SMALLINT</kbd>) [1] |
| * </li> |
| * <li> |
| * <kbd>ifx</kbd> -> <samp>1/0</samp> |
| * (<kbd>SMALLINT</kbd>) [1] |
| * </li> |
| * <li> |
| * <kbd>msql</kbd> -> <samp>1/0</samp> |
| * (<kbd>INTEGER</kbd>) |
| * </li> |
| * <li> |
| * <kbd>mssql</kbd> -> <samp>1/0</samp> |
| * (<kbd>BIT</kbd>) |
| * </li> |
| * <li> |
| * <kbd>mysql</kbd> -> <samp>1/0</samp> |
| * (<kbd>TINYINT(1)</kbd>) |
| * </li> |
| * <li> |
| * <kbd>mysqli</kbd> -> <samp>1/0</samp> |
| * (<kbd>TINYINT(1)</kbd>) |
| * </li> |
| * <li> |
| * <kbd>oci8</kbd> -> <samp>1/0</samp> |
| * (<kbd>NUMBER(1)</kbd>) |
| * </li> |
| * <li> |
| * <kbd>odbc</kbd> -> <samp>1/0</samp> |
| * (<kbd>SMALLINT</kbd>) [1] |
| * </li> |
| * <li> |
| * <kbd>pgsql</kbd> -> <samp>TRUE/FALSE</samp> |
| * (<kbd>BOOLEAN</kbd>) |
| * </li> |
| * <li> |
| * <kbd>sqlite</kbd> -> <samp>1/0</samp> |
| * (<kbd>INTEGER</kbd>) |
| * </li> |
| * <li> |
| * <kbd>sybase</kbd> -> <samp>1/0</samp> |
| * (<kbd>TINYINT(1)</kbd>) |
| * </li> |
| * </ul> |
| * [1] Accommodate the lowest common denominator because not all |
| * versions of have <kbd>BOOLEAN</kbd>. |
| * </li> |
| * <li> |
| * other (including strings and numeric strings) -> |
| * the data with single quotes escaped by preceeding |
| * single quotes, backslashes are escaped by preceeding |
| * backslashes, then the whole string is encapsulated |
| * between single quotes |
| * </li> |
| * </ul> |
| * |
| * @since 1.6.0 |
| * @see DB_common::escapeSimple() |
| * @access public |
| */ |
| function quoteSmart($in) |
| { |
| if (is_int($in) || is_double($in)) { |
| return $in; |
| } elseif (is_bool($in)) { |
| return $in ? 1 : 0; |
| } elseif (is_null($in)) { |
| return 'NULL'; |
| } else { |
| return "'" . $this->escapeSimple($in) . "'"; |
| } |
| } |
| // }}} |
| // {{{ escapeSimple() |
| /** |
| * Escape a string according to the current DBMS's standards |
| * |
| * In SQLite, this makes things safe for inserts/updates, but may |
| * cause problems when performing text comparisons against columns |
| * containing binary data. See the |
| * {@link http://php.net/sqlite_escape_string PHP manual} for more info. |
| * |
| * @param string $str the string to be escaped |
| * |
| * @return string the escaped string |
| * |
| * @since 1.6.0 |
| * @see DB_common::quoteSmart() |
| * @access public |
| */ |
| function escapeSimple($str) { |
| return str_replace("'", "''", $str); |
| } |
| // }}} |
| // {{{ provides() |
| /** |
| * Tell whether a DB implementation or its backend extension |
| * supports a given feature |
| * |
| * @param array $feature name of the feature (see the DB class doc) |
| * @return bool whether this DB implementation supports $feature |
| * @access public |
| */ |
| function provides($feature) |
| { |
| return $this->features[$feature]; |
| } |
| // }}} |
| // {{{ errorCode() |
| /** |
| * Map native error codes to DB's portable ones |
| * |
| * Requires that the DB implementation's constructor fills |
| * in the <var>$errorcode_map</var> property. |
| * |
| * @param mixed $nativecode the native error code, as returned by the |
| * backend database extension (string or integer) |
| * |
| * @return int a portable DB error code, or DB_ERROR if this DB |
| * implementation has no mapping for the given error code. |
| * |
| * @access public |
| */ |
| function errorCode($nativecode) |
| { |
| if (isset($this->errorcode_map[$nativecode])) { |
| return $this->errorcode_map[$nativecode]; |
| } |
| // Fall back to DB_ERROR if there was no mapping. |
| return DB_ERROR; |
| } |
| // }}} |
| // {{{ errorMessage() |
| /** |
| * Map a DB error code to a textual message. This is actually |
| * just a wrapper for DB::errorMessage() |
| * |
| * @param integer $dbcode the DB error code |
| * |
| * @return string the corresponding error message, of false |
| * if the error code was unknown |
| * |
| * @access public |
| */ |
| function errorMessage($dbcode) |
| { |
| return DB::errorMessage($this->errorcode_map[$dbcode]); |
| } |
| // }}} |
| // {{{ raiseError() |
| /** |
| * Communicate an error and invoke error callbacks, etc |
| * |
| * Basically a wrapper for PEAR::raiseError without the message string. |
| * |
| * @param mixed integer error code, or a PEAR error object (all |
| * other parameters are ignored if this parameter is |
| * an object |
| * |
| * @param int error mode, see PEAR_Error docs |
| * |
| * @param mixed If error mode is PEAR_ERROR_TRIGGER, this is the |
| * error level (E_USER_NOTICE etc). If error mode is |
| * PEAR_ERROR_CALLBACK, this is the callback function, |
| * either as a function name, or as an array of an |
| * object and method name. For other error modes this |
| * parameter is ignored. |
| * |
| * @param string Extra debug information. Defaults to the last |
| * query and native error code. |
| * |
| * @param mixed Native error code, integer or string depending the |
| * backend. |
| * |
| * @return object a PEAR error object |
| * |
| * @access public |
| * @see PEAR_Error |
| */ |
| function &raiseError($code = DB_ERROR, $mode = null, $options = null, |
| $userinfo = null, $nativecode = null) |
| { |
| // The error is yet a DB error object |
| if (is_object($code)) { |
| // because we the static PEAR::raiseError, our global |
| // handler should be used if it is set |
| if ($mode === null && !empty($this->_default_error_mode)) { |
| $mode = $this->_default_error_mode; |
| $options = $this->_default_error_options; |
| } |
| $tmp = PEAR::raiseError($code, null, $mode, $options, null, null, true); |
| return $tmp; |
| } |
| if ($userinfo === null) { |
| $userinfo = $this->last_query; |
| } |
| if ($nativecode) { |
| $userinfo .= ' [nativecode=' . trim($nativecode) . ']'; |
| } |
| $tmp = PEAR::raiseError(null, $code, $mode, $options, $userinfo, |
| 'DB_Error', true); |
| return $tmp; |
| } |
| // }}} |
| // {{{ setFetchMode() |
| /** |
| * Sets which fetch mode should be used by default on queries |
| * on this connection |
| * |
| * @param integer $fetchmode DB_FETCHMODE_ORDERED or |
| * DB_FETCHMODE_ASSOC, possibly bit-wise OR'ed with |
| * DB_FETCHMODE_FLIPPED. |
| * |
| * @param string $object_class The class of the object |
| * to be returned by the fetch methods when |
| * the DB_FETCHMODE_OBJECT mode is selected. |
| * If no class is specified by default a cast |
| * to object from the assoc array row will be done. |
| * There is also the posibility to use and extend the |
| * 'DB_row' class. |
| * |
| * @see DB_FETCHMODE_ORDERED |
| * @see DB_FETCHMODE_ASSOC |
| * @see DB_FETCHMODE_FLIPPED |
| * @see DB_FETCHMODE_OBJECT |
| * @see DB_row::DB_row() |
| * @access public |
| */ |
| function setFetchMode($fetchmode, $object_class = 'stdClass') |
| { |
| switch ($fetchmode) { |
| case DB_FETCHMODE_OBJECT: |
| $this->fetchmode_object_class = $object_class; |
| case DB_FETCHMODE_ORDERED: |
| case DB_FETCHMODE_ASSOC: |
| $this->fetchmode = $fetchmode; |
| break; |
| default: |
| return $this->raiseError('invalid fetchmode mode'); |
| } |
| } |
| // }}} |
| // {{{ setOption() |
| /** |
| * Set run-time configuration options for PEAR DB |
| * |
| * Options, their data types, default values and description: |
| * <ul> |
| * <li> |
| * <var>autofree</var> <kbd>boolean</kbd> = <samp>false</samp> |
| * <br />should results be freed automatically when there are no |
| * more rows? |
| * </li><li> |
| * <var>debug</var> <kbd>integer</kbd> = <samp>0</samp> |
| * <br />debug level |
| * </li><li> |
| * <var>persistent</var> <kbd>boolean</kbd> = <samp>false</samp> |
| * <br />should the connection be persistent? |
| * </li><li> |
| * <var>portability</var> <kbd>integer</kbd> = <samp>DB_PORTABILITY_NONE</samp> |
| * <br />portability mode constant (see below) |
| * </li><li> |
| * <var>seqname_format</var> <kbd>string</kbd> = <samp>%s_seq</samp> |
| * <br />the sprintf() format string used on sequence names. This |
| * format is applied to sequence names passed to |
| * createSequence(), nextID() and dropSequence(). |
| * </li><li> |
| * <var>ssl</var> <kbd>boolean</kbd> = <samp>false</samp> |
| * <br />use ssl to connect? |
| * </li> |
| * </ul> |
| * |
| * ----------------------------------------- |
| * |
| * PORTABILITY MODES |
| * |
| * These modes are bitwised, so they can be combined using <kbd>|</kbd> |
| * and removed using <kbd>^</kbd>. See the examples section below on how |
| * to do this. |
| * |
| * <samp>DB_PORTABILITY_NONE</samp> |
| * turn off all portability features |
| * |
| * This mode gets automatically turned on if the deprecated |
| * <var>optimize</var> option gets set to <samp>performance</samp>. |
| * |
| * |
| * <samp>DB_PORTABILITY_LOWERCASE</samp> |
| * convert names of tables and fields to lower case when using |
| * <kbd>get*()</kbd>, <kbd>fetch*()</kbd> and <kbd>tableInfo()</kbd> |
| * |
| * This mode gets automatically turned on in the following databases |
| * if the deprecated option <var>optimize</var> gets set to |
| * <samp>portability</samp>: |
| * + oci8 |
| * |
| * |
| * <samp>DB_PORTABILITY_RTRIM</samp> |
| * right trim the data output by <kbd>get*()</kbd> <kbd>fetch*()</kbd> |
| * |
| * |
| * <samp>DB_PORTABILITY_DELETE_COUNT</samp> |
| * force reporting the number of rows deleted |
| * |
| * Some DBMS's don't count the number of rows deleted when performing |
| * simple <kbd>DELETE FROM tablename</kbd> queries. This portability |
| * mode tricks such DBMS's into telling the count by adding |
| * <samp>WHERE 1=1</samp> to the end of <kbd>DELETE</kbd> queries. |
| * |
| * This mode gets automatically turned on in the following databases |
| * if the deprecated option <var>optimize</var> gets set to |
| * <samp>portability</samp>: |
| * + fbsql |
| * + mysql |
| * + mysqli |
| * + sqlite |
| * |
| * |
| * <samp>DB_PORTABILITY_NUMROWS</samp> |
| * enable hack that makes <kbd>numRows()</kbd> work in Oracle |
| * |
| * This mode gets automatically turned on in the following databases |
| * if the deprecated option <var>optimize</var> gets set to |
| * <samp>portability</samp>: |
| * + oci8 |
| * |
| * |
| * <samp>DB_PORTABILITY_ERRORS</samp> |
| * makes certain error messages in certain drivers compatible |
| * with those from other DBMS's |
| * |
| * + mysql, mysqli: change unique/primary key constraints |
| * DB_ERROR_ALREADY_EXISTS -> DB_ERROR_CONSTRAINT |
| * |
| * + odbc(access): MS's ODBC driver reports 'no such field' as code |
| * 07001, which means 'too few parameters.' When this option is on |
| * that code gets mapped to DB_ERROR_NOSUCHFIELD. |
| * DB_ERROR_MISMATCH -> DB_ERROR_NOSUCHFIELD |
| * |
| * |
| * <samp>DB_PORTABILITY_NULL_TO_EMPTY</samp> |
| * convert null values to empty strings in data output by get*() and |
| * fetch*(). Needed because Oracle considers empty strings to be null, |
| * while most other DBMS's know the difference between empty and null. |
| * |
| * |
| * <samp>DB_PORTABILITY_ALL</samp> |
| * turn on all portability features |
| * |
| * ----------------------------------------- |
| * |
| * Example 1. Simple setOption() example |
| * <code> <?php |
| * $dbh->setOption('autofree', true); |
| * ?></code> |
| * |
| * Example 2. Portability for lowercasing and trimming |
| * <code> <?php |
| * $dbh->setOption('portability', |
| * DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_RTRIM); |
| * ?></code> |
| * |
| * Example 3. All portability options except trimming |
| * <code> <?php |
| * $dbh->setOption('portability', |
| * DB_PORTABILITY_ALL ^ DB_PORTABILITY_RTRIM); |
| * ?></code> |
| * |
| * @param string $option option name |
| * @param mixed $value value for the option |
| * |
| * @return int DB_OK on success. DB_Error object on failure. |
| * |
| * @see DB_common::$options |
| */ |
| function setOption($option, $value) |
| { |
| if (isset($this->options[$option])) { |
| $this->options[$option] = $value; |
| /* |
| * Backwards compatibility check for the deprecated 'optimize' |
| * option. Done here in case settings change after connecting. |
| */ |
| if ($option == 'optimize') { |
| if ($value == 'portability') { |
| switch ($this->phptype) { |
| case 'oci8': |
| $this->options['portability'] = |
| DB_PORTABILITY_LOWERCASE | |
| DB_PORTABILITY_NUMROWS; |
| break; |
| case 'fbsql': |
| case 'mysql': |
| case 'mysqli': |
| case 'sqlite': |
| $this->options['portability'] = |
| DB_PORTABILITY_DELETE_COUNT; |
| break; |
| } |
| } else { |
| $this->options['portability'] = DB_PORTABILITY_NONE; |
| } |
| } |
| return DB_OK; |
| } |
| return $this->raiseError("unknown option $option"); |
| } |
| // }}} |
| // {{{ getOption() |
| /** |
| * Returns the value of an option |
| * |
| * @param string $option option name |
| * |
| * @return mixed the option value |
| */ |
| function getOption($option) |
| { |
| if (isset($this->options[$option])) { |
| return $this->options[$option]; |
| } |
| return $this->raiseError("unknown option $option"); |
| } |
| // }}} |
| // {{{ prepare() |
| /** |
| * Prepares a query for multiple execution with execute() |
| * |
| * Creates a query that can be run multiple times. Each time it is run, |
| * the placeholders, if any, will be replaced by the contents of |
| * execute()'s $data argument. |
| * |
| * Three types of placeholders can be used: |
| * + <kbd>?</kbd> scalar value (i.e. strings, integers). The system |
| * will automatically quote and escape the data. |
| * + <kbd>!</kbd> value is inserted 'as is' |
| * + <kbd>&</kbd> requires a file name. The file's contents get |
| * inserted into the query (i.e. saving binary |
| * data in a db) |
| * |
| * Example 1. |
| * <code> <?php |
| * $sth = $dbh->prepare('INSERT INTO tbl (a, b, c) VALUES (?, !, &)'); |
| * $data = array( |
| * "John's text", |
| * "'it''s good'", |
| * 'filename.txt' |
| * ); |
| * $res = $dbh->execute($sth, $data); |
| * ?></code> |
| * |
| * Use backslashes to escape placeholder characters if you don't want |
| * them to be interpreted as placeholders: |
| * <pre> |
| * "UPDATE foo SET col=? WHERE col='over \& under'" |
| * </pre> |
| * |
| * With some database backends, this is emulated. |
| * |
| * {@internal ibase and oci8 have their own prepare() methods.}} |
| * |
| * @param string $query query to be prepared |
| * |
| * @return mixed DB statement resource on success. DB_Error on failure. |
| * |
| * @see DB_common::execute() |
| * @access public |
| */ |
| function prepare($query) |
| { |
| $tokens = preg_split('/((?<!\\\)[&?!])/', $query, -1, |
| PREG_SPLIT_DELIM_CAPTURE); |
| $token = 0; |
| $types = array(); |
| $newtokens = array(); |
| foreach ($tokens as $val) { |
| switch ($val) { |
| case '?': |
| $types[$token++] = DB_PARAM_SCALAR; |
| break; |
| case '&': |
| $types[$token++] = DB_PARAM_OPAQUE; |
| break; |
| case '!': |
| $types[$token++] = DB_PARAM_MISC; |
| break; |
| default: |
| $newtokens[] = preg_replace('/\\\([&?!])/', "\\1", $val); |
| } |
| } |
| $this->prepare_tokens[] = &$newtokens; |
| end($this->prepare_tokens); |
| $k = key($this->prepare_tokens); |
| $this->prepare_types[$k] = $types; |
| $this->prepared_queries[$k] = implode(' ', $newtokens); |
| return $k; |
| } |
| // }}} |
| // {{{ autoPrepare() |
| /** |
| * Automaticaly generate an insert or update query and pass it to prepare() |
| * |
| * @param string $table name of the table |
| * @param array $table_fields ordered array containing the fields names |
| * @param int $mode type of query to make (DB_AUTOQUERY_INSERT or DB_AUTOQUERY_UPDATE) |
| * @param string $where in case of update queries, this string will be put after the sql WHERE statement |
| * @return resource handle for the query |
| * @see DB_common::prepare(), DB_common::buildManipSQL() |
| * @access public |
| */ |
| function autoPrepare($table, $table_fields, $mode = DB_AUTOQUERY_INSERT, $where = false) |
| { |
| $query = $this->buildManipSQL($table, $table_fields, $mode, $where); |
| return $this->prepare($query); |
| } |
| // }}} |
| // {{{ autoExecute() |
| /** |
| * Automaticaly generate an insert or update query and call prepare() |
| * and execute() with it |
| * |
| * @param string $table name of the table |
| * @param array $fields_values assoc ($key=>$value) where $key is a field name and $value its value |
| * @param int $mode type of query to make (DB_AUTOQUERY_INSERT or DB_AUTOQUERY_UPDATE) |
| * @param string $where in case of update queries, this string will be put after the sql WHERE statement |
| * @return mixed a new DB_Result or a DB_Error when fail |
| * @see DB_common::autoPrepare(), DB_common::buildManipSQL() |
| * @access public |
| */ |
| function autoExecute($table, $fields_values, $mode = DB_AUTOQUERY_INSERT, $where = false) |
| { |
| $sth = $this->autoPrepare($table, array_keys($fields_values), $mode, $where); |
| $ret =& $this->execute($sth, array_values($fields_values)); |
| $this->freePrepared($sth); |
| return $ret; |
| } |
| // }}} |
| // {{{ buildManipSQL() |
| /** |
| * Make automaticaly an sql query for prepare() |
| * |
| * Example : buildManipSQL('table_sql', array('field1', 'field2', 'field3'), DB_AUTOQUERY_INSERT) |
| * will return the string : INSERT INTO table_sql (field1,field2,field3) VALUES (?,?,?) |
| * NB : - This belongs more to a SQL Builder class, but this is a simple facility |
| * - Be carefull ! If you don't give a $where param with an UPDATE query, all |
| * the records of the table will be updated ! |
| * |
| * @param string $table name of the table |
| * @param array $table_fields ordered array containing the fields names |
| * @param int $mode type of query to make (DB_AUTOQUERY_INSERT or DB_AUTOQUERY_UPDATE) |
| * @param string $where in case of update queries, this string will be put after the sql WHERE statement |
| * @return string sql query for prepare() |
| * @access public |
| */ |
| function buildManipSQL($table, $table_fields, $mode, $where = false) |
| { |
| if (count($table_fields) == 0) { |
| $this->raiseError(DB_ERROR_NEED_MORE_DATA); |
| } |
| $first = true; |
| switch ($mode) { |
| case DB_AUTOQUERY_INSERT: |
| $values = ''; |
| $names = ''; |
| foreach ($table_fields as $value) { |
| if ($first) { |
| $first = false; |
| } else { |
| $names .= ','; |
| $values .= ','; |
| } |
| $names .= $value; |
| $values .= '?'; |
| } |
| return "INSERT INTO $table ($names) VALUES ($values)"; |
| case DB_AUTOQUERY_UPDATE: |
| $set = ''; |
| foreach ($table_fields as $value) { |
| if ($first) { |
| $first = false; |
| } else { |
| $set .= ','; |
| } |
| $set .= "$value = ?"; |
| } |
| $sql = "UPDATE $table SET $set"; |
| if ($where) { |
| $sql .= " WHERE $where"; |
| } |
| return $sql; |
| default: |
| $this->raiseError(DB_ERROR_SYNTAX); |
| } |
| } |
| // }}} |
| // {{{ execute() |
| /** |
| * Executes a DB statement prepared with prepare() |
| * |
| * Example 1. |
| * <code> <?php |
| * $sth = $dbh->prepare('INSERT INTO tbl (a, b, c) VALUES (?, !, &)'); |
| * $data = array( |
| * "John's text", |
| * "'it''s good'", |
| * 'filename.txt' |
| * ); |
| * $res =& $dbh->execute($sth, $data); |
| * ?></code> |
| * |
| * @param resource $stmt a DB statement resource returned from prepare() |
| * @param mixed $data array, string or numeric data to be used in |
| * execution of the statement. Quantity of items |
| * passed must match quantity of placeholders in |
| * query: meaning 1 placeholder for non-array |
| * parameters or 1 placeholder per array element. |
| * |
| * @return object a new DB_Result or a DB_Error when fail |
| * |
| * {@internal ibase and oci8 have their own execute() methods.}} |
| * |
| * @see DB_common::prepare() |
| * @access public |
| */ |
| function &execute($stmt, $data = array()) |
| { |
| $realquery = $this->executeEmulateQuery($stmt, $data); |
| if (DB::isError($realquery)) { |
| return $realquery; |
| } |
| $result = $this->simpleQuery($realquery); |
| if (DB::isError($result) || $result === DB_OK) { |
| return $result; |
| } else { |
| $tmp =& new DB_result($this, $result); |
| return $tmp; |
| } |
| } |
| // }}} |
| // {{{ executeEmulateQuery() |
| /** |
| * Emulates the execute statement, when not supported |
| * |
| * @param resource $stmt a DB statement resource returned from execute() |
| * @param mixed $data array, string or numeric data to be used in |
| * execution of the statement. Quantity of items |
| * passed must match quantity of placeholders in |
| * query: meaning 1 placeholder for non-array |
| * parameters or 1 placeholder per array element. |
| * |
| * @return mixed a string containing the real query run when emulating |
| * prepare/execute. A DB error code is returned on failure. |
| * |
| * @see DB_common::execute() |
| * @access private |
| */ |
| function executeEmulateQuery($stmt, $data = array()) |
| { |
| if (!is_array($data)) { |
| $data = array($data); |
| } |
| if (count($this->prepare_types[$stmt]) != count($data)) { |
| $this->last_query = $this->prepared_queries[$stmt]; |
| return $this->raiseError(DB_ERROR_MISMATCH); |
| } |
| $realquery = $this->prepare_tokens[$stmt][0]; |
| $i = 0; |
| foreach ($data as $value) { |
| if ($this->prepare_types[$stmt][$i] == DB_PARAM_SCALAR) { |
| $realquery .= $this->quoteSmart($value); |
| } elseif ($this->prepare_types[$stmt][$i] == DB_PARAM_OPAQUE) { |
| $fp = @fopen($value, 'rb'); |
| if (!$fp) { |
| return $this->raiseError(DB_ERROR_ACCESS_VIOLATION); |
| } |
| $realquery .= $this->quoteSmart(fread($fp, filesize($value))); |
| fclose($fp); |
| } else { |
| $realquery .= $value; |
| } |
| $realquery .= $this->prepare_tokens[$stmt][++$i]; |
| } |
| return $realquery; |
| } |
| // }}} |
| // {{{ executeMultiple() |
| /** |
| * This function does several execute() calls on the same |
| * statement handle |
| * |
| * $data must be an array indexed numerically |
| * from 0, one execute call is done for every "row" in the array. |
| * |
| * If an error occurs during execute(), executeMultiple() does not |
| * execute the unfinished rows, but rather returns that error. |
| * |
| * @param resource $stmt query handle from prepare() |
| * @param array $data numeric array containing the |
| * data to insert into the query |
| * |
| * @return mixed DB_OK or DB_Error |
| * |
| * @see DB_common::prepare(), DB_common::execute() |
| * @access public |
| */ |
| function executeMultiple($stmt, $data) |
| { |
| foreach ($data as $value) { |
| $res =& $this->execute($stmt, $value); |
| if (DB::isError($res)) { |
| return $res; |
| } |
| } |
| return DB_OK; |
| } |
| // }}} |
| // {{{ freePrepared() |
| /** |
| * Free the resource used in a prepared query |
| * |
| * @param $stmt The resurce returned by the prepare() function |
| * @see DB_common::prepare() |
| */ |
| function freePrepared($stmt) |
| { |
| // Free the internal prepared vars |
| if (isset($this->prepare_tokens[$stmt])) { |
| unset($this->prepare_tokens[$stmt]); |
| unset($this->prepare_types[$stmt]); |
| unset($this->prepared_queries[$stmt]); |
| return true; |
| } |
| return false; |
| } |
| // }}} |
| // {{{ modifyQuery() |
| /** |
| * This method is used by backends to alter queries for various |
| * reasons |
| * |
| * It is defined here to assure that all implementations |
| * have this method defined. |
| * |
| * @param string $query query to modify |
| * |
| * @return the new (modified) query |
| * |
| * @access private |
| */ |
| function modifyQuery($query) { |
| return $query; |
| } |
| // }}} |
| // {{{ modifyLimitQuery() |
| /** |
| * This method is used by backends to alter limited queries |
| * |
| * @param string $query query to modify |
| * @param integer $from the row to start to fetching |
| * @param integer $count the numbers of rows to fetch |
| * |
| * @return the new (modified) query |
| * |
| * @access private |
| */ |
| function modifyLimitQuery($query, $from, $count, $params = array()) |
| { |
| return $query; |
| } |
| // }}} |
| // {{{ query() |
| /** |
| * Send a query to the database and return any results with a |
| * DB_result object |
| * |
| * The query string can be either a normal statement to be sent directly |
| * to the server OR if <var>$params</var> are passed the query can have |
| * placeholders and it will be passed through prepare() and execute(). |
| * |
| * @param string $query the SQL query or the statement to prepare |
| * @param mixed $params array, string or numeric data to be used in |
| * execution of the statement. Quantity of items |
| * passed must match quantity of placeholders in |
| * query: meaning 1 placeholder for non-array |
| * parameters or 1 placeholder per array element. |
| * |
| * @return mixed a DB_result object or DB_OK on success, a DB |
| * error on failure |
| * |
| * @see DB_result, DB_common::prepare(), DB_common::execute() |
| * @access public |
| */ |
| function &query($query, $params = array()) |
| { |
| if (sizeof($params) > 0) { |
| $sth = $this->prepare($query); |
| if (DB::isError($sth)) { |
| return $sth; |
| } |
| $ret =& $this->execute($sth, $params); |
| $this->freePrepared($sth); |
| return $ret; |
| } else { |
| $result = $this->simpleQuery($query); |
| if (DB::isError($result) || $result === DB_OK) { |
| return $result; |
| } else { |
| $tmp =& new DB_result($this, $result); |
| return $tmp; |
| } |
| } |
| } |
| // }}} |
| // {{{ limitQuery() |
| /** |
| * Generates a limited query |
| * |
| * @param string $query query |
| * @param integer $from the row to start to fetching |
| * @param integer $count the numbers of rows to fetch |
| * @param mixed $params array, string or numeric data to be used in |
| * execution of the statement. Quantity of items |
| * passed must match quantity of placeholders in |
| * query: meaning 1 placeholder for non-array |
| * parameters or 1 placeholder per array element. |
| * |
| * @return mixed a DB_Result object, DB_OK or a DB_Error |
| * |
| * @access public |
| */ |
| function &limitQuery($query, $from, $count, $params = array()) |
| { |
| $query = $this->modifyLimitQuery($query, $from, $count, $params); |
| if (DB::isError($query)){ |
| return $query; |
| } |
| $result =& $this->query($query, $params); |
| if (is_a($result, 'DB_result')) { |
| $result->setOption('limit_from', $from); |
| $result->setOption('limit_count', $count); |
| } |
| return $result; |
| } |
| // }}} |
| // {{{ getOne() |
| /** |
| * Fetch the first column of the first row of data returned from |
| * a query |
| * |
| * Takes care of doing the query and freeing the results when finished. |
| * |
| * @param string $query the SQL query |
| * @param mixed $params array, string or numeric data to be used in |
| * execution of the statement. Quantity of items |
| * passed must match quantity of placeholders in |
| * query: meaning 1 placeholder for non-array |
| * parameters or 1 placeholder per array element. |
| * |
| * @return mixed the returned value of the query. DB_Error on failure. |
| * |
| * @access public |
| */ |
| function &getOne($query, $params = array()) |
| { |
| settype($params, 'array'); |
| if (sizeof($params) > 0) { |
| $sth = $this->prepare($query); |
| if (DB::isError($sth)) { |
| return $sth; |
| } |
| $res =& $this->execute($sth, $params); |
| $this->freePrepared($sth); |
| } else { |
| $res =& $this->query($query); |
| } |
| if (DB::isError($res)) { |
| return $res; |
| } |
| $err = $res->fetchInto($row, DB_FETCHMODE_ORDERED); |
| $res->free(); |
| if ($err !== DB_OK) { |
| return $err; |
| } |
| return $row[0]; |
| } |
| // }}} |
| // {{{ getRow() |
| /** |
| * Fetch the first row of data returned from a query |
| * |
| * Takes care of doing the query and freeing the results when finished. |
| * |
| * @param string $query the SQL query |
| * @param array $params array to be used in execution of the statement. |
| * Quantity of array elements must match quantity |
| * of placeholders in query. This function does |
| * NOT support scalars. |
| * @param int $fetchmode the fetch mode to use |
| * |
| * @return array the first row of results as an array indexed from |
| * 0, or a DB error code. |
| * |
| * @access public |
| */ |
| function &getRow($query, |
| $params = array(), |
| $fetchmode = DB_FETCHMODE_DEFAULT) |
| { |
| // compat check, the params and fetchmode parameters used to |
| // have the opposite order |
| if (!is_array($params)) { |
| if (is_array($fetchmode)) { |
| if ($params === null) { |
| $tmp = DB_FETCHMODE_DEFAULT; |
| } else { |
| $tmp = $params; |
| } |
| $params = $fetchmode; |
| $fetchmode = $tmp; |
| } elseif ($params !== null) { |
| $fetchmode = $params; |
| $params = array(); |
| } |
| } |
| if (sizeof($params) > 0) { |
| $sth = $this->prepare($query); |
| if (DB::isError($sth)) { |
| return $sth; |
| } |
| $res =& $this->execute($sth, $params); |
| $this->freePrepared($sth); |
| } else { |
| $res =& $this->query($query); |
| } |
| if (DB::isError($res)) { |
| return $res; |
| } |
| $err = $res->fetchInto($row, $fetchmode); |
| $res->free(); |
| if ($err !== DB_OK) { |
| return $err; |
| } |
| return $row; |
| } |
| // }}} |
| // {{{ getCol() |
| /** |
| * Fetch a single column from a result set and return it as an |
| * indexed array |
| * |
| * @param string $query the SQL query |
| * @param mixed $col which column to return (integer [column number, |
| * starting at 0] or string [column name]) |
| * @param mixed $params array, string or numeric data to be used in |
| * execution of the statement. Quantity of items |
| * passed must match quantity of placeholders in |
| * query: meaning 1 placeholder for non-array |
| * parameters or 1 placeholder per array element. |
| * |
| * @return array an indexed array with the data from the first |
| * row at index 0, or a DB error code |
| * |
| * @see DB_common::query() |
| * @access public |
| */ |
| function &getCol($query, $col = 0, $params = array()) |
| { |
| settype($params, 'array'); |
| if (sizeof($params) > 0) { |
| $sth = $this->prepare($query); |
| if (DB::isError($sth)) { |
| return $sth; |
| } |
| $res =& $this->execute($sth, $params); |
| $this->freePrepared($sth); |
| } else { |
| $res =& $this->query($query); |
| } |
| if (DB::isError($res)) { |
| return $res; |
| } |
| $fetchmode = is_int($col) ? DB_FETCHMODE_ORDERED : DB_FETCHMODE_ASSOC; |
| if (!is_array($row = $res->fetchRow($fetchmode))) { |
| $ret = array(); |
| } else { |
| if (!array_key_exists($col, $row)) { |
| $ret =& $this->raiseError(DB_ERROR_NOSUCHFIELD); |
| } else { |
| $ret = array($row[$col]); |
| while (is_array($row = $res->fetchRow($fetchmode))) { |
| $ret[] = $row[$col]; |
| } |
| } |
| } |
| $res->free(); |
| if (DB::isError($row)) { |
| $ret = $row; |
| } |
| return $ret; |
| } |
| // }}} |
| // {{{ getAssoc() |
| /** |
| * Fetch the entire result set of a query and return it as an |
| * associative array using the first column as the key |
| * |
| * If the result set contains more than two columns, the value |
| * will be an array of the values from column 2-n. If the result |
| * set contains only two columns, the returned value will be a |
| * scalar with the value of the second column (unless forced to an |
| * array with the $force_array parameter). A DB error code is |
| * returned on errors. If the result set contains fewer than two |
| * columns, a DB_ERROR_TRUNCATED error is returned. |
| * |
| * For example, if the table "mytable" contains: |
| * |
| * <pre> |
| * ID TEXT DATE |
| * -------------------------------- |
| * 1 'one' 944679408 |
| * 2 'two' 944679408 |
| * 3 'three' 944679408 |
| * </pre> |
| * |
| * Then the call getAssoc('SELECT id,text FROM mytable') returns: |
| * <pre> |
| * array( |
| * '1' => 'one', |
| * '2' => 'two', |
| * '3' => 'three', |
| * ) |
| * </pre> |
| * |
| * ...while the call getAssoc('SELECT id,text,date FROM mytable') returns: |
| * <pre> |
| * array( |
| * '1' => array('one', '944679408'), |
| * '2' => array('two', '944679408'), |
| * '3' => array('three', '944679408') |
| * ) |
| * </pre> |
| * |
| * If the more than one row occurs with the same value in the |
| * first column, the last row overwrites all previous ones by |
| * default. Use the $group parameter if you don't want to |
| * overwrite like this. Example: |
| * |
| * <pre> |
| * getAssoc('SELECT category,id,name FROM mytable', false, null, |
| * DB_FETCHMODE_ASSOC, true) returns: |
| * |
| * array( |
| * '1' => array(array('id' => '4', 'name' => 'number four'), |
| * array('id' => '6', 'name' => 'number six') |
| * ), |
| * '9' => array(array('id' => '4', 'name' => 'number four'), |
| * array('id' => '6', 'name' => 'number six') |
| * ) |
| * ) |
| * </pre> |
| * |
| * Keep in mind that database functions in PHP usually return string |
| * values for results regardless of the database's internal type. |
| * |
| * @param string $query the SQL query |
| * @param boolean $force_array used only when the query returns |
| * exactly two columns. If true, the values |
| * of the returned array will be one-element |
| * arrays instead of scalars. |
| * @param mixed $params array, string or numeric data to be used in |
| * execution of the statement. Quantity of items |
| * passed must match quantity of placeholders in |
| * query: meaning 1 placeholder for non-array |
| * parameters or 1 placeholder per array element. |
| * @param int $fetchmode the fetch mode to use |
| * @param boolean $group if true, the values of the returned array |
| * is wrapped in another array. If the same |
| * key value (in the first column) repeats |
| * itself, the values will be appended to |
| * this array instead of overwriting the |
| * existing values. |
| * |
| * @return array associative array with results from the query. |
| * DB Error on failure. |
| * |
| * @access public |
| */ |
| function &getAssoc($query, $force_array = false, $params = array(), |
| $fetchmode = DB_FETCHMODE_DEFAULT, $group = false) |
| { |
| settype($params, 'array'); |
| if (sizeof($params) > 0) { |
| $sth = $this->prepare($query); |
| if (DB::isError($sth)) { |
| return $sth; |
| } |
| $res =& $this->execute($sth, $params); |
| $this->freePrepared($sth); |
| } else { |
| $res =& $this->query($query); |
| } |
| if (DB::isError($res)) { |
| return $res; |
| } |
| if ($fetchmode == DB_FETCHMODE_DEFAULT) { |
| $fetchmode = $this->fetchmode; |
| } |
| $cols = $res->numCols(); |
| if ($cols < 2) { |
| $tmp =& $this->raiseError(DB_ERROR_TRUNCATED); |
| return $tmp; |
| } |
| $results = array(); |
| if ($cols > 2 || $force_array) { |
| // return array values |
| // XXX this part can be optimized |
| if ($fetchmode == DB_FETCHMODE_ASSOC) { |
| while (is_array($row = $res->fetchRow(DB_FETCHMODE_ASSOC))) { |
| reset($row); |
| $key = current($row); |
| unset($row[key($row)]); |
| if ($group) { |
| $results[$key][] = $row; |
| } else { |
| $results[$key] = $row; |
| } |
| } |
| } elseif ($fetchmode == DB_FETCHMODE_OBJECT) { |
| while ($row = $res->fetchRow(DB_FETCHMODE_OBJECT)) { |
| $arr = get_object_vars($row); |
| $key = current($arr); |
| if ($group) { |
| $results[$key][] = $row; |
| } else { |
| $results[$key] = $row; |
| } |
| } |
| } else { |
| while (is_array($row = $res->fetchRow(DB_FETCHMODE_ORDERED))) { |
| // we shift away the first element to get |
| // indices running from 0 again |
| $key = array_shift($row); |
| if ($group) { |
| $results[$key][] = $row; |
| } else { |
| $results[$key] = $row; |
| } |
| } |
| } |
| if (DB::isError($row)) { |
| $results = $row; |
| } |
| } else { |
| // return scalar values |
| while (is_array($row = $res->fetchRow(DB_FETCHMODE_ORDERED))) { |
| if ($group) { |
| $results[$row[0]][] = $row[1]; |
| } else { |
| $results[$row[0]] = $row[1]; |
| } |
| } |
| if (DB::isError($row)) { |
| $results = $row; |
| } |
| } |
| $res->free(); |
| return $results; |
| } |
| // }}} |
| // {{{ getAll() |
| /** |
| * Fetch all the rows returned from a query |
| * |
| * @param string $query the SQL query |
| * @param array $params array to be used in execution of the statement. |
| * Quantity of array elements must match quantity |
| * of placeholders in query. This function does |
| * NOT support scalars. |
| * @param int $fetchmode the fetch mode to use |
| * |
| * @return array an nested array. DB error on failure. |
| * |
| * @access public |
| */ |
| function &getAll($query, |
| $params = array(), |
| $fetchmode = DB_FETCHMODE_DEFAULT) |
| { |
| // compat check, the params and fetchmode parameters used to |
| // have the opposite order |
| if (!is_array($params)) { |
| if (is_array($fetchmode)) { |
| if ($params === null) { |
| $tmp = DB_FETCHMODE_DEFAULT; |
| } else { |
| $tmp = $params; |
| } |
| $params = $fetchmode; |
| $fetchmode = $tmp; |
| } elseif ($params !== null) { |
| $fetchmode = $params; |
| $params = array(); |
| } |
| } |
| if (sizeof($params) > 0) { |
| $sth = $this->prepare($query); |
| if (DB::isError($sth)) { |
| return $sth; |
| } |
| $res =& $this->execute($sth, $params); |
| $this->freePrepared($sth); |
| } else { |
| $res =& $this->query($query); |
| } |
| if (DB::isError($res) || $res === DB_OK) { |
| return $res; |
| } |
| $results = array(); |
| while (DB_OK === $res->fetchInto($row, $fetchmode)) { |
| if ($fetchmode & DB_FETCHMODE_FLIPPED) { |
| foreach ($row as $key => $val) { |
| $results[$key][] = $val; |
| } |
| } else { |
| $results[] = $row; |
| } |
| } |
| $res->free(); |
| if (DB::isError($row)) { |
| $tmp =& $this->raiseError($row); |
| return $tmp; |
| } |
| return $results; |
| } |
| // }}} |
| // {{{ autoCommit() |
| /** |
| * enable automatic Commit |
| * |
| * @param boolean $onoff |
| * @return mixed DB_Error |
| * |
| * @access public |
| */ |
| function autoCommit($onoff=false) |
| { |
| return $this->raiseError(DB_ERROR_NOT_CAPABLE); |
| } |
| // }}} |
| // {{{ commit() |
| /** |
| * starts a Commit |
| * |
| * @return mixed DB_Error |
| * |
| * @access public |
| */ |
| function commit() |
| { |
| return $this->raiseError(DB_ERROR_NOT_CAPABLE); |
| } |
| // }}} |
| // {{{ rollback() |
| /** |
| * starts a rollback |
| * |
| * @return mixed DB_Error |
| * |
| * @access public |
| */ |
| function rollback() |
| { |
| return $this->raiseError(DB_ERROR_NOT_CAPABLE); |
| } |
| // }}} |
| // {{{ numRows() |
| /** |
| * Returns the number of rows in a result object |
| * |
| * @param object DB_Result the result object to check |
| * |
| * @return mixed DB_Error or the number of rows |
| * |
| * @access public |
| */ |
| function numRows($result) |
| { |
| return $this->raiseError(DB_ERROR_NOT_CAPABLE); |
| } |
| // }}} |
| // {{{ affectedRows() |
| /** |
| * Returns the affected rows of a query |
| * |
| * @return mixed DB_Error or number of rows |
| * |
| * @access public |
| */ |
| function affectedRows() |
| { |
| return $this->raiseError(DB_ERROR_NOT_CAPABLE); |
| } |
| // }}} |
| // {{{ errorNative() |
| /** |
| * Returns an errormessage, provides by the database |
| * |
| * @return mixed DB_Error or message |
| * |
| * @access public |
| */ |
| function errorNative() |
| { |
| return $this->raiseError(DB_ERROR_NOT_CAPABLE); |
| } |
| // }}} |
| // {{{ getSequenceName() |
| /** |
| * Generate the name used inside the database for a sequence |
| * |
| * The createSequence() docblock contains notes about storing sequence |
| * names. |
| * |
| * @param string $sqn the sequence's public name |
| * |
| * @return string the sequence's name in the backend |
| * |
| * @see DB_common::createSequence(), DB_common::dropSequence(), |
| * DB_common::nextID(), DB_common::setOption() |
| * @access private |
| */ |
| function getSequenceName($sqn) |
| { |
| return sprintf($this->getOption('seqname_format'), |
| preg_replace('/[^a-z0-9_.]/i', '_', $sqn)); |
| } |
| // }}} |
| // {{{ nextId() |
| /** |
| * Returns the next free id in a sequence |
| * |
| * @param string $seq_name name of the sequence |
| * @param boolean $ondemand when true, the seqence is automatically |
| * created if it does not exist |
| * |
| * @return int the next id number in the sequence. DB_Error if problem. |
| * |
| * @see DB_common::createSequence(), DB_common::dropSequence(), |
| * DB_common::getSequenceName() |
| * @access public |
| */ |
| function nextId($seq_name, $ondemand = true) |
| { |
| return $this->raiseError(DB_ERROR_NOT_CAPABLE); |
| } |
| // }}} |
| // {{{ createSequence() |
| /** |
| * Creates a new sequence |
| * |
| * The name of a given sequence is determined by passing the string |
| * provided in the <var>$seq_name</var> argument through PHP's sprintf() |
| * function using the value from the <var>seqname_format</var> option as |
| * the sprintf()'s format argument. |
| * |
| * <var>seqname_format</var> is set via setOption(). |
| * |
| * @param string $seq_name name of the new sequence |
| * |
| * @return int DB_OK on success. A DB_Error object is returned if |
| * problems arise. |
| * |
| * @see DB_common::dropSequence(), DB_common::getSequenceName(), |
| * DB_common::nextID() |
| * @access public |
| */ |
| function createSequence($seq_name) |
| { |
| return $this->raiseError(DB_ERROR_NOT_CAPABLE); |
| } |
| // }}} |
| // {{{ dropSequence() |
| /** |
| * Deletes a sequence |
| * |
| * @param string $seq_name name of the sequence to be deleted |
| * |
| * @return int DB_OK on success. DB_Error if problems. |
| * |
| * @see DB_common::createSequence(), DB_common::getSequenceName(), |
| * DB_common::nextID() |
| * @access public |
| */ |
| function dropSequence($seq_name) |
| { |
| return $this->raiseError(DB_ERROR_NOT_CAPABLE); |
| } |
| // }}} |
| // {{{ tableInfo() |
| /** |
| * Returns information about a table or a result set |
| * |
| * The format of the resulting array depends on which <var>$mode</var> |
| * you select. The sample output below is based on this query: |
| * <pre> |
| * SELECT tblFoo.fldID, tblFoo.fldPhone, tblBar.fldId |
| * FROM tblFoo |
| * JOIN tblBar ON tblFoo.fldId = tblBar.fldId |
| * </pre> |
| * |
| * <ul> |
| * <li> |
| * |
| * <kbd>null</kbd> (default) |
| * <pre> |
| * [0] => Array ( |
| * [table] => tblFoo |
| * [name] => fldId |
| * [type] => int |
| * [len] => 11 |
| * [flags] => primary_key not_null |
| * ) |
| * [1] => Array ( |
| * [table] => tblFoo |
| * [name] => fldPhone |
| * [type] => string |
| * [len] => 20 |
| * [flags] => |
| * ) |
| * [2] => Array ( |
| * [table] => tblBar |
| * [name] => fldId |
| * [type] => int |
| * [len] => 11 |
| * [flags] => primary_key not_null |
| * ) |
| * </pre> |
| * |
| * </li><li> |
| * |
| * <kbd>DB_TABLEINFO_ORDER</kbd> |
| * |
| * <p>In addition to the information found in the default output, |
| * a notation of the number of columns is provided by the |
| * <samp>num_fields</samp> element while the <samp>order</samp> |
| * element provides an array with the column names as the keys and |
| * their location index number (corresponding to the keys in the |
| * the default output) as the values.</p> |
| * |
| * <p>If a result set has identical field names, the last one is |
| * used.</p> |
| * |
| * <pre> |
| * [num_fields] => 3 |
| * [order] => Array ( |
| * [fldId] => 2 |
| * [fldTrans] => 1 |
| * ) |
| * </pre> |
| * |
| * </li><li> |
| * |
| * <kbd>DB_TABLEINFO_ORDERTABLE</kbd> |
| * |
| * <p>Similar to <kbd>DB_TABLEINFO_ORDER</kbd> but adds more |
| * dimensions to the array in which the table names are keys and |
| * the field names are sub-keys. This is helpful for queries that |
| * join tables which have identical field names.</p> |
| * |
| * <pre> |
| * [num_fields] => 3 |
| * [ordertable] => Array ( |
| * [tblFoo] => Array ( |
| * [fldId] => 0 |
| * [fldPhone] => 1 |
| * ) |
| * [tblBar] => Array ( |
| * [fldId] => 2 |
| * ) |
| * ) |
| * </pre> |
| * |
| * </li> |
| * </ul> |
| * |
| * The <samp>flags</samp> element contains a space separated list |
| * of extra information about the field. This data is inconsistent |
| * between DBMS's due to the way each DBMS works. |
| * + <samp>primary_key</samp> |
| * + <samp>unique_key</samp> |
| * + <samp>multiple_key</samp> |
| * + <samp>not_null</samp> |
| * |
| * Most DBMS's only provide the <samp>table</samp> and <samp>flags</samp> |
| * elements if <var>$result</var> is a table name. The following DBMS's |
| * provide full information from queries: |
| * + fbsql |
| * + mysql |
| * |
| * If the 'portability' option has <samp>DB_PORTABILITY_LOWERCASE</samp> |
| * turned on, the names of tables and fields will be lowercased. |
| * |
| * @param object|string $result DB_result object from a query or a |
| * string containing the name of a table. |
| * While this also accepts a query result |
| * resource identifier, this behavior is |
| * deprecated. |
| * @param int $mode either unused or one of the tableInfo modes: |
| * <kbd>DB_TABLEINFO_ORDERTABLE</kbd>, |
| * <kbd>DB_TABLEINFO_ORDER</kbd> or |
| * <kbd>DB_TABLEINFO_FULL</kbd> (which does both). |
| * These are bitwise, so the first two can be |
| * combined using <kbd>|</kbd>. |
| * @return array an associative array with the information requested. |
| * If something goes wrong an error object is returned. |
| * |
| * @see DB_common::setOption() |
| * @access public |
| */ |
| function tableInfo($result, $mode = null) |
| { |
| /* |
| * If the DB_<driver> class has a tableInfo() method, that one |
| * overrides this one. But, if the driver doesn't have one, |
| * this method runs and tells users about that fact. |
| */ |
| return $this->raiseError(DB_ERROR_NOT_CAPABLE); |
| } |
| // }}} |
| // {{{ getTables() |
| /** |
| * @deprecated Deprecated in release 1.2 or lower |
| */ |
| function getTables() |
| { |
| return $this->getListOf('tables'); |
| } |
| // }}} |
| // {{{ getListOf() |
| /** |
| * list internal DB info |
| * valid values for $type are db dependent, |
| * often: databases, users, view, functions |
| * |
| * @param string $type type of requested info |
| * |
| * @return mixed DB_Error or the requested data |
| * |
| * @access public |
| */ |
| function getListOf($type) |
| { |
| $sql = $this->getSpecialQuery($type); |
| if ($sql === null) { // No support |
| return $this->raiseError(DB_ERROR_UNSUPPORTED); |
| } elseif (is_int($sql) || DB::isError($sql)) { // Previous error |
| return $this->raiseError($sql); |
| } elseif (is_array($sql)) { // Already the result |
| return $sql; |
| } |
| return $this->getCol($sql); // Launch this query |
| } |
| // }}} |
| // {{{ getSpecialQuery() |
| /** |
| * Returns the query needed to get some backend info |
| * |
| * @param string $type What kind of info you want to retrieve |
| * |
| * @return string The SQL query string |
| * |
| * @access public |
| */ |
| function getSpecialQuery($type) |
| { |
| return $this->raiseError(DB_ERROR_UNSUPPORTED); |
| } |
| // }}} |
| // {{{ _rtrimArrayValues() |
| /** |
| * Right trim all strings in an array |
| * |
| * @param array $array the array to be trimmed (passed by reference) |
| * @return void |
| * @access private |
| */ |
| function _rtrimArrayValues(&$array) |
| { |
| foreach ($array as $key => $value) { |
| if (is_string($value)) { |
| $array[$key] = rtrim($value); |
| } |
| } |
| } |
| // }}} |
| // {{{ _convertNullArrayValuesToEmpty() |
| /** |
| * Convert all null values in an array to empty strings |
| * |
| * @param array $array the array to be de-nullified (passed by reference) |
| * @return void |
| * @access private |
| */ |
| function _convertNullArrayValuesToEmpty(&$array) |
| { |
| foreach ($array as $key => $value) { |
| if (is_null($value)) { |
| $array[$key] = ''; |
| } |
| } |
| } |
| // }}} |
| } |
| /* |
| * Local variables: |
| * tab-width: 4 |
| * c-basic-offset: 4 |
| * End: |
| */ |
| ?> |