diff --git a/ChangeLog b/ChangeLog index b3ef7d205e2..a2d95573257 100644 --- a/ChangeLog +++ b/ChangeLog @@ -60,7 +60,7 @@ For users: - New: [ task #210 ] Can choose cash account during POS login. - New: [ task #104 ] Can create an invoice from several orders. - New: Update libs/tools/logo for DoliWamp (now use PHP 5.3). -- New: Added ODT Template tag {object_total_discount} +- New: Added ODT Template tag {object_total_discount_ht} - New: Add new import options: Third parties bank details, warehouses and stocks, categories and suppliers prices - New: English bank account need a bank code (called sort code) to identify an account. - New: Can choose menu entry to show with external site module. diff --git a/dev/skeletons/build_webservice_from_class.php b/dev/skeletons/build_webservice_from_class.php index f489f32201b..e21b4cf89f7 100644 --- a/dev/skeletons/build_webservice_from_class.php +++ b/dev/skeletons/build_webservice_from_class.php @@ -28,7 +28,7 @@ $path=dirname(__FILE__).'/'; // Test if batch mode if (substr($sapi_type, 0, 3) == 'cgi') { - echo "Error: You ar usingr PH for CGI. To execute ".$script_file." from command line, you must use PHP for CLI mode.\n"; + echo "Error: You are using PHP for CGI. To execute ".$script_file." from command line, you must use PHP for CLI mode.\n"; exit; } diff --git a/htdocs/adherents/class/adherent.class.php b/htdocs/adherents/class/adherent.class.php index e2e20f41fba..03353dfe386 100644 --- a/htdocs/adherents/class/adherent.class.php +++ b/htdocs/adherents/class/adherent.class.php @@ -423,7 +423,7 @@ class Adherent extends CommonObject $this->db->begin(); $sql = "UPDATE ".MAIN_DB_PREFIX."adherent SET"; - $sql.= " civilite = ".($this->civilite_id?"'".$this->civilite_id."'":"null"); + $sql.= " civilite = ".(!is_null($this->civilite_id)?"'".$this->civilite_id."'":"null"); $sql.= ", prenom = ".($this->firstname?"'".$this->db->escape($this->firstname)."'":"null"); $sql.= ", nom=" .($this->lastname?"'".$this->db->escape($this->lastname)."'":"null"); $sql.= ", login=" .($this->login?"'".$this->db->escape($this->login)."'":"null"); diff --git a/htdocs/categories/categorie.php b/htdocs/categories/categorie.php index 61351343556..2557da5a030 100644 --- a/htdocs/categories/categorie.php +++ b/htdocs/categories/categorie.php @@ -85,9 +85,9 @@ if ($id || $ref) if ($user->societe_id) $socid=$user->societe_id; $result = restrictedArea($user,$objecttype,$objectid,$dbtablename,'','',$fieldid); -// Initialize technical object to manage hooks of thirdparties. Note that conf->hooks_modules contains array array -include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php'; -$hookmanager=new HookManager($db); +// Initialize technical object to manage hooks of thirdparties. Note that conf->hooks_modules contains array array +include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php'; +$hookmanager=new HookManager($db); $hookmanager->initHooks(array('categorycard')); @@ -95,9 +95,9 @@ $hookmanager->initHooks(array('categorycard')); * Actions */ -$parameters=array('id'=>$socid); -$reshook=$hookmanager->executeHooks('doActions',$parameters,$object,$action); // Note that $action and $object may have been modified by some hooks -$error=$hookmanager->error; $errors=array_merge($errors, (array) $hookmanager->errors); +$parameters=array('id'=>$socid); +$reshook=$hookmanager->executeHooks('doActions',$parameters,$object,$action); // Note that $action and $object may have been modified by some hooks +$error=$hookmanager->error; $errors=array_merge($errors, (array) $hookmanager->errors); if (empty($reshook)) { diff --git a/htdocs/comm/action/fiche.php b/htdocs/comm/action/fiche.php index 1a480fa56d8..ecb6c4e9b84 100644 --- a/htdocs/comm/action/fiche.php +++ b/htdocs/comm/action/fiche.php @@ -555,7 +555,13 @@ if ($action == 'create') } else { - print $form->select_company('','socid','',1,1); + //For external user force the company to user company + if (!empty($user->societe_id)) { + print $form->select_company($user->societe_id,'socid','',1,1); + } else { + print $form->select_company('','socid','',1,1); + } + } print ''; diff --git a/htdocs/compta/prelevement/factures.php b/htdocs/compta/prelevement/factures.php index 9778bf999c0..7ec5356c97b 100644 --- a/htdocs/compta/prelevement/factures.php +++ b/htdocs/compta/prelevement/factures.php @@ -32,6 +32,7 @@ require_once DOL_DOCUMENT_ROOT.'/compta/paiement/class/paiement.class.php'; $langs->load("companies"); $langs->load("categories"); +$langs->load('withdrawals'); // Securite acces client if ($user->societe_id > 0) accessforbidden(); diff --git a/htdocs/compta/prelevement/fiche-rejet.php b/htdocs/compta/prelevement/fiche-rejet.php index b5678b26923..988f1db2bc6 100644 --- a/htdocs/compta/prelevement/fiche-rejet.php +++ b/htdocs/compta/prelevement/fiche-rejet.php @@ -31,6 +31,7 @@ require_once DOL_DOCUMENT_ROOT.'/compta/prelevement/class/rejetprelevement.class require_once DOL_DOCUMENT_ROOT.'/compta/paiement/class/paiement.class.php'; $langs->load("categories"); +$langs->load('withdrawals'); // Securite acces client if ($user->societe_id > 0) accessforbidden(); diff --git a/htdocs/compta/prelevement/fiche.php b/htdocs/compta/prelevement/fiche.php index 9bfe97a4737..73450228480 100644 --- a/htdocs/compta/prelevement/fiche.php +++ b/htdocs/compta/prelevement/fiche.php @@ -130,7 +130,7 @@ if ($action == 'infocredit' && $user->rights->prelevement->bons->credit) $bon = new BonPrelevement($db,""); $form = new Form($db); -llxHeader('',$langs->trans("WithdrawalReceipts")); +llxHeader('',$langs->trans("WithdrawalReceipt")); if ($id > 0) @@ -138,7 +138,7 @@ if ($id > 0) $bon->fetch($id); $head = prelevement_prepare_head($bon); - dol_fiche_head($head, 'prelevement', $langs->trans("WithdrawalReceipts"), '', 'payment'); + dol_fiche_head($head, 'prelevement', $langs->trans("WithdrawalReceipt"), '', 'payment'); if (GETPOST('error','alpha')!='') { diff --git a/htdocs/compta/prelevement/lignes.php b/htdocs/compta/prelevement/lignes.php index 16da5e8c9e9..2e8978778ef 100644 --- a/htdocs/compta/prelevement/lignes.php +++ b/htdocs/compta/prelevement/lignes.php @@ -35,6 +35,7 @@ require_once DOL_DOCUMENT_ROOT.'/compta/paiement/class/paiement.class.php'; if ($user->societe_id > 0) accessforbidden(); $langs->load("categories"); +$langs->load('withdrawals'); // Get supervariables $prev_id = GETPOST('id','int'); diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index 9a6838d4886..0a5ae5df34c 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -2253,24 +2253,43 @@ abstract class CommonObject } /** - * Function that returns the total amount of discounts applied. + * Function that returns the total amount HT of discounts applied for all lines. * - * @return false|float False is returned if the discount couldn't be retrieved + * @return float */ function getTotalDiscount() { - $sql = 'SELECT (SUM(`subprice`) - SUM(`total_ht`)) as `discount` FROM '.MAIN_DB_PREFIX.$this->table_element.'det WHERE `'.$this->fk_element.'` = '.$this->id; + $total_discount=0.00; - $query = $this->db->query($sql); + $sql = "SELECT subprice as pu_ht, qty, remise_percent, total_ht"; + $sql.= " FROM ".MAIN_DB_PREFIX.$this->table_element."det"; + $sql.= " WHERE ".$this->fk_element." = ".$this->id; - if ($query) + dol_syslog(get_class($this).'::getTotalDiscount sql='.$sql); + $resql = $this->db->query($sql); + if ($resql) { - $result = $this->db->fetch_object($query); + $num=$this->db->num_rows($resql); + $i=0; + while ($i < $num) + { + $obj = $this->db->fetch_object($query); - return price2num($result->discount); + $pu_ht = $obj->pu_ht; + $qty= $obj->qty; + $discount_percent_line = $obj->remise_percent; + $total_ht = $obj->total_ht; + + $total_discount_line = price2num(($pu_ht * $qty) - $total_ht, 'MT'); + $total_discount += $total_discount_line; + + $i++; + } } - - return false; + else dol_syslog(get_class($this).'::getTotalDiscount '.$this->db->lasterror(), LOG_ERR); + + //print $total_discount; exit; + return price2num($total_discount); } /** @@ -2313,7 +2332,7 @@ abstract class CommonObject function isInEEC() { // List of all country codes that are in europe for european vat rules - // List found on http://ec.europa.eu/taxation_customs/vies/lang.do?fromWhichPage=vieshome + // List found on http://ec.europa.eu/taxation_customs/common/faq/faq_1179_en.htm#9 $country_code_in_EEC=array( 'AT', // Austria 'BE', // Belgium @@ -2326,16 +2345,17 @@ abstract class CommonObject 'ES', // Spain 'FI', // Finland 'FR', // France - 'GB', // Royaume-uni + 'GB', // United Kingdom 'GR', // Greece 'NL', // Holland 'HU', // Hungary 'IE', // Ireland + 'IM', // Isle of Man - Included in UK 'IT', // Italy 'LT', // Lithuania 'LU', // Luxembourg 'LV', // Latvia - 'MC', // Monaco Seems to use same IntraVAT than France (http://www.gouv.mc/devwww/wwwnew.nsf/c3241c4782f528bdc1256d52004f970b/9e370807042516a5c1256f81003f5bb3!OpenDocument) + 'MC', // Monaco - Included in France 'MT', // Malta //'NO', // Norway 'PL', // Poland diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index 6cf1f3aff41..8ff1f5706bf 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -3181,19 +3181,19 @@ class Form //print "name=$name, selectedrate=$selectedrate, seller=".$societe_vendeuse->country_code." buyer=".$societe_acheteuse->country_code." buyer is company=".$societe_acheteuse->isACompany()." idprod=$idprod, info_bits=$info_bits type=$type"; //exit; - // Get list of all VAT rates to show + // Define list of countries to use to search VAT rates to show // First we defined code_pays to use to find list if (is_object($societe_vendeuse)) { $code_pays="'".$societe_vendeuse->country_code."'"; } else - { + { $code_pays="'".$mysoc->country_code."'"; // Pour compatibilite ascendente } if (! empty($conf->global->SERVICE_ARE_ECOMMERCE_200238EC)) // If option to have vat for end customer for services is on { - if (! $societe_vendeuse->isInEEC() && $societe_acheteuse->isInEEC() && ! $societe_acheteuse->isACompany()) + if (! $societe_vendeuse->isInEEC() && (! is_object($societe_acheteuse) || ($societe_acheteuse->isInEEC() && ! $societe_acheteuse->isACompany()))) { // We also add the buyer if (is_numeric($type)) diff --git a/htdocs/core/class/html.formfile.class.php b/htdocs/core/class/html.formfile.class.php index 15ea8b2cc2c..d6d5483ffed 100644 --- a/htdocs/core/class/html.formfile.class.php +++ b/htdocs/core/class/html.formfile.class.php @@ -120,6 +120,7 @@ class FormFile { if ($perm) { + $langs->load('other'); print ' ('.$langs->trans("MaxSize").': '.$max.' '.$langs->trans("Kb"); print ' '.info_admin($langs->trans("ThisLimitIsDefinedInSetup",$max,$maxphp),1); print ')'; diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 8918731ea0e..576d9845776 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -2921,6 +2921,18 @@ function get_default_tva($thirdparty_seller, $thirdparty_buyer, $idprod=0, $idpr dol_syslog("get_default_tva: seller use vat=".$thirdparty_seller->tva_assuj.", seller country=".$thirdparty_seller->country_code.", seller in cee=".$thirdparty_seller->isInEEC().", buyer country=".$thirdparty_buyer->country_code.", buyer in cee=".$thirdparty_buyer->isInEEC().", idprod=".$idprod.", idprodfournprice=".$idprodfournprice.", SERVICE_ARE_ECOMMERCE_200238EC=".(! empty($conf->global->SERVICES_ARE_ECOMMERCE_200238EC)?$conf->global->SERVICES_ARE_ECOMMERCE_200238EC:'')); + // If services are eServices according to EU Council Directive 2002/38/EC (http://ec.europa.eu/taxation_customs/taxation/vat/traders/e-commerce/article_1610_en.htm) + // we use the buyer VAT. + if (! empty($conf->global->SERVICE_ARE_ECOMMERCE_200238EC)) + { + //print "eee".$thirdparty_buyer->isACompany();exit; + if (! $thirdparty_seller->isInEEC() && $thirdparty_buyer->isInEEC() && ! $thirdparty_buyer->isACompany()) + { + //print 'VATRULE 6'; + return get_product_vat_for_country($idprod,$thirdparty_buyer,$idprodfournprice); + } + } + // Si vendeur non assujeti a TVA (tva_assuj vaut 0/1 ou franchise/reel) if (is_numeric($thirdparty_seller->tva_assuj) && ! $thirdparty_seller->tva_assuj) { @@ -2964,18 +2976,6 @@ function get_default_tva($thirdparty_seller, $thirdparty_buyer, $idprod=0, $idpr } } - // If services are eServices according to EU Council Directive 2002/38/EC (ec.europa.eu/taxation_customs/taxation/v.../article_1610_en.htm) - // we use the buyer VAT. - if (! empty($conf->global->SERVICE_ARE_ECOMMERCE_200238EC)) - { - //print "eee".$thirdparty_buyer->isACompany();exit; - if (! $thirdparty_seller->isInEEC() && $thirdparty_buyer->isInEEC() && ! $thirdparty_buyer->isACompany()) - { - //print 'VATRULE 6'; - return get_product_vat_for_country($idprod,$thirdparty_buyer,$idprodfournprice); - } - } - // Sinon la TVA proposee par defaut=0. Fin de regle. // Rem: Cela signifie qu'au moins un des 2 est hors Communaute europeenne et que le pays differe //print 'VATRULE 7'; diff --git a/htdocs/core/modules/commande/doc/doc_generic_order_odt.modules.php b/htdocs/core/modules/commande/doc/doc_generic_order_odt.modules.php index db204d2d421..9e7edc33b08 100644 --- a/htdocs/core/modules/commande/doc/doc_generic_order_odt.modules.php +++ b/htdocs/core/modules/commande/doc/doc_generic_order_odt.modules.php @@ -115,7 +115,7 @@ class doc_generic_order_odt extends ModelePDFCommandes 'object_total_ht'=>price($object->total_ht,0,$outputlangs), 'object_total_vat'=>price($object->total_tva,0,$outputlangs), 'object_total_ttc'=>price($object->total_ttc,0,$outputlangs), - 'object_total_discount' => price($object->getTotalDiscount(), 0, $outputlangs), + 'object_total_discount_ht' => price($object->getTotalDiscount(), 0, $outputlangs), 'object_vatrate'=>vatrate($object->tva), 'object_note_private'=>$object->note, 'object_note'=>$object->note_public, diff --git a/htdocs/core/modules/facture/doc/doc_generic_invoice_odt.modules.php b/htdocs/core/modules/facture/doc/doc_generic_invoice_odt.modules.php index 96802f9ae4b..23f6f4685b3 100644 --- a/htdocs/core/modules/facture/doc/doc_generic_invoice_odt.modules.php +++ b/htdocs/core/modules/facture/doc/doc_generic_invoice_odt.modules.php @@ -124,7 +124,7 @@ class doc_generic_invoice_odt extends ModelePDFFactures 'object_total_ht'=>price($object->total_ht,0,$outputlangs), 'object_total_vat'=>price($object->total_tva,0,$outputlangs), 'object_total_ttc'=>price($object->total_ttc,0,$outputlangs), - 'object_total_discount' => price($object->getTotalDiscount(), 0, $outputlangs), + 'object_total_discount_ht' => price($object->getTotalDiscount(), 0, $outputlangs), 'object_vatrate'=>(isset($object->tva)?vatrate($object->tva):''), 'object_note_private'=>$object->note, 'object_note'=>$object->note_public, diff --git a/htdocs/core/modules/propale/doc/doc_generic_proposal_odt.modules.php b/htdocs/core/modules/propale/doc/doc_generic_proposal_odt.modules.php index 9327e4adbae..0c1d394aa6d 100644 --- a/htdocs/core/modules/propale/doc/doc_generic_proposal_odt.modules.php +++ b/htdocs/core/modules/propale/doc/doc_generic_proposal_odt.modules.php @@ -114,7 +114,7 @@ class doc_generic_proposal_odt extends ModelePDFPropales 'object_total_ht'=>price($object->total_ht,0,$outputlangs), 'object_total_vat'=>price($object->total_tva,0,$outputlangs), 'object_total_ttc'=>price($object->total_ttc,0,$outputlangs), - 'object_total_discount' => price($object->getTotalDiscount(), 0, $outputlangs), + 'object_total_discount_ht' => price($object->getTotalDiscount(), 0, $outputlangs), 'object_vatrate'=>vatrate($object->tva), 'object_note_private'=>$object->note, 'object_note'=>$object->note_public, diff --git a/htdocs/core/tpl/freeproductline_create.tpl.php b/htdocs/core/tpl/freeproductline_create.tpl.php index 2457e664ac9..d8ef04f18dc 100644 --- a/htdocs/core/tpl/freeproductline_create.tpl.php +++ b/htdocs/core/tpl/freeproductline_create.tpl.php @@ -152,4 +152,4 @@ if (! empty($conf->margin->enabled) && ! empty($object->element) && in_array($ob - + \ No newline at end of file diff --git a/htdocs/core/tpl/predefinedproductline_create.tpl.php b/htdocs/core/tpl/predefinedproductline_create.tpl.php index d03750c98f4..470d76eed34 100644 --- a/htdocs/core/tpl/predefinedproductline_create.tpl.php +++ b/htdocs/core/tpl/predefinedproductline_create.tpl.php @@ -204,4 +204,4 @@ if (! empty($usemargins)) - + \ No newline at end of file diff --git a/htdocs/includes/ckeditor/ckeditor.php b/htdocs/includes/ckeditor/ckeditor.php index b2bd65b3c02..ced620b9b14 100644 --- a/htdocs/includes/ckeditor/ckeditor.php +++ b/htdocs/includes/ckeditor/ckeditor.php @@ -1,29 +1,29 @@ -CKEditor web site to find more information about the editor. - * \section install_sec Installation - * \subsection step1 Include ckeditor.php in your PHP web site. - * @code - * - * @endcode - * \subsection step2 Create CKEditor class instance and use one of available methods to insert CKEditor. - * @code - * editor("editor1", "

Initial value.

"); - * ?> - * @endcode - */ - -if ( !function_exists('version_compare') || version_compare( phpversion(), '5', '<' ) ) - include_once( 'ckeditor_php4.php' ) ; -else - include_once( 'ckeditor_php5.php' ) ; +CKEditor web site to find more information about the editor. + * \section install_sec Installation + * \subsection step1 Include ckeditor.php in your PHP web site. + * @code + * + * @endcode + * \subsection step2 Create CKEditor class instance and use one of available methods to insert CKEditor. + * @code + * editor("editor1", "

Initial value.

"); + * ?> + * @endcode + */ + +if ( !function_exists('version_compare') || version_compare( phpversion(), '5', '<' ) ) + include_once( 'ckeditor_php4.php' ) ; +else + include_once( 'ckeditor_php5.php' ) ; diff --git a/htdocs/includes/ckeditor/ckeditor_php4.php b/htdocs/includes/ckeditor/ckeditor_php4.php index 47dfb52b6eb..34122ba094b 100644 --- a/htdocs/includes/ckeditor/ckeditor_php4.php +++ b/htdocs/includes/ckeditor/ckeditor_php4.php @@ -1,566 +1,566 @@ -editor("editor1", "

Initial value.

"); - * @endcode - */ -class CKEditor -{ - /** - * The version of %CKEditor. - * \private - */ - var $version = '3.6.4'; - /** - * A constant string unique for each release of %CKEditor. - * \private - */ - var $_timestamp = 'C6HH5UF'; - - /** - * URL to the %CKEditor installation directory (absolute or relative to document root). - * If not set, CKEditor will try to guess it's path. - * - * Example usage: - * @code - * $CKEditor->basePath = '/ckeditor/'; - * @endcode - */ - var $basePath; - /** - * An array that holds the global %CKEditor configuration. - * For the list of available options, see http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.config.html - * - * Example usage: - * @code - * $CKEditor->config['height'] = 400; - * // Use @@ at the beggining of a string to ouput it without surrounding quotes. - * $CKEditor->config['width'] = '@@screen.width * 0.8'; - * @endcode - */ - var $config = array(); - /** - * A boolean variable indicating whether CKEditor has been initialized. - * Set it to true only if you have already included - * <script> tag loading ckeditor.js in your website. - */ - var $initialized = false; - /** - * Boolean variable indicating whether created code should be printed out or returned by a function. - * - * Example 1: get the code creating %CKEditor instance and print it on a page with the "echo" function. - * @code - * $CKEditor = new CKEditor(); - * $CKEditor->returnOutput = true; - * $code = $CKEditor->editor("editor1", "

Initial value.

"); - * echo "

Editor 1:

"; - * echo $code; - * @endcode - */ - var $returnOutput = false; - /** - * An array with textarea attributes. - * - * When %CKEditor is created with the editor() method, a HTML <textarea> element is created, - * it will be displayed to anyone with JavaScript disabled or with incompatible browser. - */ - var $textareaAttributes = array( "rows" => 8, "cols" => 60 ); - /** - * A string indicating the creation date of %CKEditor. - * Do not change it unless you want to force browsers to not use previously cached version of %CKEditor. - */ - var $timestamp = "C6HH5UF"; - /** - * An array that holds event listeners. - * \private - */ - var $_events = array(); - /** - * An array that holds global event listeners. - * \private - */ - var $_globalEvents = array(); - - /** - * Main Constructor. - * - * @param $basePath (string) URL to the %CKEditor installation directory (optional). - */ - function CKEditor($basePath = null) { - if (!empty($basePath)) { - $this->basePath = $basePath; - } - } - - /** - * Creates a %CKEditor instance. - * In incompatible browsers %CKEditor will downgrade to plain HTML <textarea> element. - * - * @param $name (string) Name of the %CKEditor instance (this will be also the "name" attribute of textarea element). - * @param $value (string) Initial value (optional). - * @param $config (array) The specific configurations to apply to this editor instance (optional). - * @param $events (array) Event listeners for this editor instance (optional). - * - * Example usage: - * @code - * $CKEditor = new CKEditor(); - * $CKEditor->editor("field1", "

Initial value.

"); - * @endcode - * - * Advanced example: - * @code - * $CKEditor = new CKEditor(); - * $config = array(); - * $config['toolbar'] = array( - * array( 'Source', '-', 'Bold', 'Italic', 'Underline', 'Strike' ), - * array( 'Image', 'Link', 'Unlink', 'Anchor' ) - * ); - * $events['instanceReady'] = 'function (ev) { - * alert("Loaded: " + ev.editor.name); - * }'; - * $CKEditor->editor("field1", "

Initial value.

", $config, $events); - * @endcode - */ - function editor($name, $value = "", $config = array(), $events = array()) - { - $attr = ""; - foreach ($this->textareaAttributes as $key => $val) { - $attr.= " " . $key . '="' . str_replace('"', '"', $val) . '"'; - } - $out = "\n"; - if (!$this->initialized) { - $out .= $this->init(); - } - - $_config = $this->configSettings($config, $events); - - $js = $this->returnGlobalEvents(); - if (!empty($_config)) - $js .= "CKEDITOR.replace('".$name."', ".$this->jsEncode($_config).");"; - else - $js .= "CKEDITOR.replace('".$name."');"; - - $out .= $this->script($js); - - if (!$this->returnOutput) { - print $out; - $out = ""; - } - - return $out; - } - - /** - * Replaces a <textarea> with a %CKEditor instance. - * - * @param $id (string) The id or name of textarea element. - * @param $config (array) The specific configurations to apply to this editor instance (optional). - * @param $events (array) Event listeners for this editor instance (optional). - * - * Example 1: adding %CKEditor to <textarea name="article"></textarea> element: - * @code - * $CKEditor = new CKEditor(); - * $CKEditor->replace("article"); - * @endcode - */ - function replace($id, $config = array(), $events = array()) - { - $out = ""; - if (!$this->initialized) { - $out .= $this->init(); - } - - $_config = $this->configSettings($config, $events); - - $js = $this->returnGlobalEvents(); - if (!empty($_config)) { - $js .= "CKEDITOR.replace('".$id."', ".$this->jsEncode($_config).");"; - } - else { - $js .= "CKEDITOR.replace('".$id."');"; - } - $out .= $this->script($js); - - if (!$this->returnOutput) { - print $out; - $out = ""; - } - - return $out; - } - - /** - * Replace all <textarea> elements available in the document with editor instances. - * - * @param $className (string) If set, replace all textareas with class className in the page. - * - * Example 1: replace all <textarea> elements in the page. - * @code - * $CKEditor = new CKEditor(); - * $CKEditor->replaceAll(); - * @endcode - * - * Example 2: replace all <textarea class="myClassName"> elements in the page. - * @code - * $CKEditor = new CKEditor(); - * $CKEditor->replaceAll( 'myClassName' ); - * @endcode - */ - function replaceAll($className = null) - { - $out = ""; - if (!$this->initialized) { - $out .= $this->init(); - } - - $_config = $this->configSettings(); - - $js = $this->returnGlobalEvents(); - if (empty($_config)) { - if (empty($className)) { - $js .= "CKEDITOR.replaceAll();"; - } - else { - $js .= "CKEDITOR.replaceAll('".$className."');"; - } - } - else { - $classDetection = ""; - $js .= "CKEDITOR.replaceAll( function(textarea, config) {\n"; - if (!empty($className)) { - $js .= " var classRegex = new RegExp('(?:^| )' + '". $className ."' + '(?:$| )');\n"; - $js .= " if (!classRegex.test(textarea.className))\n"; - $js .= " return false;\n"; - } - $js .= " CKEDITOR.tools.extend(config, ". $this->jsEncode($_config) .", true);"; - $js .= "} );"; - - } - - $out .= $this->script($js); - - if (!$this->returnOutput) { - print $out; - $out = ""; - } - - return $out; - } - - /** - * Adds event listener. - * Events are fired by %CKEditor in various situations. - * - * @param $event (string) Event name. - * @param $javascriptCode (string) Javascript anonymous function or function name. - * - * Example usage: - * @code - * $CKEditor->addEventHandler('instanceReady', 'function (ev) { - * alert("Loaded: " + ev.editor.name); - * }'); - * @endcode - */ - function addEventHandler($event, $javascriptCode) - { - if (!isset($this->_events[$event])) { - $this->_events[$event] = array(); - } - // Avoid duplicates. - if (!in_array($javascriptCode, $this->_events[$event])) { - $this->_events[$event][] = $javascriptCode; - } - } - - /** - * Clear registered event handlers. - * Note: this function will have no effect on already created editor instances. - * - * @param $event (string) Event name, if not set all event handlers will be removed (optional). - */ - function clearEventHandlers($event = null) - { - if (!empty($event)) { - $this->_events[$event] = array(); - } - else { - $this->_events = array(); - } - } - - /** - * Adds global event listener. - * - * @param $event (string) Event name. - * @param $javascriptCode (string) Javascript anonymous function or function name. - * - * Example usage: - * @code - * $CKEditor->addGlobalEventHandler('dialogDefinition', 'function (ev) { - * alert("Loading dialog: " + ev.data.name); - * }'); - * @endcode - */ - function addGlobalEventHandler($event, $javascriptCode) - { - if (!isset($this->_globalEvents[$event])) { - $this->_globalEvents[$event] = array(); - } - // Avoid duplicates. - if (!in_array($javascriptCode, $this->_globalEvents[$event])) { - $this->_globalEvents[$event][] = $javascriptCode; - } - } - - /** - * Clear registered global event handlers. - * Note: this function will have no effect if the event handler has been already printed/returned. - * - * @param $event (string) Event name, if not set all event handlers will be removed (optional). - */ - function clearGlobalEventHandlers($event = null) - { - if (!empty($event)) { - $this->_globalEvents[$event] = array(); - } - else { - $this->_globalEvents = array(); - } - } - - /** - * Prints javascript code. - * \private - * - * @param string $js - */ - function script($js) - { - $out = "\n"; - - return $out; - } - - /** - * Returns the configuration array (global and instance specific settings are merged into one array). - * \private - * - * @param $config (array) The specific configurations to apply to editor instance. - * @param $events (array) Event listeners for editor instance. - */ - function configSettings($config = array(), $events = array()) - { - $_config = $this->config; - $_events = $this->_events; - - if (is_array($config) && !empty($config)) { - $_config = array_merge($_config, $config); - } - - if (is_array($events) && !empty($events)) { - foreach ($events as $eventName => $code) { - if (!isset($_events[$eventName])) { - $_events[$eventName] = array(); - } - if (!in_array($code, $_events[$eventName])) { - $_events[$eventName][] = $code; - } - } - } - - if (!empty($_events)) { - foreach($_events as $eventName => $handlers) { - if (empty($handlers)) { - continue; - } - else if (count($handlers) == 1) { - $_config['on'][$eventName] = '@@'.$handlers[0]; - } - else { - $_config['on'][$eventName] = '@@function (ev){'; - foreach ($handlers as $handler => $code) { - $_config['on'][$eventName] .= '('.$code.')(ev);'; - } - $_config['on'][$eventName] .= '}'; - } - } - } - - return $_config; - } - - /** - * Return global event handlers. - * \private - */ - function returnGlobalEvents() - { - static $returnedEvents; - $out = ""; - - if (!isset($returnedEvents)) { - $returnedEvents = array(); - } - - if (!empty($this->_globalEvents)) { - foreach ($this->_globalEvents as $eventName => $handlers) { - foreach ($handlers as $handler => $code) { - if (!isset($returnedEvents[$eventName])) { - $returnedEvents[$eventName] = array(); - } - // Return only new events - if (!in_array($code, $returnedEvents[$eventName])) { - $out .= ($code ? "\n" : "") . "CKEDITOR.on('". $eventName ."', $code);"; - $returnedEvents[$eventName][] = $code; - } - } - } - } - - return $out; - } - - /** - * Initializes CKEditor (executed only once). - * \private - */ - function init() - { - static $initComplete; - $out = ""; - - if (!empty($initComplete)) { - return ""; - } - - if ($this->initialized) { - $initComplete = true; - return ""; - } - - $args = ""; - $ckeditorPath = $this->ckeditorPath(); - - if (!empty($this->timestamp) && $this->timestamp != "%"."TIMESTAMP%") { - $args = '?t=' . $this->timestamp; - } - - // Skip relative paths... - if (strpos($ckeditorPath, '..') !== 0) { - $out .= $this->script("window.CKEDITOR_BASEPATH='". $ckeditorPath ."';"); - } - - $out .= "\n"; - - $extraCode = ""; - if ($this->timestamp != $this->_timestamp) { - $extraCode .= ($extraCode ? "\n" : "") . "CKEDITOR.timestamp = '". $this->timestamp ."';"; - } - if ($extraCode) { - $out .= $this->script($extraCode); - } - - $initComplete = $this->initialized = true; - - return $out; - } - - /** - * Return path to ckeditor.js. - * \private - */ - function ckeditorPath() - { - if (!empty($this->basePath)) { - return $this->basePath; - } - - /** - * The absolute pathname of the currently executing script. - * Note: If a script is executed with the CLI, as a relative path, such as file.php or ../file.php, - * $_SERVER['SCRIPT_FILENAME'] will contain the relative path specified by the user. - */ - if (isset($_SERVER['SCRIPT_FILENAME'])) { - $realPath = dirname($_SERVER['SCRIPT_FILENAME']); - } - else { - /** - * realpath - Returns canonicalized absolute pathname - */ - $realPath = realpath( './' ) ; - } - - /** - * The filename of the currently executing script, relative to the document root. - * For instance, $_SERVER['PHP_SELF'] in a script at the address http://example.com/test.php/foo.bar - * would be /test.php/foo.bar. - */ - $selfPath = dirname($_SERVER['PHP_SELF']); - $file = str_replace("\\", "/", __FILE__); - - if (!$selfPath || !$realPath || !$file) { - return "/ckeditor/"; - } - - $documentRoot = substr($realPath, 0, strlen($realPath) - strlen($selfPath)); - $fileUrl = substr($file, strlen($documentRoot)); - $ckeditorUrl = str_replace("ckeditor_php4.php", "", $fileUrl); - - return $ckeditorUrl; - } - - /** - * This little function provides a basic JSON support. - * \private - * - * @param mixed $val - * @return string - */ - function jsEncode($val) - { - if (is_null($val)) { - return 'null'; - } - if (is_bool($val)) { - return $val ? 'true' : 'false'; - } - if (is_int($val)) { - return $val; - } - if (is_float($val)) { - return str_replace(',', '.', $val); - } - if (is_array($val) || is_object($val)) { - if (is_array($val) && (array_keys($val) === range(0,count($val)-1))) { - return '[' . implode(',', array_map(array($this, 'jsEncode'), $val)) . ']'; - } - $temp = array(); - foreach ($val as $k => $v){ - $temp[] = $this->jsEncode("{$k}") . ':' . $this->jsEncode($v); - } - return '{' . implode(',', $temp) . '}'; - } - // String otherwise - if (strpos($val, '@@') === 0) - return substr($val, 2); - if (strtoupper(substr($val, 0, 9)) == 'CKEDITOR.') - return $val; - - return '"' . str_replace(array("\\", "/", "\n", "\t", "\r", "\x08", "\x0c", '"'), array('\\\\', '\\/', '\\n', '\\t', '\\r', '\\b', '\\f', '\"'), $val) . '"'; - } -} +editor("editor1", "

Initial value.

"); + * @endcode + */ +class CKEditor +{ + /** + * The version of %CKEditor. + * \private + */ + var $version = '3.6.4'; + /** + * A constant string unique for each release of %CKEditor. + * \private + */ + var $_timestamp = 'C6HH5UF'; + + /** + * URL to the %CKEditor installation directory (absolute or relative to document root). + * If not set, CKEditor will try to guess it's path. + * + * Example usage: + * @code + * $CKEditor->basePath = '/ckeditor/'; + * @endcode + */ + var $basePath; + /** + * An array that holds the global %CKEditor configuration. + * For the list of available options, see http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.config.html + * + * Example usage: + * @code + * $CKEditor->config['height'] = 400; + * // Use @@ at the beggining of a string to ouput it without surrounding quotes. + * $CKEditor->config['width'] = '@@screen.width * 0.8'; + * @endcode + */ + var $config = array(); + /** + * A boolean variable indicating whether CKEditor has been initialized. + * Set it to true only if you have already included + * <script> tag loading ckeditor.js in your website. + */ + var $initialized = false; + /** + * Boolean variable indicating whether created code should be printed out or returned by a function. + * + * Example 1: get the code creating %CKEditor instance and print it on a page with the "echo" function. + * @code + * $CKEditor = new CKEditor(); + * $CKEditor->returnOutput = true; + * $code = $CKEditor->editor("editor1", "

Initial value.

"); + * echo "

Editor 1:

"; + * echo $code; + * @endcode + */ + var $returnOutput = false; + /** + * An array with textarea attributes. + * + * When %CKEditor is created with the editor() method, a HTML <textarea> element is created, + * it will be displayed to anyone with JavaScript disabled or with incompatible browser. + */ + var $textareaAttributes = array( "rows" => 8, "cols" => 60 ); + /** + * A string indicating the creation date of %CKEditor. + * Do not change it unless you want to force browsers to not use previously cached version of %CKEditor. + */ + var $timestamp = "C6HH5UF"; + /** + * An array that holds event listeners. + * \private + */ + var $_events = array(); + /** + * An array that holds global event listeners. + * \private + */ + var $_globalEvents = array(); + + /** + * Main Constructor. + * + * @param $basePath (string) URL to the %CKEditor installation directory (optional). + */ + function CKEditor($basePath = null) { + if (!empty($basePath)) { + $this->basePath = $basePath; + } + } + + /** + * Creates a %CKEditor instance. + * In incompatible browsers %CKEditor will downgrade to plain HTML <textarea> element. + * + * @param $name (string) Name of the %CKEditor instance (this will be also the "name" attribute of textarea element). + * @param $value (string) Initial value (optional). + * @param $config (array) The specific configurations to apply to this editor instance (optional). + * @param $events (array) Event listeners for this editor instance (optional). + * + * Example usage: + * @code + * $CKEditor = new CKEditor(); + * $CKEditor->editor("field1", "

Initial value.

"); + * @endcode + * + * Advanced example: + * @code + * $CKEditor = new CKEditor(); + * $config = array(); + * $config['toolbar'] = array( + * array( 'Source', '-', 'Bold', 'Italic', 'Underline', 'Strike' ), + * array( 'Image', 'Link', 'Unlink', 'Anchor' ) + * ); + * $events['instanceReady'] = 'function (ev) { + * alert("Loaded: " + ev.editor.name); + * }'; + * $CKEditor->editor("field1", "

Initial value.

", $config, $events); + * @endcode + */ + function editor($name, $value = "", $config = array(), $events = array()) + { + $attr = ""; + foreach ($this->textareaAttributes as $key => $val) { + $attr.= " " . $key . '="' . str_replace('"', '"', $val) . '"'; + } + $out = "\n"; + if (!$this->initialized) { + $out .= $this->init(); + } + + $_config = $this->configSettings($config, $events); + + $js = $this->returnGlobalEvents(); + if (!empty($_config)) + $js .= "CKEDITOR.replace('".$name."', ".$this->jsEncode($_config).");"; + else + $js .= "CKEDITOR.replace('".$name."');"; + + $out .= $this->script($js); + + if (!$this->returnOutput) { + print $out; + $out = ""; + } + + return $out; + } + + /** + * Replaces a <textarea> with a %CKEditor instance. + * + * @param $id (string) The id or name of textarea element. + * @param $config (array) The specific configurations to apply to this editor instance (optional). + * @param $events (array) Event listeners for this editor instance (optional). + * + * Example 1: adding %CKEditor to <textarea name="article"></textarea> element: + * @code + * $CKEditor = new CKEditor(); + * $CKEditor->replace("article"); + * @endcode + */ + function replace($id, $config = array(), $events = array()) + { + $out = ""; + if (!$this->initialized) { + $out .= $this->init(); + } + + $_config = $this->configSettings($config, $events); + + $js = $this->returnGlobalEvents(); + if (!empty($_config)) { + $js .= "CKEDITOR.replace('".$id."', ".$this->jsEncode($_config).");"; + } + else { + $js .= "CKEDITOR.replace('".$id."');"; + } + $out .= $this->script($js); + + if (!$this->returnOutput) { + print $out; + $out = ""; + } + + return $out; + } + + /** + * Replace all <textarea> elements available in the document with editor instances. + * + * @param $className (string) If set, replace all textareas with class className in the page. + * + * Example 1: replace all <textarea> elements in the page. + * @code + * $CKEditor = new CKEditor(); + * $CKEditor->replaceAll(); + * @endcode + * + * Example 2: replace all <textarea class="myClassName"> elements in the page. + * @code + * $CKEditor = new CKEditor(); + * $CKEditor->replaceAll( 'myClassName' ); + * @endcode + */ + function replaceAll($className = null) + { + $out = ""; + if (!$this->initialized) { + $out .= $this->init(); + } + + $_config = $this->configSettings(); + + $js = $this->returnGlobalEvents(); + if (empty($_config)) { + if (empty($className)) { + $js .= "CKEDITOR.replaceAll();"; + } + else { + $js .= "CKEDITOR.replaceAll('".$className."');"; + } + } + else { + $classDetection = ""; + $js .= "CKEDITOR.replaceAll( function(textarea, config) {\n"; + if (!empty($className)) { + $js .= " var classRegex = new RegExp('(?:^| )' + '". $className ."' + '(?:$| )');\n"; + $js .= " if (!classRegex.test(textarea.className))\n"; + $js .= " return false;\n"; + } + $js .= " CKEDITOR.tools.extend(config, ". $this->jsEncode($_config) .", true);"; + $js .= "} );"; + + } + + $out .= $this->script($js); + + if (!$this->returnOutput) { + print $out; + $out = ""; + } + + return $out; + } + + /** + * Adds event listener. + * Events are fired by %CKEditor in various situations. + * + * @param $event (string) Event name. + * @param $javascriptCode (string) Javascript anonymous function or function name. + * + * Example usage: + * @code + * $CKEditor->addEventHandler('instanceReady', 'function (ev) { + * alert("Loaded: " + ev.editor.name); + * }'); + * @endcode + */ + function addEventHandler($event, $javascriptCode) + { + if (!isset($this->_events[$event])) { + $this->_events[$event] = array(); + } + // Avoid duplicates. + if (!in_array($javascriptCode, $this->_events[$event])) { + $this->_events[$event][] = $javascriptCode; + } + } + + /** + * Clear registered event handlers. + * Note: this function will have no effect on already created editor instances. + * + * @param $event (string) Event name, if not set all event handlers will be removed (optional). + */ + function clearEventHandlers($event = null) + { + if (!empty($event)) { + $this->_events[$event] = array(); + } + else { + $this->_events = array(); + } + } + + /** + * Adds global event listener. + * + * @param $event (string) Event name. + * @param $javascriptCode (string) Javascript anonymous function or function name. + * + * Example usage: + * @code + * $CKEditor->addGlobalEventHandler('dialogDefinition', 'function (ev) { + * alert("Loading dialog: " + ev.data.name); + * }'); + * @endcode + */ + function addGlobalEventHandler($event, $javascriptCode) + { + if (!isset($this->_globalEvents[$event])) { + $this->_globalEvents[$event] = array(); + } + // Avoid duplicates. + if (!in_array($javascriptCode, $this->_globalEvents[$event])) { + $this->_globalEvents[$event][] = $javascriptCode; + } + } + + /** + * Clear registered global event handlers. + * Note: this function will have no effect if the event handler has been already printed/returned. + * + * @param $event (string) Event name, if not set all event handlers will be removed (optional). + */ + function clearGlobalEventHandlers($event = null) + { + if (!empty($event)) { + $this->_globalEvents[$event] = array(); + } + else { + $this->_globalEvents = array(); + } + } + + /** + * Prints javascript code. + * \private + * + * @param string $js + */ + function script($js) + { + $out = "\n"; + + return $out; + } + + /** + * Returns the configuration array (global and instance specific settings are merged into one array). + * \private + * + * @param $config (array) The specific configurations to apply to editor instance. + * @param $events (array) Event listeners for editor instance. + */ + function configSettings($config = array(), $events = array()) + { + $_config = $this->config; + $_events = $this->_events; + + if (is_array($config) && !empty($config)) { + $_config = array_merge($_config, $config); + } + + if (is_array($events) && !empty($events)) { + foreach ($events as $eventName => $code) { + if (!isset($_events[$eventName])) { + $_events[$eventName] = array(); + } + if (!in_array($code, $_events[$eventName])) { + $_events[$eventName][] = $code; + } + } + } + + if (!empty($_events)) { + foreach($_events as $eventName => $handlers) { + if (empty($handlers)) { + continue; + } + else if (count($handlers) == 1) { + $_config['on'][$eventName] = '@@'.$handlers[0]; + } + else { + $_config['on'][$eventName] = '@@function (ev){'; + foreach ($handlers as $handler => $code) { + $_config['on'][$eventName] .= '('.$code.')(ev);'; + } + $_config['on'][$eventName] .= '}'; + } + } + } + + return $_config; + } + + /** + * Return global event handlers. + * \private + */ + function returnGlobalEvents() + { + static $returnedEvents; + $out = ""; + + if (!isset($returnedEvents)) { + $returnedEvents = array(); + } + + if (!empty($this->_globalEvents)) { + foreach ($this->_globalEvents as $eventName => $handlers) { + foreach ($handlers as $handler => $code) { + if (!isset($returnedEvents[$eventName])) { + $returnedEvents[$eventName] = array(); + } + // Return only new events + if (!in_array($code, $returnedEvents[$eventName])) { + $out .= ($code ? "\n" : "") . "CKEDITOR.on('". $eventName ."', $code);"; + $returnedEvents[$eventName][] = $code; + } + } + } + } + + return $out; + } + + /** + * Initializes CKEditor (executed only once). + * \private + */ + function init() + { + static $initComplete; + $out = ""; + + if (!empty($initComplete)) { + return ""; + } + + if ($this->initialized) { + $initComplete = true; + return ""; + } + + $args = ""; + $ckeditorPath = $this->ckeditorPath(); + + if (!empty($this->timestamp) && $this->timestamp != "%"."TIMESTAMP%") { + $args = '?t=' . $this->timestamp; + } + + // Skip relative paths... + if (strpos($ckeditorPath, '..') !== 0) { + $out .= $this->script("window.CKEDITOR_BASEPATH='". $ckeditorPath ."';"); + } + + $out .= "\n"; + + $extraCode = ""; + if ($this->timestamp != $this->_timestamp) { + $extraCode .= ($extraCode ? "\n" : "") . "CKEDITOR.timestamp = '". $this->timestamp ."';"; + } + if ($extraCode) { + $out .= $this->script($extraCode); + } + + $initComplete = $this->initialized = true; + + return $out; + } + + /** + * Return path to ckeditor.js. + * \private + */ + function ckeditorPath() + { + if (!empty($this->basePath)) { + return $this->basePath; + } + + /** + * The absolute pathname of the currently executing script. + * Note: If a script is executed with the CLI, as a relative path, such as file.php or ../file.php, + * $_SERVER['SCRIPT_FILENAME'] will contain the relative path specified by the user. + */ + if (isset($_SERVER['SCRIPT_FILENAME'])) { + $realPath = dirname($_SERVER['SCRIPT_FILENAME']); + } + else { + /** + * realpath - Returns canonicalized absolute pathname + */ + $realPath = realpath( './' ) ; + } + + /** + * The filename of the currently executing script, relative to the document root. + * For instance, $_SERVER['PHP_SELF'] in a script at the address http://example.com/test.php/foo.bar + * would be /test.php/foo.bar. + */ + $selfPath = dirname($_SERVER['PHP_SELF']); + $file = str_replace("\\", "/", __FILE__); + + if (!$selfPath || !$realPath || !$file) { + return "/ckeditor/"; + } + + $documentRoot = substr($realPath, 0, strlen($realPath) - strlen($selfPath)); + $fileUrl = substr($file, strlen($documentRoot)); + $ckeditorUrl = str_replace("ckeditor_php4.php", "", $fileUrl); + + return $ckeditorUrl; + } + + /** + * This little function provides a basic JSON support. + * \private + * + * @param mixed $val + * @return string + */ + function jsEncode($val) + { + if (is_null($val)) { + return 'null'; + } + if (is_bool($val)) { + return $val ? 'true' : 'false'; + } + if (is_int($val)) { + return $val; + } + if (is_float($val)) { + return str_replace(',', '.', $val); + } + if (is_array($val) || is_object($val)) { + if (is_array($val) && (array_keys($val) === range(0,count($val)-1))) { + return '[' . implode(',', array_map(array($this, 'jsEncode'), $val)) . ']'; + } + $temp = array(); + foreach ($val as $k => $v){ + $temp[] = $this->jsEncode("{$k}") . ':' . $this->jsEncode($v); + } + return '{' . implode(',', $temp) . '}'; + } + // String otherwise + if (strpos($val, '@@') === 0) + return substr($val, 2); + if (strtoupper(substr($val, 0, 9)) == 'CKEDITOR.') + return $val; + + return '"' . str_replace(array("\\", "/", "\n", "\t", "\r", "\x08", "\x0c", '"'), array('\\\\', '\\/', '\\n', '\\t', '\\r', '\\b', '\\f', '\"'), $val) . '"'; + } +} diff --git a/htdocs/includes/ckeditor/ckeditor_php5.php b/htdocs/includes/ckeditor/ckeditor_php5.php index 122fe7abfe2..5596d6745c8 100644 --- a/htdocs/includes/ckeditor/ckeditor_php5.php +++ b/htdocs/includes/ckeditor/ckeditor_php5.php @@ -1,556 +1,556 @@ -editor("editor1", "

Initial value.

"); - * @endcode - */ -class CKEditor -{ - /** - * The version of %CKEditor. - */ - const version = '3.6.4'; - /** - * A constant string unique for each release of %CKEditor. - */ - const timestamp = 'C6HH5UF'; - - /** - * URL to the %CKEditor installation directory (absolute or relative to document root). - * If not set, CKEditor will try to guess it's path. - * - * Example usage: - * @code - * $CKEditor->basePath = '/ckeditor/'; - * @endcode - */ - public $basePath; - /** - * An array that holds the global %CKEditor configuration. - * For the list of available options, see http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.config.html - * - * Example usage: - * @code - * $CKEditor->config['height'] = 400; - * // Use @@ at the beggining of a string to ouput it without surrounding quotes. - * $CKEditor->config['width'] = '@@screen.width * 0.8'; - * @endcode - */ - public $config = array(); - /** - * A boolean variable indicating whether CKEditor has been initialized. - * Set it to true only if you have already included - * <script> tag loading ckeditor.js in your website. - */ - public $initialized = false; - /** - * Boolean variable indicating whether created code should be printed out or returned by a function. - * - * Example 1: get the code creating %CKEditor instance and print it on a page with the "echo" function. - * @code - * $CKEditor = new CKEditor(); - * $CKEditor->returnOutput = true; - * $code = $CKEditor->editor("editor1", "

Initial value.

"); - * echo "

Editor 1:

"; - * echo $code; - * @endcode - */ - public $returnOutput = false; - /** - * An array with textarea attributes. - * - * When %CKEditor is created with the editor() method, a HTML <textarea> element is created, - * it will be displayed to anyone with JavaScript disabled or with incompatible browser. - */ - public $textareaAttributes = array( "rows" => 8, "cols" => 60 ); - /** - * A string indicating the creation date of %CKEditor. - * Do not change it unless you want to force browsers to not use previously cached version of %CKEditor. - */ - public $timestamp = "C6HH5UF"; - /** - * An array that holds event listeners. - */ - private $events = array(); - /** - * An array that holds global event listeners. - */ - private $globalEvents = array(); - - /** - * Main Constructor. - * - * @param $basePath (string) URL to the %CKEditor installation directory (optional). - */ - function __construct($basePath = null) { - if (!empty($basePath)) { - $this->basePath = $basePath; - } - } - - /** - * Creates a %CKEditor instance. - * In incompatible browsers %CKEditor will downgrade to plain HTML <textarea> element. - * - * @param $name (string) Name of the %CKEditor instance (this will be also the "name" attribute of textarea element). - * @param $value (string) Initial value (optional). - * @param $config (array) The specific configurations to apply to this editor instance (optional). - * @param $events (array) Event listeners for this editor instance (optional). - * - * Example usage: - * @code - * $CKEditor = new CKEditor(); - * $CKEditor->editor("field1", "

Initial value.

"); - * @endcode - * - * Advanced example: - * @code - * $CKEditor = new CKEditor(); - * $config = array(); - * $config['toolbar'] = array( - * array( 'Source', '-', 'Bold', 'Italic', 'Underline', 'Strike' ), - * array( 'Image', 'Link', 'Unlink', 'Anchor' ) - * ); - * $events['instanceReady'] = 'function (ev) { - * alert("Loaded: " + ev.editor.name); - * }'; - * $CKEditor->editor("field1", "

Initial value.

", $config, $events); - * @endcode - */ - public function editor($name, $value = "", $config = array(), $events = array()) - { - $attr = ""; - foreach ($this->textareaAttributes as $key => $val) { - $attr.= " " . $key . '="' . str_replace('"', '"', $val) . '"'; - } - $out = "\n"; - if (!$this->initialized) { - $out .= $this->init(); - } - - $_config = $this->configSettings($config, $events); - - $js = $this->returnGlobalEvents(); - if (!empty($_config)) - $js .= "CKEDITOR.replace('".$name."', ".$this->jsEncode($_config).");"; - else - $js .= "CKEDITOR.replace('".$name."');"; - - $out .= $this->script($js); - - if (!$this->returnOutput) { - print $out; - $out = ""; - } - - return $out; - } - - /** - * Replaces a <textarea> with a %CKEditor instance. - * - * @param $id (string) The id or name of textarea element. - * @param $config (array) The specific configurations to apply to this editor instance (optional). - * @param $events (array) Event listeners for this editor instance (optional). - * - * Example 1: adding %CKEditor to <textarea name="article"></textarea> element: - * @code - * $CKEditor = new CKEditor(); - * $CKEditor->replace("article"); - * @endcode - */ - public function replace($id, $config = array(), $events = array()) - { - $out = ""; - if (!$this->initialized) { - $out .= $this->init(); - } - - $_config = $this->configSettings($config, $events); - - $js = $this->returnGlobalEvents(); - if (!empty($_config)) { - $js .= "CKEDITOR.replace('".$id."', ".$this->jsEncode($_config).");"; - } - else { - $js .= "CKEDITOR.replace('".$id."');"; - } - $out .= $this->script($js); - - if (!$this->returnOutput) { - print $out; - $out = ""; - } - - return $out; - } - - /** - * Replace all <textarea> elements available in the document with editor instances. - * - * @param $className (string) If set, replace all textareas with class className in the page. - * - * Example 1: replace all <textarea> elements in the page. - * @code - * $CKEditor = new CKEditor(); - * $CKEditor->replaceAll(); - * @endcode - * - * Example 2: replace all <textarea class="myClassName"> elements in the page. - * @code - * $CKEditor = new CKEditor(); - * $CKEditor->replaceAll( 'myClassName' ); - * @endcode - */ - public function replaceAll($className = null) - { - $out = ""; - if (!$this->initialized) { - $out .= $this->init(); - } - - $_config = $this->configSettings(); - - $js = $this->returnGlobalEvents(); - if (empty($_config)) { - if (empty($className)) { - $js .= "CKEDITOR.replaceAll();"; - } - else { - $js .= "CKEDITOR.replaceAll('".$className."');"; - } - } - else { - $classDetection = ""; - $js .= "CKEDITOR.replaceAll( function(textarea, config) {\n"; - if (!empty($className)) { - $js .= " var classRegex = new RegExp('(?:^| )' + '". $className ."' + '(?:$| )');\n"; - $js .= " if (!classRegex.test(textarea.className))\n"; - $js .= " return false;\n"; - } - $js .= " CKEDITOR.tools.extend(config, ". $this->jsEncode($_config) .", true);"; - $js .= "} );"; - - } - - $out .= $this->script($js); - - if (!$this->returnOutput) { - print $out; - $out = ""; - } - - return $out; - } - - /** - * Adds event listener. - * Events are fired by %CKEditor in various situations. - * - * @param $event (string) Event name. - * @param $javascriptCode (string) Javascript anonymous function or function name. - * - * Example usage: - * @code - * $CKEditor->addEventHandler('instanceReady', 'function (ev) { - * alert("Loaded: " + ev.editor.name); - * }'); - * @endcode - */ - public function addEventHandler($event, $javascriptCode) - { - if (!isset($this->events[$event])) { - $this->events[$event] = array(); - } - // Avoid duplicates. - if (!in_array($javascriptCode, $this->events[$event])) { - $this->events[$event][] = $javascriptCode; - } - } - - /** - * Clear registered event handlers. - * Note: this function will have no effect on already created editor instances. - * - * @param $event (string) Event name, if not set all event handlers will be removed (optional). - */ - public function clearEventHandlers($event = null) - { - if (!empty($event)) { - $this->events[$event] = array(); - } - else { - $this->events = array(); - } - } - - /** - * Adds global event listener. - * - * @param $event (string) Event name. - * @param $javascriptCode (string) Javascript anonymous function or function name. - * - * Example usage: - * @code - * $CKEditor->addGlobalEventHandler('dialogDefinition', 'function (ev) { - * alert("Loading dialog: " + ev.data.name); - * }'); - * @endcode - */ - public function addGlobalEventHandler($event, $javascriptCode) - { - if (!isset($this->globalEvents[$event])) { - $this->globalEvents[$event] = array(); - } - // Avoid duplicates. - if (!in_array($javascriptCode, $this->globalEvents[$event])) { - $this->globalEvents[$event][] = $javascriptCode; - } - } - - /** - * Clear registered global event handlers. - * Note: this function will have no effect if the event handler has been already printed/returned. - * - * @param $event (string) Event name, if not set all event handlers will be removed (optional). - */ - public function clearGlobalEventHandlers($event = null) - { - if (!empty($event)) { - $this->globalEvents[$event] = array(); - } - else { - $this->globalEvents = array(); - } - } - - /** - * Prints javascript code. - * - * @param string $js - */ - private function script($js) - { - $out = "\n"; - - return $out; - } - - /** - * Returns the configuration array (global and instance specific settings are merged into one array). - * - * @param $config (array) The specific configurations to apply to editor instance. - * @param $events (array) Event listeners for editor instance. - */ - private function configSettings($config = array(), $events = array()) - { - $_config = $this->config; - $_events = $this->events; - - if (is_array($config) && !empty($config)) { - $_config = array_merge($_config, $config); - } - - if (is_array($events) && !empty($events)) { - foreach ($events as $eventName => $code) { - if (!isset($_events[$eventName])) { - $_events[$eventName] = array(); - } - if (!in_array($code, $_events[$eventName])) { - $_events[$eventName][] = $code; - } - } - } - - if (!empty($_events)) { - foreach($_events as $eventName => $handlers) { - if (empty($handlers)) { - continue; - } - else if (count($handlers) == 1) { - $_config['on'][$eventName] = '@@'.$handlers[0]; - } - else { - $_config['on'][$eventName] = '@@function (ev){'; - foreach ($handlers as $handler => $code) { - $_config['on'][$eventName] .= '('.$code.')(ev);'; - } - $_config['on'][$eventName] .= '}'; - } - } - } - - return $_config; - } - - /** - * Return global event handlers. - */ - private function returnGlobalEvents() - { - static $returnedEvents; - $out = ""; - - if (!isset($returnedEvents)) { - $returnedEvents = array(); - } - - if (!empty($this->globalEvents)) { - foreach ($this->globalEvents as $eventName => $handlers) { - foreach ($handlers as $handler => $code) { - if (!isset($returnedEvents[$eventName])) { - $returnedEvents[$eventName] = array(); - } - // Return only new events - if (!in_array($code, $returnedEvents[$eventName])) { - $out .= ($code ? "\n" : "") . "CKEDITOR.on('". $eventName ."', $code);"; - $returnedEvents[$eventName][] = $code; - } - } - } - } - - return $out; - } - - /** - * Initializes CKEditor (executed only once). - */ - private function init() - { - static $initComplete; - $out = ""; - - if (!empty($initComplete)) { - return ""; - } - - if ($this->initialized) { - $initComplete = true; - return ""; - } - - $args = ""; - $ckeditorPath = $this->ckeditorPath(); - - if (!empty($this->timestamp) && $this->timestamp != "%"."TIMESTAMP%") { - $args = '?t=' . $this->timestamp; - } - - // Skip relative paths... - if (strpos($ckeditorPath, '..') !== 0) { - $out .= $this->script("window.CKEDITOR_BASEPATH='". $ckeditorPath ."';"); - } - - $out .= "\n"; - - $extraCode = ""; - if ($this->timestamp != self::timestamp) { - $extraCode .= ($extraCode ? "\n" : "") . "CKEDITOR.timestamp = '". $this->timestamp ."';"; - } - if ($extraCode) { - $out .= $this->script($extraCode); - } - - $initComplete = $this->initialized = true; - - return $out; - } - - /** - * Return path to ckeditor.js. - */ - private function ckeditorPath() - { - if (!empty($this->basePath)) { - return $this->basePath; - } - - /** - * The absolute pathname of the currently executing script. - * Note: If a script is executed with the CLI, as a relative path, such as file.php or ../file.php, - * $_SERVER['SCRIPT_FILENAME'] will contain the relative path specified by the user. - */ - if (isset($_SERVER['SCRIPT_FILENAME'])) { - $realPath = dirname($_SERVER['SCRIPT_FILENAME']); - } - else { - /** - * realpath - Returns canonicalized absolute pathname - */ - $realPath = realpath( './' ) ; - } - - /** - * The filename of the currently executing script, relative to the document root. - * For instance, $_SERVER['PHP_SELF'] in a script at the address http://example.com/test.php/foo.bar - * would be /test.php/foo.bar. - */ - $selfPath = dirname($_SERVER['PHP_SELF']); - $file = str_replace("\\", "/", __FILE__); - - if (!$selfPath || !$realPath || !$file) { - return "/ckeditor/"; - } - - $documentRoot = substr($realPath, 0, strlen($realPath) - strlen($selfPath)); - $fileUrl = substr($file, strlen($documentRoot)); - $ckeditorUrl = str_replace("ckeditor_php5.php", "", $fileUrl); - - return $ckeditorUrl; - } - - /** - * This little function provides a basic JSON support. - * - * @param mixed $val - * @return string - */ - private function jsEncode($val) - { - if (is_null($val)) { - return 'null'; - } - if (is_bool($val)) { - return $val ? 'true' : 'false'; - } - if (is_int($val)) { - return $val; - } - if (is_float($val)) { - return str_replace(',', '.', $val); - } - if (is_array($val) || is_object($val)) { - if (is_array($val) && (array_keys($val) === range(0,count($val)-1))) { - return '[' . implode(',', array_map(array($this, 'jsEncode'), $val)) . ']'; - } - $temp = array(); - foreach ($val as $k => $v){ - $temp[] = $this->jsEncode("{$k}") . ':' . $this->jsEncode($v); - } - return '{' . implode(',', $temp) . '}'; - } - // String otherwise - if (strpos($val, '@@') === 0) - return substr($val, 2); - if (strtoupper(substr($val, 0, 9)) == 'CKEDITOR.') - return $val; - - return '"' . str_replace(array("\\", "/", "\n", "\t", "\r", "\x08", "\x0c", '"'), array('\\\\', '\\/', '\\n', '\\t', '\\r', '\\b', '\\f', '\"'), $val) . '"'; - } -} +editor("editor1", "

Initial value.

"); + * @endcode + */ +class CKEditor +{ + /** + * The version of %CKEditor. + */ + const version = '3.6.4'; + /** + * A constant string unique for each release of %CKEditor. + */ + const timestamp = 'C6HH5UF'; + + /** + * URL to the %CKEditor installation directory (absolute or relative to document root). + * If not set, CKEditor will try to guess it's path. + * + * Example usage: + * @code + * $CKEditor->basePath = '/ckeditor/'; + * @endcode + */ + public $basePath; + /** + * An array that holds the global %CKEditor configuration. + * For the list of available options, see http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.config.html + * + * Example usage: + * @code + * $CKEditor->config['height'] = 400; + * // Use @@ at the beggining of a string to ouput it without surrounding quotes. + * $CKEditor->config['width'] = '@@screen.width * 0.8'; + * @endcode + */ + public $config = array(); + /** + * A boolean variable indicating whether CKEditor has been initialized. + * Set it to true only if you have already included + * <script> tag loading ckeditor.js in your website. + */ + public $initialized = false; + /** + * Boolean variable indicating whether created code should be printed out or returned by a function. + * + * Example 1: get the code creating %CKEditor instance and print it on a page with the "echo" function. + * @code + * $CKEditor = new CKEditor(); + * $CKEditor->returnOutput = true; + * $code = $CKEditor->editor("editor1", "

Initial value.

"); + * echo "

Editor 1:

"; + * echo $code; + * @endcode + */ + public $returnOutput = false; + /** + * An array with textarea attributes. + * + * When %CKEditor is created with the editor() method, a HTML <textarea> element is created, + * it will be displayed to anyone with JavaScript disabled or with incompatible browser. + */ + public $textareaAttributes = array( "rows" => 8, "cols" => 60 ); + /** + * A string indicating the creation date of %CKEditor. + * Do not change it unless you want to force browsers to not use previously cached version of %CKEditor. + */ + public $timestamp = "C6HH5UF"; + /** + * An array that holds event listeners. + */ + private $events = array(); + /** + * An array that holds global event listeners. + */ + private $globalEvents = array(); + + /** + * Main Constructor. + * + * @param $basePath (string) URL to the %CKEditor installation directory (optional). + */ + function __construct($basePath = null) { + if (!empty($basePath)) { + $this->basePath = $basePath; + } + } + + /** + * Creates a %CKEditor instance. + * In incompatible browsers %CKEditor will downgrade to plain HTML <textarea> element. + * + * @param $name (string) Name of the %CKEditor instance (this will be also the "name" attribute of textarea element). + * @param $value (string) Initial value (optional). + * @param $config (array) The specific configurations to apply to this editor instance (optional). + * @param $events (array) Event listeners for this editor instance (optional). + * + * Example usage: + * @code + * $CKEditor = new CKEditor(); + * $CKEditor->editor("field1", "

Initial value.

"); + * @endcode + * + * Advanced example: + * @code + * $CKEditor = new CKEditor(); + * $config = array(); + * $config['toolbar'] = array( + * array( 'Source', '-', 'Bold', 'Italic', 'Underline', 'Strike' ), + * array( 'Image', 'Link', 'Unlink', 'Anchor' ) + * ); + * $events['instanceReady'] = 'function (ev) { + * alert("Loaded: " + ev.editor.name); + * }'; + * $CKEditor->editor("field1", "

Initial value.

", $config, $events); + * @endcode + */ + public function editor($name, $value = "", $config = array(), $events = array()) + { + $attr = ""; + foreach ($this->textareaAttributes as $key => $val) { + $attr.= " " . $key . '="' . str_replace('"', '"', $val) . '"'; + } + $out = "\n"; + if (!$this->initialized) { + $out .= $this->init(); + } + + $_config = $this->configSettings($config, $events); + + $js = $this->returnGlobalEvents(); + if (!empty($_config)) + $js .= "CKEDITOR.replace('".$name."', ".$this->jsEncode($_config).");"; + else + $js .= "CKEDITOR.replace('".$name."');"; + + $out .= $this->script($js); + + if (!$this->returnOutput) { + print $out; + $out = ""; + } + + return $out; + } + + /** + * Replaces a <textarea> with a %CKEditor instance. + * + * @param $id (string) The id or name of textarea element. + * @param $config (array) The specific configurations to apply to this editor instance (optional). + * @param $events (array) Event listeners for this editor instance (optional). + * + * Example 1: adding %CKEditor to <textarea name="article"></textarea> element: + * @code + * $CKEditor = new CKEditor(); + * $CKEditor->replace("article"); + * @endcode + */ + public function replace($id, $config = array(), $events = array()) + { + $out = ""; + if (!$this->initialized) { + $out .= $this->init(); + } + + $_config = $this->configSettings($config, $events); + + $js = $this->returnGlobalEvents(); + if (!empty($_config)) { + $js .= "CKEDITOR.replace('".$id."', ".$this->jsEncode($_config).");"; + } + else { + $js .= "CKEDITOR.replace('".$id."');"; + } + $out .= $this->script($js); + + if (!$this->returnOutput) { + print $out; + $out = ""; + } + + return $out; + } + + /** + * Replace all <textarea> elements available in the document with editor instances. + * + * @param $className (string) If set, replace all textareas with class className in the page. + * + * Example 1: replace all <textarea> elements in the page. + * @code + * $CKEditor = new CKEditor(); + * $CKEditor->replaceAll(); + * @endcode + * + * Example 2: replace all <textarea class="myClassName"> elements in the page. + * @code + * $CKEditor = new CKEditor(); + * $CKEditor->replaceAll( 'myClassName' ); + * @endcode + */ + public function replaceAll($className = null) + { + $out = ""; + if (!$this->initialized) { + $out .= $this->init(); + } + + $_config = $this->configSettings(); + + $js = $this->returnGlobalEvents(); + if (empty($_config)) { + if (empty($className)) { + $js .= "CKEDITOR.replaceAll();"; + } + else { + $js .= "CKEDITOR.replaceAll('".$className."');"; + } + } + else { + $classDetection = ""; + $js .= "CKEDITOR.replaceAll( function(textarea, config) {\n"; + if (!empty($className)) { + $js .= " var classRegex = new RegExp('(?:^| )' + '". $className ."' + '(?:$| )');\n"; + $js .= " if (!classRegex.test(textarea.className))\n"; + $js .= " return false;\n"; + } + $js .= " CKEDITOR.tools.extend(config, ". $this->jsEncode($_config) .", true);"; + $js .= "} );"; + + } + + $out .= $this->script($js); + + if (!$this->returnOutput) { + print $out; + $out = ""; + } + + return $out; + } + + /** + * Adds event listener. + * Events are fired by %CKEditor in various situations. + * + * @param $event (string) Event name. + * @param $javascriptCode (string) Javascript anonymous function or function name. + * + * Example usage: + * @code + * $CKEditor->addEventHandler('instanceReady', 'function (ev) { + * alert("Loaded: " + ev.editor.name); + * }'); + * @endcode + */ + public function addEventHandler($event, $javascriptCode) + { + if (!isset($this->events[$event])) { + $this->events[$event] = array(); + } + // Avoid duplicates. + if (!in_array($javascriptCode, $this->events[$event])) { + $this->events[$event][] = $javascriptCode; + } + } + + /** + * Clear registered event handlers. + * Note: this function will have no effect on already created editor instances. + * + * @param $event (string) Event name, if not set all event handlers will be removed (optional). + */ + public function clearEventHandlers($event = null) + { + if (!empty($event)) { + $this->events[$event] = array(); + } + else { + $this->events = array(); + } + } + + /** + * Adds global event listener. + * + * @param $event (string) Event name. + * @param $javascriptCode (string) Javascript anonymous function or function name. + * + * Example usage: + * @code + * $CKEditor->addGlobalEventHandler('dialogDefinition', 'function (ev) { + * alert("Loading dialog: " + ev.data.name); + * }'); + * @endcode + */ + public function addGlobalEventHandler($event, $javascriptCode) + { + if (!isset($this->globalEvents[$event])) { + $this->globalEvents[$event] = array(); + } + // Avoid duplicates. + if (!in_array($javascriptCode, $this->globalEvents[$event])) { + $this->globalEvents[$event][] = $javascriptCode; + } + } + + /** + * Clear registered global event handlers. + * Note: this function will have no effect if the event handler has been already printed/returned. + * + * @param $event (string) Event name, if not set all event handlers will be removed (optional). + */ + public function clearGlobalEventHandlers($event = null) + { + if (!empty($event)) { + $this->globalEvents[$event] = array(); + } + else { + $this->globalEvents = array(); + } + } + + /** + * Prints javascript code. + * + * @param string $js + */ + private function script($js) + { + $out = "\n"; + + return $out; + } + + /** + * Returns the configuration array (global and instance specific settings are merged into one array). + * + * @param $config (array) The specific configurations to apply to editor instance. + * @param $events (array) Event listeners for editor instance. + */ + private function configSettings($config = array(), $events = array()) + { + $_config = $this->config; + $_events = $this->events; + + if (is_array($config) && !empty($config)) { + $_config = array_merge($_config, $config); + } + + if (is_array($events) && !empty($events)) { + foreach ($events as $eventName => $code) { + if (!isset($_events[$eventName])) { + $_events[$eventName] = array(); + } + if (!in_array($code, $_events[$eventName])) { + $_events[$eventName][] = $code; + } + } + } + + if (!empty($_events)) { + foreach($_events as $eventName => $handlers) { + if (empty($handlers)) { + continue; + } + else if (count($handlers) == 1) { + $_config['on'][$eventName] = '@@'.$handlers[0]; + } + else { + $_config['on'][$eventName] = '@@function (ev){'; + foreach ($handlers as $handler => $code) { + $_config['on'][$eventName] .= '('.$code.')(ev);'; + } + $_config['on'][$eventName] .= '}'; + } + } + } + + return $_config; + } + + /** + * Return global event handlers. + */ + private function returnGlobalEvents() + { + static $returnedEvents; + $out = ""; + + if (!isset($returnedEvents)) { + $returnedEvents = array(); + } + + if (!empty($this->globalEvents)) { + foreach ($this->globalEvents as $eventName => $handlers) { + foreach ($handlers as $handler => $code) { + if (!isset($returnedEvents[$eventName])) { + $returnedEvents[$eventName] = array(); + } + // Return only new events + if (!in_array($code, $returnedEvents[$eventName])) { + $out .= ($code ? "\n" : "") . "CKEDITOR.on('". $eventName ."', $code);"; + $returnedEvents[$eventName][] = $code; + } + } + } + } + + return $out; + } + + /** + * Initializes CKEditor (executed only once). + */ + private function init() + { + static $initComplete; + $out = ""; + + if (!empty($initComplete)) { + return ""; + } + + if ($this->initialized) { + $initComplete = true; + return ""; + } + + $args = ""; + $ckeditorPath = $this->ckeditorPath(); + + if (!empty($this->timestamp) && $this->timestamp != "%"."TIMESTAMP%") { + $args = '?t=' . $this->timestamp; + } + + // Skip relative paths... + if (strpos($ckeditorPath, '..') !== 0) { + $out .= $this->script("window.CKEDITOR_BASEPATH='". $ckeditorPath ."';"); + } + + $out .= "\n"; + + $extraCode = ""; + if ($this->timestamp != self::timestamp) { + $extraCode .= ($extraCode ? "\n" : "") . "CKEDITOR.timestamp = '". $this->timestamp ."';"; + } + if ($extraCode) { + $out .= $this->script($extraCode); + } + + $initComplete = $this->initialized = true; + + return $out; + } + + /** + * Return path to ckeditor.js. + */ + private function ckeditorPath() + { + if (!empty($this->basePath)) { + return $this->basePath; + } + + /** + * The absolute pathname of the currently executing script. + * Note: If a script is executed with the CLI, as a relative path, such as file.php or ../file.php, + * $_SERVER['SCRIPT_FILENAME'] will contain the relative path specified by the user. + */ + if (isset($_SERVER['SCRIPT_FILENAME'])) { + $realPath = dirname($_SERVER['SCRIPT_FILENAME']); + } + else { + /** + * realpath - Returns canonicalized absolute pathname + */ + $realPath = realpath( './' ) ; + } + + /** + * The filename of the currently executing script, relative to the document root. + * For instance, $_SERVER['PHP_SELF'] in a script at the address http://example.com/test.php/foo.bar + * would be /test.php/foo.bar. + */ + $selfPath = dirname($_SERVER['PHP_SELF']); + $file = str_replace("\\", "/", __FILE__); + + if (!$selfPath || !$realPath || !$file) { + return "/ckeditor/"; + } + + $documentRoot = substr($realPath, 0, strlen($realPath) - strlen($selfPath)); + $fileUrl = substr($file, strlen($documentRoot)); + $ckeditorUrl = str_replace("ckeditor_php5.php", "", $fileUrl); + + return $ckeditorUrl; + } + + /** + * This little function provides a basic JSON support. + * + * @param mixed $val + * @return string + */ + private function jsEncode($val) + { + if (is_null($val)) { + return 'null'; + } + if (is_bool($val)) { + return $val ? 'true' : 'false'; + } + if (is_int($val)) { + return $val; + } + if (is_float($val)) { + return str_replace(',', '.', $val); + } + if (is_array($val) || is_object($val)) { + if (is_array($val) && (array_keys($val) === range(0,count($val)-1))) { + return '[' . implode(',', array_map(array($this, 'jsEncode'), $val)) . ']'; + } + $temp = array(); + foreach ($val as $k => $v){ + $temp[] = $this->jsEncode("{$k}") . ':' . $this->jsEncode($v); + } + return '{' . implode(',', $temp) . '}'; + } + // String otherwise + if (strpos($val, '@@') === 0) + return substr($val, 2); + if (strtoupper(substr($val, 0, 9)) == 'CKEDITOR.') + return $val; + + return '"' . str_replace(array("\\", "/", "\n", "\t", "\r", "\x08", "\x0c", '"'), array('\\\\', '\\/', '\\n', '\\t', '\\r', '\\b', '\\f', '\"'), $val) . '"'; + } +} diff --git a/htdocs/includes/fpdfi/filters/FilterASCII85_FPDI.php b/htdocs/includes/fpdfi/filters/FilterASCII85_FPDI.php index fb5600116bc..d672d584f70 100755 --- a/htdocs/includes/fpdfi/filters/FilterASCII85_FPDI.php +++ b/htdocs/includes/fpdfi/filters/FilterASCII85_FPDI.php @@ -1,33 +1,33 @@ -fpdi =& $fpdi; - } - - function error($msg) { - $this->fpdi->error($msg); - } +fpdi =& $fpdi; + } + + function error($msg) { + $this->fpdi->error($msg); + } } \ No newline at end of file diff --git a/htdocs/includes/fpdfi/filters/FilterLZW_FPDI.php b/htdocs/includes/fpdfi/filters/FilterLZW_FPDI.php index e7a88119ff9..13ff1eb8e82 100755 --- a/htdocs/includes/fpdfi/filters/FilterLZW_FPDI.php +++ b/htdocs/includes/fpdfi/filters/FilterLZW_FPDI.php @@ -1,33 +1,33 @@ -fpdi =& $fpdi; - } - - function error($msg) { - $this->fpdi->error($msg); - } +fpdi =& $fpdi; + } + + function error($msg) { + $this->fpdi->error($msg); + } } \ No newline at end of file diff --git a/htdocs/includes/fpdfi/fpdf_tpl.php b/htdocs/includes/fpdfi/fpdf_tpl.php index d21743e6374..6e234bf9321 100755 --- a/htdocs/includes/fpdfi/fpdf_tpl.php +++ b/htdocs/includes/fpdfi/fpdf_tpl.php @@ -1,449 +1,449 @@ -Error('This method is only usable with FPDF. Use TCPDF methods startTemplate() instead.'); - return; - } - - if ($this->page <= 0) - $this->error("You have to add a page to fpdf first!"); - - if ($x == null) - $x = 0; - if ($y == null) - $y = 0; - if ($w == null) - $w = $this->w; - if ($h == null) - $h = $this->h; - - // Save settings - $this->tpl++; - $tpl =& $this->tpls[$this->tpl]; - $tpl = array( - 'o_x' => $this->x, - 'o_y' => $this->y, - 'o_AutoPageBreak' => $this->AutoPageBreak, - 'o_bMargin' => $this->bMargin, - 'o_tMargin' => $this->tMargin, - 'o_lMargin' => $this->lMargin, - 'o_rMargin' => $this->rMargin, - 'o_h' => $this->h, - 'o_w' => $this->w, - 'buffer' => '', - 'x' => $x, - 'y' => $y, - 'w' => $w, - 'h' => $h - ); - - $this->SetAutoPageBreak(false); - - // Define own high and width to calculate possitions correct - $this->h = $h; - $this->w = $w; - - $this->_intpl = true; - $this->SetXY($x + $this->lMargin, $y + $this->tMargin); - $this->SetRightMargin($this->w - $w + $this->rMargin); - - return $this->tpl; - } - - /** - * End Template - * - * This method ends a template and reset initiated variables on beginTemplate. - * - * @return mixed If a template is opened, the ID is returned. If not a false is returned. - */ - function endTemplate() { - if (is_subclass_of($this, 'TCPDF')) { - $args = func_get_args(); - return call_user_func_array(array($this, 'TCPDF::endTemplate'), $args); - } - - if ($this->_intpl) { - $this->_intpl = false; - $tpl =& $this->tpls[$this->tpl]; - $this->SetXY($tpl['o_x'], $tpl['o_y']); - $this->tMargin = $tpl['o_tMargin']; - $this->lMargin = $tpl['o_lMargin']; - $this->rMargin = $tpl['o_rMargin']; - $this->h = $tpl['o_h']; - $this->w = $tpl['o_w']; - $this->SetAutoPageBreak($tpl['o_AutoPageBreak'], $tpl['o_bMargin']); - - return $this->tpl; - } else { - return false; - } - } - - /** - * Use a Template in current Page or other Template - * - * You can use a template in a page or in another template. - * You can give the used template a new size like you use the Image()-method. - * All parameters are optional. The width or height is calculated automaticaly - * if one is given. If no parameter is given the origin size as defined in - * beginTemplate() is used. - * The calculated or used width and height are returned as an array. - * - * @param int $tplidx A valid template-Id - * @param int $_x The x-position - * @param int $_y The y-position - * @param int $_w The new width of the template - * @param int $_h The new height of the template - * @retrun array The height and width of the template - */ - function useTemplate($tplidx, $_x = null, $_y = null, $_w = 0, $_h = 0) { - if ($this->page <= 0) - $this->error('You have to add a page first!'); - - if (!isset($this->tpls[$tplidx])) - $this->error('Template does not exist!'); - - if ($this->_intpl) { - $this->_res['tpl'][$this->tpl]['tpls'][$tplidx] =& $this->tpls[$tplidx]; - } - - $tpl =& $this->tpls[$tplidx]; - $w = $tpl['w']; - $h = $tpl['h']; - - if ($_x == null) - $_x = 0; - if ($_y == null) - $_y = 0; - - $_x += $tpl['x']; - $_y += $tpl['y']; - - $wh = $this->getTemplateSize($tplidx, $_w, $_h); - $_w = $wh['w']; - $_h = $wh['h']; - - $tData = array( - 'x' => $this->x, - 'y' => $this->y, - 'w' => $_w, - 'h' => $_h, - 'scaleX' => ($_w / $w), - 'scaleY' => ($_h / $h), - 'tx' => $_x, - 'ty' => ($this->h - $_y - $_h), - 'lty' => ($this->h - $_y - $_h) - ($this->h - $h) * ($_h / $h) - ); - - $this->_out(sprintf('q %.4F 0 0 %.4F %.4F %.4F cm', $tData['scaleX'], $tData['scaleY'], $tData['tx'] * $this->k, $tData['ty'] * $this->k)); // Translate - $this->_out(sprintf('%s%d Do Q', $this->tplprefix, $tplidx)); - - // reset font in the outer graphic state - if ($this->FontFamily) { - $family = $this->FontFamily; - $this->FontFamily = ''; - $this->SetFont($family); - } - - $this->lastUsedTemplateData = $tData; - - return array('w' => $_w, 'h' => $_h); - } - - /** - * Get The calculated Size of a Template - * - * If one size is given, this method calculates the other one. - * - * @param int $tplidx A valid template-Id - * @param int $_w The width of the template - * @param int $_h The height of the template - * @return array The height and width of the template - */ - function getTemplateSize($tplidx, $_w = 0, $_h = 0) { - if (!$this->tpls[$tplidx]) - return false; - - $tpl =& $this->tpls[$tplidx]; - $w = $tpl['w']; - $h = $tpl['h']; - - if ($_w == 0 and $_h == 0) { - $_w = $w; - $_h = $h; - } - - if($_w == 0) - $_w = $_h * $w / $h; - if($_h == 0) - $_h = $_w * $h / $w; - - return array("w" => $_w, "h" => $_h); - } - - /** - * See FPDF/TCPDF-Documentation ;-) - */ - public function SetFont($family, $style = '', $size = 0) { - if (is_subclass_of($this, 'TCPDF')) { - $args = func_get_args(); - return call_user_func_array(array($this, 'TCPDF::SetFont'), $args); - } - - /** - * force the resetting of font changes in a template - */ - if ($this->_intpl) - $this->FontFamily = ''; - - parent::SetFont($family, $style, $size); - - $fontkey = $this->FontFamily . $this->FontStyle; - - if ($this->_intpl) { - $this->_res['tpl'][$this->tpl]['fonts'][$fontkey] =& $this->fonts[$fontkey]; - } else { - $this->_res['page'][$this->page]['fonts'][$fontkey] =& $this->fonts[$fontkey]; - } - } - - /** - * See FPDF/TCPDF-Documentation ;-) - */ - function Image($file, $x = null, $y = null, $w = 0, $h = 0, $type = '', $link = '') { - if (is_subclass_of($this, 'TCPDF')) { - $args = func_get_args(); - return call_user_func_array(array($this, 'TCPDF::Image'), $args); - } - - $ret = parent::Image($file, $x, $y, $w, $h, $type, $link); - if ($this->_intpl) { - $this->_res['tpl'][$this->tpl]['images'][$file] =& $this->images[$file]; - } else { - $this->_res['page'][$this->page]['images'][$file] =& $this->images[$file]; - } - - return $ret; - } - - /** - * See FPDF-Documentation ;-) - * - * AddPage is not available when you're "in" a template. - */ - function AddPage($orientation = '', $format = '') { - if (is_subclass_of($this, 'TCPDF')) { - $args = func_get_args(); - return call_user_func_array(array($this, 'TCPDF::AddPage'), $args); - } - - if ($this->_intpl) - $this->Error('Adding pages in templates isn\'t possible!'); - - parent::AddPage($orientation, $format); - } - - /** - * Preserve adding Links in Templates ...won't work - */ - function Link($x, $y, $w, $h, $link) { - if (is_subclass_of($this, 'TCPDF')) { - $args = func_get_args(); - return call_user_func_array(array($this, 'TCPDF::Link'), $args); - } - - if ($this->_intpl) - $this->Error('Using links in templates aren\'t possible!'); - - parent::Link($x, $y, $w, $h, $link); - } - - function AddLink() { - if (is_subclass_of($this, 'TCPDF')) { - $args = func_get_args(); - return call_user_func_array(array($this, 'TCPDF::AddLink'), $args); - } - - if ($this->_intpl) - $this->Error('Adding links in templates aren\'t possible!'); - return parent::AddLink(); - } - - function SetLink($link, $y = 0, $page = -1) { - if (is_subclass_of($this, 'TCPDF')) { - $args = func_get_args(); - return call_user_func_array(array($this, 'TCPDF::SetLink'), $args); - } - - if ($this->_intpl) - $this->Error('Setting links in templates aren\'t possible!'); - parent::SetLink($link, $y, $page); - } - - /** - * Private Method that writes the form xobjects - */ - function _putformxobjects() { - $filter=($this->compress) ? '/Filter /FlateDecode ' : ''; - reset($this->tpls); - foreach($this->tpls AS $tplidx => $tpl) { - - $p=($this->compress) ? gzcompress($tpl['buffer']) : $tpl['buffer']; - $this->_newobj(); - $this->tpls[$tplidx]['n'] = $this->n; - $this->_out('<<'.$filter.'/Type /XObject'); - $this->_out('/Subtype /Form'); - $this->_out('/FormType 1'); - $this->_out(sprintf('/BBox [%.2F %.2F %.2F %.2F]', - // llx - $tpl['x'] * $this->k, - // lly - -$tpl['y'] * $this->k, - // urx - ($tpl['w'] + $tpl['x']) * $this->k, - // ury - ($tpl['h'] - $tpl['y']) * $this->k - )); - - if ($tpl['x'] != 0 || $tpl['y'] != 0) { - $this->_out(sprintf('/Matrix [1 0 0 1 %.5F %.5F]', - -$tpl['x'] * $this->k * 2, $tpl['y'] * $this->k * 2 - )); - } - - $this->_out('/Resources '); - - $this->_out('<_res['tpl'][$tplidx]['fonts']) && count($this->_res['tpl'][$tplidx]['fonts'])) { - $this->_out('/Font <<'); - foreach($this->_res['tpl'][$tplidx]['fonts'] as $font) - $this->_out('/F' . $font['i'] . ' ' . $font['n'] . ' 0 R'); - $this->_out('>>'); - } - if(isset($this->_res['tpl'][$tplidx]['images']) && count($this->_res['tpl'][$tplidx]['images']) || - isset($this->_res['tpl'][$tplidx]['tpls']) && count($this->_res['tpl'][$tplidx]['tpls'])) - { - $this->_out('/XObject <<'); - if (isset($this->_res['tpl'][$tplidx]['images']) && count($this->_res['tpl'][$tplidx]['images'])) { - foreach($this->_res['tpl'][$tplidx]['images'] as $image) - $this->_out('/I' . $image['i'] . ' ' . $image['n'] . ' 0 R'); - } - if (isset($this->_res['tpl'][$tplidx]['tpls']) && count($this->_res['tpl'][$tplidx]['tpls'])) { - foreach($this->_res['tpl'][$tplidx]['tpls'] as $i => $tpl) - $this->_out($this->tplprefix . $i . ' ' . $tpl['n'] . ' 0 R'); - } - $this->_out('>>'); - } - $this->_out('>>'); - - $this->_out('/Length ' . strlen($p) . ' >>'); - $this->_putstream($p); - $this->_out('endobj'); - } - } - - /** - * Overwritten to add _putformxobjects() after _putimages() - * - */ - function _putimages() { - parent::_putimages(); - $this->_putformxobjects(); - } - - function _putxobjectdict() { - parent::_putxobjectdict(); - - if (count($this->tpls)) { - foreach($this->tpls as $tplidx => $tpl) { - $this->_out(sprintf('%s%d %d 0 R', $this->tplprefix, $tplidx, $tpl['n'])); - } - } - } - - /** - * Private Method - */ - function _out($s) { - if ($this->state == 2 && $this->_intpl) { - $this->tpls[$this->tpl]['buffer'] .= $s . "\n"; - } else { - parent::_out($s); - } - } -} +Error('This method is only usable with FPDF. Use TCPDF methods startTemplate() instead.'); + return; + } + + if ($this->page <= 0) + $this->error("You have to add a page to fpdf first!"); + + if ($x == null) + $x = 0; + if ($y == null) + $y = 0; + if ($w == null) + $w = $this->w; + if ($h == null) + $h = $this->h; + + // Save settings + $this->tpl++; + $tpl =& $this->tpls[$this->tpl]; + $tpl = array( + 'o_x' => $this->x, + 'o_y' => $this->y, + 'o_AutoPageBreak' => $this->AutoPageBreak, + 'o_bMargin' => $this->bMargin, + 'o_tMargin' => $this->tMargin, + 'o_lMargin' => $this->lMargin, + 'o_rMargin' => $this->rMargin, + 'o_h' => $this->h, + 'o_w' => $this->w, + 'buffer' => '', + 'x' => $x, + 'y' => $y, + 'w' => $w, + 'h' => $h + ); + + $this->SetAutoPageBreak(false); + + // Define own high and width to calculate possitions correct + $this->h = $h; + $this->w = $w; + + $this->_intpl = true; + $this->SetXY($x + $this->lMargin, $y + $this->tMargin); + $this->SetRightMargin($this->w - $w + $this->rMargin); + + return $this->tpl; + } + + /** + * End Template + * + * This method ends a template and reset initiated variables on beginTemplate. + * + * @return mixed If a template is opened, the ID is returned. If not a false is returned. + */ + function endTemplate() { + if (is_subclass_of($this, 'TCPDF')) { + $args = func_get_args(); + return call_user_func_array(array($this, 'TCPDF::endTemplate'), $args); + } + + if ($this->_intpl) { + $this->_intpl = false; + $tpl =& $this->tpls[$this->tpl]; + $this->SetXY($tpl['o_x'], $tpl['o_y']); + $this->tMargin = $tpl['o_tMargin']; + $this->lMargin = $tpl['o_lMargin']; + $this->rMargin = $tpl['o_rMargin']; + $this->h = $tpl['o_h']; + $this->w = $tpl['o_w']; + $this->SetAutoPageBreak($tpl['o_AutoPageBreak'], $tpl['o_bMargin']); + + return $this->tpl; + } else { + return false; + } + } + + /** + * Use a Template in current Page or other Template + * + * You can use a template in a page or in another template. + * You can give the used template a new size like you use the Image()-method. + * All parameters are optional. The width or height is calculated automaticaly + * if one is given. If no parameter is given the origin size as defined in + * beginTemplate() is used. + * The calculated or used width and height are returned as an array. + * + * @param int $tplidx A valid template-Id + * @param int $_x The x-position + * @param int $_y The y-position + * @param int $_w The new width of the template + * @param int $_h The new height of the template + * @retrun array The height and width of the template + */ + function useTemplate($tplidx, $_x = null, $_y = null, $_w = 0, $_h = 0) { + if ($this->page <= 0) + $this->error('You have to add a page first!'); + + if (!isset($this->tpls[$tplidx])) + $this->error('Template does not exist!'); + + if ($this->_intpl) { + $this->_res['tpl'][$this->tpl]['tpls'][$tplidx] =& $this->tpls[$tplidx]; + } + + $tpl =& $this->tpls[$tplidx]; + $w = $tpl['w']; + $h = $tpl['h']; + + if ($_x == null) + $_x = 0; + if ($_y == null) + $_y = 0; + + $_x += $tpl['x']; + $_y += $tpl['y']; + + $wh = $this->getTemplateSize($tplidx, $_w, $_h); + $_w = $wh['w']; + $_h = $wh['h']; + + $tData = array( + 'x' => $this->x, + 'y' => $this->y, + 'w' => $_w, + 'h' => $_h, + 'scaleX' => ($_w / $w), + 'scaleY' => ($_h / $h), + 'tx' => $_x, + 'ty' => ($this->h - $_y - $_h), + 'lty' => ($this->h - $_y - $_h) - ($this->h - $h) * ($_h / $h) + ); + + $this->_out(sprintf('q %.4F 0 0 %.4F %.4F %.4F cm', $tData['scaleX'], $tData['scaleY'], $tData['tx'] * $this->k, $tData['ty'] * $this->k)); // Translate + $this->_out(sprintf('%s%d Do Q', $this->tplprefix, $tplidx)); + + // reset font in the outer graphic state + if ($this->FontFamily) { + $family = $this->FontFamily; + $this->FontFamily = ''; + $this->SetFont($family); + } + + $this->lastUsedTemplateData = $tData; + + return array('w' => $_w, 'h' => $_h); + } + + /** + * Get The calculated Size of a Template + * + * If one size is given, this method calculates the other one. + * + * @param int $tplidx A valid template-Id + * @param int $_w The width of the template + * @param int $_h The height of the template + * @return array The height and width of the template + */ + function getTemplateSize($tplidx, $_w = 0, $_h = 0) { + if (!$this->tpls[$tplidx]) + return false; + + $tpl =& $this->tpls[$tplidx]; + $w = $tpl['w']; + $h = $tpl['h']; + + if ($_w == 0 and $_h == 0) { + $_w = $w; + $_h = $h; + } + + if($_w == 0) + $_w = $_h * $w / $h; + if($_h == 0) + $_h = $_w * $h / $w; + + return array("w" => $_w, "h" => $_h); + } + + /** + * See FPDF/TCPDF-Documentation ;-) + */ + public function SetFont($family, $style = '', $size = 0) { + if (is_subclass_of($this, 'TCPDF')) { + $args = func_get_args(); + return call_user_func_array(array($this, 'TCPDF::SetFont'), $args); + } + + /** + * force the resetting of font changes in a template + */ + if ($this->_intpl) + $this->FontFamily = ''; + + parent::SetFont($family, $style, $size); + + $fontkey = $this->FontFamily . $this->FontStyle; + + if ($this->_intpl) { + $this->_res['tpl'][$this->tpl]['fonts'][$fontkey] =& $this->fonts[$fontkey]; + } else { + $this->_res['page'][$this->page]['fonts'][$fontkey] =& $this->fonts[$fontkey]; + } + } + + /** + * See FPDF/TCPDF-Documentation ;-) + */ + function Image($file, $x = null, $y = null, $w = 0, $h = 0, $type = '', $link = '') { + if (is_subclass_of($this, 'TCPDF')) { + $args = func_get_args(); + return call_user_func_array(array($this, 'TCPDF::Image'), $args); + } + + $ret = parent::Image($file, $x, $y, $w, $h, $type, $link); + if ($this->_intpl) { + $this->_res['tpl'][$this->tpl]['images'][$file] =& $this->images[$file]; + } else { + $this->_res['page'][$this->page]['images'][$file] =& $this->images[$file]; + } + + return $ret; + } + + /** + * See FPDF-Documentation ;-) + * + * AddPage is not available when you're "in" a template. + */ + function AddPage($orientation = '', $format = '') { + if (is_subclass_of($this, 'TCPDF')) { + $args = func_get_args(); + return call_user_func_array(array($this, 'TCPDF::AddPage'), $args); + } + + if ($this->_intpl) + $this->Error('Adding pages in templates isn\'t possible!'); + + parent::AddPage($orientation, $format); + } + + /** + * Preserve adding Links in Templates ...won't work + */ + function Link($x, $y, $w, $h, $link) { + if (is_subclass_of($this, 'TCPDF')) { + $args = func_get_args(); + return call_user_func_array(array($this, 'TCPDF::Link'), $args); + } + + if ($this->_intpl) + $this->Error('Using links in templates aren\'t possible!'); + + parent::Link($x, $y, $w, $h, $link); + } + + function AddLink() { + if (is_subclass_of($this, 'TCPDF')) { + $args = func_get_args(); + return call_user_func_array(array($this, 'TCPDF::AddLink'), $args); + } + + if ($this->_intpl) + $this->Error('Adding links in templates aren\'t possible!'); + return parent::AddLink(); + } + + function SetLink($link, $y = 0, $page = -1) { + if (is_subclass_of($this, 'TCPDF')) { + $args = func_get_args(); + return call_user_func_array(array($this, 'TCPDF::SetLink'), $args); + } + + if ($this->_intpl) + $this->Error('Setting links in templates aren\'t possible!'); + parent::SetLink($link, $y, $page); + } + + /** + * Private Method that writes the form xobjects + */ + function _putformxobjects() { + $filter=($this->compress) ? '/Filter /FlateDecode ' : ''; + reset($this->tpls); + foreach($this->tpls AS $tplidx => $tpl) { + + $p=($this->compress) ? gzcompress($tpl['buffer']) : $tpl['buffer']; + $this->_newobj(); + $this->tpls[$tplidx]['n'] = $this->n; + $this->_out('<<'.$filter.'/Type /XObject'); + $this->_out('/Subtype /Form'); + $this->_out('/FormType 1'); + $this->_out(sprintf('/BBox [%.2F %.2F %.2F %.2F]', + // llx + $tpl['x'] * $this->k, + // lly + -$tpl['y'] * $this->k, + // urx + ($tpl['w'] + $tpl['x']) * $this->k, + // ury + ($tpl['h'] - $tpl['y']) * $this->k + )); + + if ($tpl['x'] != 0 || $tpl['y'] != 0) { + $this->_out(sprintf('/Matrix [1 0 0 1 %.5F %.5F]', + -$tpl['x'] * $this->k * 2, $tpl['y'] * $this->k * 2 + )); + } + + $this->_out('/Resources '); + + $this->_out('<_res['tpl'][$tplidx]['fonts']) && count($this->_res['tpl'][$tplidx]['fonts'])) { + $this->_out('/Font <<'); + foreach($this->_res['tpl'][$tplidx]['fonts'] as $font) + $this->_out('/F' . $font['i'] . ' ' . $font['n'] . ' 0 R'); + $this->_out('>>'); + } + if(isset($this->_res['tpl'][$tplidx]['images']) && count($this->_res['tpl'][$tplidx]['images']) || + isset($this->_res['tpl'][$tplidx]['tpls']) && count($this->_res['tpl'][$tplidx]['tpls'])) + { + $this->_out('/XObject <<'); + if (isset($this->_res['tpl'][$tplidx]['images']) && count($this->_res['tpl'][$tplidx]['images'])) { + foreach($this->_res['tpl'][$tplidx]['images'] as $image) + $this->_out('/I' . $image['i'] . ' ' . $image['n'] . ' 0 R'); + } + if (isset($this->_res['tpl'][$tplidx]['tpls']) && count($this->_res['tpl'][$tplidx]['tpls'])) { + foreach($this->_res['tpl'][$tplidx]['tpls'] as $i => $tpl) + $this->_out($this->tplprefix . $i . ' ' . $tpl['n'] . ' 0 R'); + } + $this->_out('>>'); + } + $this->_out('>>'); + + $this->_out('/Length ' . strlen($p) . ' >>'); + $this->_putstream($p); + $this->_out('endobj'); + } + } + + /** + * Overwritten to add _putformxobjects() after _putimages() + * + */ + function _putimages() { + parent::_putimages(); + $this->_putformxobjects(); + } + + function _putxobjectdict() { + parent::_putxobjectdict(); + + if (count($this->tpls)) { + foreach($this->tpls as $tplidx => $tpl) { + $this->_out(sprintf('%s%d %d 0 R', $this->tplprefix, $tplidx, $tpl['n'])); + } + } + } + + /** + * Private Method + */ + function _out($s) { + if ($this->state == 2 && $this->_intpl) { + $this->tpls[$this->tpl]['buffer'] .= $s . "\n"; + } else { + parent::_out($s); + } + } +} diff --git a/htdocs/includes/fpdfi/fpdi.php b/htdocs/includes/fpdfi/fpdi.php index 0ae2c63741c..f6ba91f96de 100755 --- a/htdocs/includes/fpdfi/fpdi.php +++ b/htdocs/includes/fpdfi/fpdi.php @@ -1,571 +1,571 @@ -current_filename = $filename; - - if (!isset($this->parsers[$filename])) - $this->parsers[$filename] = $this->_getPdfParser($filename); - $this->current_parser =& $this->parsers[$filename]; - - return $this->parsers[$filename]->getPageCount(); - } - - /** - * Returns a PDF parser object - * - * @param string $filename - * @return fpdi_pdf_parser - */ - function _getPdfParser($filename) { - return new fpdi_pdf_parser($filename, $this); - } - - /** - * Get the current PDF version - * - * @return string - */ - function getPDFVersion() { - return $this->PDFVersion; - } - - /** - * Set the PDF version - * - * @return string - */ - function setPDFVersion($version = '1.3') { - $this->PDFVersion = $version; - } - - /** - * Import a page - * - * @param int $pageno pagenumber - * @return int Index of imported page - to use with fpdf_tpl::useTemplate() - */ - function importPage($pageno, $boxName = '/CropBox') { - if ($this->_intpl) { - return $this->error('Please import the desired pages before creating a new template.'); - } - - $fn = $this->current_filename; - - // check if page already imported - $pageKey = $fn . '-' . ((int)$pageno) . $boxName; - if (isset($this->_importedPages[$pageKey])) - return $this->_importedPages[$pageKey]; - - $parser =& $this->parsers[$fn]; - $parser->setPageno($pageno); - - if (!in_array($boxName, $parser->availableBoxes)) - return $this->Error(sprintf('Unknown box: %s', $boxName)); - - $pageboxes = $parser->getPageBoxes($pageno, $this->k); - - /** - * MediaBox - * CropBox: Default -> MediaBox - * BleedBox: Default -> CropBox - * TrimBox: Default -> CropBox - * ArtBox: Default -> CropBox - */ - if (!isset($pageboxes[$boxName]) && ($boxName == '/BleedBox' || $boxName == '/TrimBox' || $boxName == '/ArtBox')) - $boxName = '/CropBox'; - if (!isset($pageboxes[$boxName]) && $boxName == '/CropBox') - $boxName = '/MediaBox'; - - if (!isset($pageboxes[$boxName])) - return false; - - $this->lastUsedPageBox = $boxName; - - $box = $pageboxes[$boxName]; - - $this->tpl++; - $this->tpls[$this->tpl] = array(); - $tpl =& $this->tpls[$this->tpl]; - $tpl['parser'] =& $parser; - $tpl['resources'] = $parser->getPageResources(); - $tpl['buffer'] = $parser->getContent(); - $tpl['box'] = $box; - - // To build an array that can be used by PDF_TPL::useTemplate() - $this->tpls[$this->tpl] = array_merge($this->tpls[$this->tpl], $box); - - // An imported page will start at 0,0 everytime. Translation will be set in _putformxobjects() - $tpl['x'] = 0; - $tpl['y'] = 0; - - // handle rotated pages - $rotation = $parser->getPageRotation($pageno); - $tpl['_rotationAngle'] = 0; - if (isset($rotation[1]) && ($angle = $rotation[1] % 360) != 0) { - $steps = $angle / 90; - - $_w = $tpl['w']; - $_h = $tpl['h']; - $tpl['w'] = $steps % 2 == 0 ? $_w : $_h; - $tpl['h'] = $steps % 2 == 0 ? $_h : $_w; - - if ($angle < 0) - $angle += 360; - - $tpl['_rotationAngle'] = $angle * -1; - } - - $this->_importedPages[$pageKey] = $this->tpl; - - return $this->tpl; - } - - /** - * Returns the last used page box - * - * @return string - */ - function getLastUsedPageBox() { - return $this->lastUsedPageBox; - } - - - function useTemplate($tplidx, $_x = null, $_y = null, $_w = 0, $_h = 0, $adjustPageSize = false) { - if ($adjustPageSize == true && is_null($_x) && is_null($_y)) { - $size = $this->getTemplateSize($tplidx, $_w, $_h); - $orientation = $size['w'] > $size['h'] ? 'L' : 'P'; - $size = array($size['w'], $size['h']); - - if (is_subclass_of($this, 'TCPDF')) { - $this->setPageFormat($size, $orientation); - } else { - $size = $this->_getpagesize($size); - - if($orientation!=$this->CurOrientation || $size[0]!=$this->CurPageSize[0] || $size[1]!=$this->CurPageSize[1]) - { - // New size or orientation - if($orientation=='P') - { - $this->w = $size[0]; - $this->h = $size[1]; - } - else - { - $this->w = $size[1]; - $this->h = $size[0]; - } - $this->wPt = $this->w*$this->k; - $this->hPt = $this->h*$this->k; - $this->PageBreakTrigger = $this->h-$this->bMargin; - $this->CurOrientation = $orientation; - $this->CurPageSize = $size; - $this->PageSizes[$this->page] = array($this->wPt, $this->hPt); - } - } - } - - $this->_out('q 0 J 1 w 0 j 0 G 0 g'); // reset standard values - $s = parent::useTemplate($tplidx, $_x, $_y, $_w, $_h); - $this->_out('Q'); - - return $s; - } - - /** - * Private method, that rebuilds all needed objects of source files - */ - function _putimportedobjects() { - if (is_array($this->parsers) && count($this->parsers) > 0) { - foreach($this->parsers AS $filename => $p) { - $this->current_parser =& $this->parsers[$filename]; - if (isset($this->_obj_stack[$filename]) && is_array($this->_obj_stack[$filename])) { - while(($n = key($this->_obj_stack[$filename])) !== null) { - $nObj = $this->current_parser->pdf_resolve_object($this->current_parser->c, $this->_obj_stack[$filename][$n][1]); - - $this->_newobj($this->_obj_stack[$filename][$n][0]); - - if ($nObj[0] == PDF_TYPE_STREAM) { - $this->pdf_write_value($nObj); - } else { - $this->pdf_write_value($nObj[1]); - } - - $this->_out('endobj'); - $this->_obj_stack[$filename][$n] = null; // free memory - unset($this->_obj_stack[$filename][$n]); - reset($this->_obj_stack[$filename]); - } - } - } - } - } - - - /** - * Private Method that writes the form xobjects - */ - function _putformxobjects() { - $filter=($this->compress) ? '/Filter /FlateDecode ' : ''; - reset($this->tpls); - foreach($this->tpls AS $tplidx => $tpl) { - $p=($this->compress) ? gzcompress($tpl['buffer']) : $tpl['buffer']; - $this->_newobj(); - $cN = $this->n; // TCPDF/Protection: rem current "n" - - $this->tpls[$tplidx]['n'] = $this->n; - $this->_out('<<' . $filter . '/Type /XObject'); - $this->_out('/Subtype /Form'); - $this->_out('/FormType 1'); - - $this->_out(sprintf('/BBox [%.2F %.2F %.2F %.2F]', - (isset($tpl['box']['llx']) ? $tpl['box']['llx'] : $tpl['x']) * $this->k, - (isset($tpl['box']['lly']) ? $tpl['box']['lly'] : -$tpl['y']) * $this->k, - (isset($tpl['box']['urx']) ? $tpl['box']['urx'] : $tpl['w'] + $tpl['x']) * $this->k, - (isset($tpl['box']['ury']) ? $tpl['box']['ury'] : $tpl['h'] - $tpl['y']) * $this->k - )); - - $c = 1; - $s = 0; - $tx = 0; - $ty = 0; - - if (isset($tpl['box'])) { - $tx = -$tpl['box']['llx']; - $ty = -$tpl['box']['lly']; - - if ($tpl['_rotationAngle'] <> 0) { - $angle = $tpl['_rotationAngle'] * M_PI/180; - $c=cos($angle); - $s=sin($angle); - - switch($tpl['_rotationAngle']) { - case -90: - $tx = -$tpl['box']['lly']; - $ty = $tpl['box']['urx']; - break; - case -180: - $tx = $tpl['box']['urx']; - $ty = $tpl['box']['ury']; - break; - case -270: - $tx = $tpl['box']['ury']; - $ty = -$tpl['box']['llx']; - break; - } - } - } else if ($tpl['x'] != 0 || $tpl['y'] != 0) { - $tx = -$tpl['x'] * 2; - $ty = $tpl['y'] * 2; - } - - $tx *= $this->k; - $ty *= $this->k; - - if ($c != 1 || $s != 0 || $tx != 0 || $ty != 0) { - $this->_out(sprintf('/Matrix [%.5F %.5F %.5F %.5F %.5F %.5F]', - $c, $s, -$s, $c, $tx, $ty - )); - } - - $this->_out('/Resources '); - - if (isset($tpl['resources'])) { - $this->current_parser =& $tpl['parser']; - $this->pdf_write_value($tpl['resources']); // "n" will be changed - } else { - $this->_out('<_res['tpl'][$tplidx]['fonts']) && count($this->_res['tpl'][$tplidx]['fonts'])) { - $this->_out('/Font <<'); - foreach($this->_res['tpl'][$tplidx]['fonts'] as $font) - $this->_out('/F' . $font['i'] . ' ' . $font['n'] . ' 0 R'); - $this->_out('>>'); - } - if(isset($this->_res['tpl'][$tplidx]['images']) && count($this->_res['tpl'][$tplidx]['images']) || - isset($this->_res['tpl'][$tplidx]['tpls']) && count($this->_res['tpl'][$tplidx]['tpls'])) - { - $this->_out('/XObject <<'); - if (isset($this->_res['tpl'][$tplidx]['images']) && count($this->_res['tpl'][$tplidx]['images'])) { - foreach($this->_res['tpl'][$tplidx]['images'] as $image) - $this->_out('/I' . $image['i'] . ' ' . $image['n'] . ' 0 R'); - } - if (isset($this->_res['tpl'][$tplidx]['tpls']) && count($this->_res['tpl'][$tplidx]['tpls'])) { - foreach($this->_res['tpl'][$tplidx]['tpls'] as $i => $tpl) - $this->_out($this->tplprefix . $i . ' ' . $tpl['n'] . ' 0 R'); - } - $this->_out('>>'); - } - $this->_out('>>'); - } - - $nN = $this->n; // TCPDF: rem new "n" - $this->n = $cN; // TCPDF: reset to current "n" - if (is_subclass_of($this, 'TCPDF')) { - $p = $this->_getrawstream($p); - $this->_out('/Length ' . strlen($p) . ' >>'); - $this->_out("stream\n" . $p . "\nendstream"); - } else { - $this->_out('/Length ' . strlen($p) . ' >>'); - $this->_putstream($p); - } - $this->_out('endobj'); - $this->n = $nN; // TCPDF: reset to new "n" - } - - $this->_putimportedobjects(); - } - - /** - * Rewritten to handle existing own defined objects - */ - function _newobj($obj_id = false, $onlynewobj = false) { - if (!$obj_id) { - $obj_id = ++$this->n; - } - - //Begin a new object - if (!$onlynewobj) { - $this->offsets[$obj_id] = is_subclass_of($this, 'TCPDF') ? $this->bufferlen : strlen($this->buffer); - $this->_out($obj_id . ' 0 obj'); - $this->_current_obj_id = $obj_id; // for later use with encryption - } - - return $obj_id; - } - - /** - * Writes a value - * Needed to rebuild the source document - * - * @param mixed $value A PDF-Value. Structure of values see cases in this method - */ - function pdf_write_value(&$value) - { - if (is_subclass_of($this, 'TCPDF')) { - parent::pdf_write_value($value); - } - - switch ($value[0]) { - - case PDF_TYPE_TOKEN: - $this->_straightOut($value[1] . ' '); - break; - case PDF_TYPE_NUMERIC: - case PDF_TYPE_REAL: - if (is_float($value[1]) && $value[1] != 0) { - $this->_straightOut(rtrim(rtrim(sprintf('%F', $value[1]), '0'), '.') . ' '); - } else { - $this->_straightOut($value[1] . ' '); - } - break; - - case PDF_TYPE_ARRAY: - - // An array. Output the proper - // structure and move on. - - $this->_straightOut('['); - for ($i = 0; $i < count($value[1]); $i++) { - $this->pdf_write_value($value[1][$i]); - } - - $this->_out(']'); - break; - - case PDF_TYPE_DICTIONARY: - - // A dictionary. - $this->_straightOut('<<'); - - reset ($value[1]); - - while (list($k, $v) = each($value[1])) { - $this->_straightOut($k . ' '); - $this->pdf_write_value($v); - } - - $this->_straightOut('>>'); - break; - - case PDF_TYPE_OBJREF: - - // An indirect object reference - // Fill the object stack if needed - $cpfn =& $this->current_parser->filename; - - if (!isset($this->_don_obj_stack[$cpfn][$value[1]])) { - $this->_newobj(false, true); - $this->_obj_stack[$cpfn][$value[1]] = array($this->n, $value); - $this->_don_obj_stack[$cpfn][$value[1]] = array($this->n, $value); // Value is maybee obsolete!!! - } - $objid = $this->_don_obj_stack[$cpfn][$value[1]][0]; - - $this->_out($objid . ' 0 R'); - break; - - case PDF_TYPE_STRING: - - // A string. - $this->_straightOut('(' . $value[1] . ')'); - - break; - - case PDF_TYPE_STREAM: - - // A stream. First, output the - // stream dictionary, then the - // stream data itself. - $this->pdf_write_value($value[1]); - $this->_out('stream'); - $this->_out($value[2][1]); - $this->_out('endstream'); - break; - - case PDF_TYPE_HEX: - $this->_straightOut('<' . $value[1] . '>'); - break; - - case PDF_TYPE_BOOLEAN: - $this->_straightOut($value[1] ? 'true ' : 'false '); - break; - - case PDF_TYPE_NULL: - // The null object. - - $this->_straightOut('null '); - break; - } - } - - - /** - * Modified so not each call will add a newline to the output. - */ - function _straightOut($s) { - if (!is_subclass_of($this, 'TCPDF')) { - if($this->state==2) - $this->pages[$this->page] .= $s; - else - $this->buffer .= $s; - } else { - if ($this->state == 2) { - if (isset($this->footerlen[$this->page]) AND ($this->footerlen[$this->page] > 0)) { - // puts data before page footer - $page = substr($this->getPageBuffer($this->page), 0, -$this->footerlen[$this->page]); - $footer = substr($this->getPageBuffer($this->page), -$this->footerlen[$this->page]); - $this->setPageBuffer($this->page, $page . ' ' . $s . "\n" . $footer); - } else { - $this->setPageBuffer($this->page, $s, true); - } - } else { - $this->setBuffer($s); - } - } - } - - /** - * rewritten to close opened parsers - * - */ - function _enddoc() { - parent::_enddoc(); - $this->_closeParsers(); - } - - /** - * close all files opened by parsers - */ - function _closeParsers() { - if ($this->state > 2 && count($this->parsers) > 0) { - foreach ($this->parsers as $k => $_){ - $this->parsers[$k]->closeFile(); - $this->parsers[$k] = null; - unset($this->parsers[$k]); - } - return true; - } - return false; - } +current_filename = $filename; + + if (!isset($this->parsers[$filename])) + $this->parsers[$filename] = $this->_getPdfParser($filename); + $this->current_parser =& $this->parsers[$filename]; + + return $this->parsers[$filename]->getPageCount(); + } + + /** + * Returns a PDF parser object + * + * @param string $filename + * @return fpdi_pdf_parser + */ + function _getPdfParser($filename) { + return new fpdi_pdf_parser($filename, $this); + } + + /** + * Get the current PDF version + * + * @return string + */ + function getPDFVersion() { + return $this->PDFVersion; + } + + /** + * Set the PDF version + * + * @return string + */ + function setPDFVersion($version = '1.3') { + $this->PDFVersion = $version; + } + + /** + * Import a page + * + * @param int $pageno pagenumber + * @return int Index of imported page - to use with fpdf_tpl::useTemplate() + */ + function importPage($pageno, $boxName = '/CropBox') { + if ($this->_intpl) { + return $this->error('Please import the desired pages before creating a new template.'); + } + + $fn = $this->current_filename; + + // check if page already imported + $pageKey = $fn . '-' . ((int)$pageno) . $boxName; + if (isset($this->_importedPages[$pageKey])) + return $this->_importedPages[$pageKey]; + + $parser =& $this->parsers[$fn]; + $parser->setPageno($pageno); + + if (!in_array($boxName, $parser->availableBoxes)) + return $this->Error(sprintf('Unknown box: %s', $boxName)); + + $pageboxes = $parser->getPageBoxes($pageno, $this->k); + + /** + * MediaBox + * CropBox: Default -> MediaBox + * BleedBox: Default -> CropBox + * TrimBox: Default -> CropBox + * ArtBox: Default -> CropBox + */ + if (!isset($pageboxes[$boxName]) && ($boxName == '/BleedBox' || $boxName == '/TrimBox' || $boxName == '/ArtBox')) + $boxName = '/CropBox'; + if (!isset($pageboxes[$boxName]) && $boxName == '/CropBox') + $boxName = '/MediaBox'; + + if (!isset($pageboxes[$boxName])) + return false; + + $this->lastUsedPageBox = $boxName; + + $box = $pageboxes[$boxName]; + + $this->tpl++; + $this->tpls[$this->tpl] = array(); + $tpl =& $this->tpls[$this->tpl]; + $tpl['parser'] =& $parser; + $tpl['resources'] = $parser->getPageResources(); + $tpl['buffer'] = $parser->getContent(); + $tpl['box'] = $box; + + // To build an array that can be used by PDF_TPL::useTemplate() + $this->tpls[$this->tpl] = array_merge($this->tpls[$this->tpl], $box); + + // An imported page will start at 0,0 everytime. Translation will be set in _putformxobjects() + $tpl['x'] = 0; + $tpl['y'] = 0; + + // handle rotated pages + $rotation = $parser->getPageRotation($pageno); + $tpl['_rotationAngle'] = 0; + if (isset($rotation[1]) && ($angle = $rotation[1] % 360) != 0) { + $steps = $angle / 90; + + $_w = $tpl['w']; + $_h = $tpl['h']; + $tpl['w'] = $steps % 2 == 0 ? $_w : $_h; + $tpl['h'] = $steps % 2 == 0 ? $_h : $_w; + + if ($angle < 0) + $angle += 360; + + $tpl['_rotationAngle'] = $angle * -1; + } + + $this->_importedPages[$pageKey] = $this->tpl; + + return $this->tpl; + } + + /** + * Returns the last used page box + * + * @return string + */ + function getLastUsedPageBox() { + return $this->lastUsedPageBox; + } + + + function useTemplate($tplidx, $_x = null, $_y = null, $_w = 0, $_h = 0, $adjustPageSize = false) { + if ($adjustPageSize == true && is_null($_x) && is_null($_y)) { + $size = $this->getTemplateSize($tplidx, $_w, $_h); + $orientation = $size['w'] > $size['h'] ? 'L' : 'P'; + $size = array($size['w'], $size['h']); + + if (is_subclass_of($this, 'TCPDF')) { + $this->setPageFormat($size, $orientation); + } else { + $size = $this->_getpagesize($size); + + if($orientation!=$this->CurOrientation || $size[0]!=$this->CurPageSize[0] || $size[1]!=$this->CurPageSize[1]) + { + // New size or orientation + if($orientation=='P') + { + $this->w = $size[0]; + $this->h = $size[1]; + } + else + { + $this->w = $size[1]; + $this->h = $size[0]; + } + $this->wPt = $this->w*$this->k; + $this->hPt = $this->h*$this->k; + $this->PageBreakTrigger = $this->h-$this->bMargin; + $this->CurOrientation = $orientation; + $this->CurPageSize = $size; + $this->PageSizes[$this->page] = array($this->wPt, $this->hPt); + } + } + } + + $this->_out('q 0 J 1 w 0 j 0 G 0 g'); // reset standard values + $s = parent::useTemplate($tplidx, $_x, $_y, $_w, $_h); + $this->_out('Q'); + + return $s; + } + + /** + * Private method, that rebuilds all needed objects of source files + */ + function _putimportedobjects() { + if (is_array($this->parsers) && count($this->parsers) > 0) { + foreach($this->parsers AS $filename => $p) { + $this->current_parser =& $this->parsers[$filename]; + if (isset($this->_obj_stack[$filename]) && is_array($this->_obj_stack[$filename])) { + while(($n = key($this->_obj_stack[$filename])) !== null) { + $nObj = $this->current_parser->pdf_resolve_object($this->current_parser->c, $this->_obj_stack[$filename][$n][1]); + + $this->_newobj($this->_obj_stack[$filename][$n][0]); + + if ($nObj[0] == PDF_TYPE_STREAM) { + $this->pdf_write_value($nObj); + } else { + $this->pdf_write_value($nObj[1]); + } + + $this->_out('endobj'); + $this->_obj_stack[$filename][$n] = null; // free memory + unset($this->_obj_stack[$filename][$n]); + reset($this->_obj_stack[$filename]); + } + } + } + } + } + + + /** + * Private Method that writes the form xobjects + */ + function _putformxobjects() { + $filter=($this->compress) ? '/Filter /FlateDecode ' : ''; + reset($this->tpls); + foreach($this->tpls AS $tplidx => $tpl) { + $p=($this->compress) ? gzcompress($tpl['buffer']) : $tpl['buffer']; + $this->_newobj(); + $cN = $this->n; // TCPDF/Protection: rem current "n" + + $this->tpls[$tplidx]['n'] = $this->n; + $this->_out('<<' . $filter . '/Type /XObject'); + $this->_out('/Subtype /Form'); + $this->_out('/FormType 1'); + + $this->_out(sprintf('/BBox [%.2F %.2F %.2F %.2F]', + (isset($tpl['box']['llx']) ? $tpl['box']['llx'] : $tpl['x']) * $this->k, + (isset($tpl['box']['lly']) ? $tpl['box']['lly'] : -$tpl['y']) * $this->k, + (isset($tpl['box']['urx']) ? $tpl['box']['urx'] : $tpl['w'] + $tpl['x']) * $this->k, + (isset($tpl['box']['ury']) ? $tpl['box']['ury'] : $tpl['h'] - $tpl['y']) * $this->k + )); + + $c = 1; + $s = 0; + $tx = 0; + $ty = 0; + + if (isset($tpl['box'])) { + $tx = -$tpl['box']['llx']; + $ty = -$tpl['box']['lly']; + + if ($tpl['_rotationAngle'] <> 0) { + $angle = $tpl['_rotationAngle'] * M_PI/180; + $c=cos($angle); + $s=sin($angle); + + switch($tpl['_rotationAngle']) { + case -90: + $tx = -$tpl['box']['lly']; + $ty = $tpl['box']['urx']; + break; + case -180: + $tx = $tpl['box']['urx']; + $ty = $tpl['box']['ury']; + break; + case -270: + $tx = $tpl['box']['ury']; + $ty = -$tpl['box']['llx']; + break; + } + } + } else if ($tpl['x'] != 0 || $tpl['y'] != 0) { + $tx = -$tpl['x'] * 2; + $ty = $tpl['y'] * 2; + } + + $tx *= $this->k; + $ty *= $this->k; + + if ($c != 1 || $s != 0 || $tx != 0 || $ty != 0) { + $this->_out(sprintf('/Matrix [%.5F %.5F %.5F %.5F %.5F %.5F]', + $c, $s, -$s, $c, $tx, $ty + )); + } + + $this->_out('/Resources '); + + if (isset($tpl['resources'])) { + $this->current_parser =& $tpl['parser']; + $this->pdf_write_value($tpl['resources']); // "n" will be changed + } else { + $this->_out('<_res['tpl'][$tplidx]['fonts']) && count($this->_res['tpl'][$tplidx]['fonts'])) { + $this->_out('/Font <<'); + foreach($this->_res['tpl'][$tplidx]['fonts'] as $font) + $this->_out('/F' . $font['i'] . ' ' . $font['n'] . ' 0 R'); + $this->_out('>>'); + } + if(isset($this->_res['tpl'][$tplidx]['images']) && count($this->_res['tpl'][$tplidx]['images']) || + isset($this->_res['tpl'][$tplidx]['tpls']) && count($this->_res['tpl'][$tplidx]['tpls'])) + { + $this->_out('/XObject <<'); + if (isset($this->_res['tpl'][$tplidx]['images']) && count($this->_res['tpl'][$tplidx]['images'])) { + foreach($this->_res['tpl'][$tplidx]['images'] as $image) + $this->_out('/I' . $image['i'] . ' ' . $image['n'] . ' 0 R'); + } + if (isset($this->_res['tpl'][$tplidx]['tpls']) && count($this->_res['tpl'][$tplidx]['tpls'])) { + foreach($this->_res['tpl'][$tplidx]['tpls'] as $i => $tpl) + $this->_out($this->tplprefix . $i . ' ' . $tpl['n'] . ' 0 R'); + } + $this->_out('>>'); + } + $this->_out('>>'); + } + + $nN = $this->n; // TCPDF: rem new "n" + $this->n = $cN; // TCPDF: reset to current "n" + if (is_subclass_of($this, 'TCPDF')) { + $p = $this->_getrawstream($p); + $this->_out('/Length ' . strlen($p) . ' >>'); + $this->_out("stream\n" . $p . "\nendstream"); + } else { + $this->_out('/Length ' . strlen($p) . ' >>'); + $this->_putstream($p); + } + $this->_out('endobj'); + $this->n = $nN; // TCPDF: reset to new "n" + } + + $this->_putimportedobjects(); + } + + /** + * Rewritten to handle existing own defined objects + */ + function _newobj($obj_id = false, $onlynewobj = false) { + if (!$obj_id) { + $obj_id = ++$this->n; + } + + //Begin a new object + if (!$onlynewobj) { + $this->offsets[$obj_id] = is_subclass_of($this, 'TCPDF') ? $this->bufferlen : strlen($this->buffer); + $this->_out($obj_id . ' 0 obj'); + $this->_current_obj_id = $obj_id; // for later use with encryption + } + + return $obj_id; + } + + /** + * Writes a value + * Needed to rebuild the source document + * + * @param mixed $value A PDF-Value. Structure of values see cases in this method + */ + function pdf_write_value(&$value) + { + if (is_subclass_of($this, 'TCPDF')) { + parent::pdf_write_value($value); + } + + switch ($value[0]) { + + case PDF_TYPE_TOKEN: + $this->_straightOut($value[1] . ' '); + break; + case PDF_TYPE_NUMERIC: + case PDF_TYPE_REAL: + if (is_float($value[1]) && $value[1] != 0) { + $this->_straightOut(rtrim(rtrim(sprintf('%F', $value[1]), '0'), '.') . ' '); + } else { + $this->_straightOut($value[1] . ' '); + } + break; + + case PDF_TYPE_ARRAY: + + // An array. Output the proper + // structure and move on. + + $this->_straightOut('['); + for ($i = 0; $i < count($value[1]); $i++) { + $this->pdf_write_value($value[1][$i]); + } + + $this->_out(']'); + break; + + case PDF_TYPE_DICTIONARY: + + // A dictionary. + $this->_straightOut('<<'); + + reset ($value[1]); + + while (list($k, $v) = each($value[1])) { + $this->_straightOut($k . ' '); + $this->pdf_write_value($v); + } + + $this->_straightOut('>>'); + break; + + case PDF_TYPE_OBJREF: + + // An indirect object reference + // Fill the object stack if needed + $cpfn =& $this->current_parser->filename; + + if (!isset($this->_don_obj_stack[$cpfn][$value[1]])) { + $this->_newobj(false, true); + $this->_obj_stack[$cpfn][$value[1]] = array($this->n, $value); + $this->_don_obj_stack[$cpfn][$value[1]] = array($this->n, $value); // Value is maybee obsolete!!! + } + $objid = $this->_don_obj_stack[$cpfn][$value[1]][0]; + + $this->_out($objid . ' 0 R'); + break; + + case PDF_TYPE_STRING: + + // A string. + $this->_straightOut('(' . $value[1] . ')'); + + break; + + case PDF_TYPE_STREAM: + + // A stream. First, output the + // stream dictionary, then the + // stream data itself. + $this->pdf_write_value($value[1]); + $this->_out('stream'); + $this->_out($value[2][1]); + $this->_out('endstream'); + break; + + case PDF_TYPE_HEX: + $this->_straightOut('<' . $value[1] . '>'); + break; + + case PDF_TYPE_BOOLEAN: + $this->_straightOut($value[1] ? 'true ' : 'false '); + break; + + case PDF_TYPE_NULL: + // The null object. + + $this->_straightOut('null '); + break; + } + } + + + /** + * Modified so not each call will add a newline to the output. + */ + function _straightOut($s) { + if (!is_subclass_of($this, 'TCPDF')) { + if($this->state==2) + $this->pages[$this->page] .= $s; + else + $this->buffer .= $s; + } else { + if ($this->state == 2) { + if (isset($this->footerlen[$this->page]) AND ($this->footerlen[$this->page] > 0)) { + // puts data before page footer + $page = substr($this->getPageBuffer($this->page), 0, -$this->footerlen[$this->page]); + $footer = substr($this->getPageBuffer($this->page), -$this->footerlen[$this->page]); + $this->setPageBuffer($this->page, $page . ' ' . $s . "\n" . $footer); + } else { + $this->setPageBuffer($this->page, $s, true); + } + } else { + $this->setBuffer($s); + } + } + } + + /** + * rewritten to close opened parsers + * + */ + function _enddoc() { + parent::_enddoc(); + $this->_closeParsers(); + } + + /** + * close all files opened by parsers + */ + function _closeParsers() { + if ($this->state > 2 && count($this->parsers) > 0) { + foreach ($this->parsers as $k => $_){ + $this->parsers[$k]->closeFile(); + $this->parsers[$k] = null; + unset($this->parsers[$k]); + } + return true; + } + return false; + } } \ No newline at end of file diff --git a/htdocs/includes/fpdfi/fpdi_pdf_parser.php b/htdocs/includes/fpdfi/fpdi_pdf_parser.php index fd2b4414c76..9da790507f3 100755 --- a/htdocs/includes/fpdfi/fpdi_pdf_parser.php +++ b/htdocs/includes/fpdfi/fpdi_pdf_parser.php @@ -1,408 +1,408 @@ -fpdi =& $fpdi; - - parent::pdf_parser($filename); - - // resolve Pages-Dictonary - $pages = $this->pdf_resolve_object($this->c, $this->root[1][1]['/Pages']); - - // Read pages - $this->read_pages($this->c, $pages, $this->pages); - - // count pages; - $this->page_count = count($this->pages); - } - - /** - * Overwrite parent::error() - * - * @param string $msg Error-Message - */ - function error($msg) { - $this->fpdi->error($msg); - } - - /** - * Get pagecount from sourcefile - * - * @return int - */ - function getPageCount() { - return $this->page_count; - } - - - /** - * Set pageno - * - * @param int $pageno Pagenumber to use - */ - function setPageno($pageno) { - $pageno = ((int) $pageno) - 1; - - if ($pageno < 0 || $pageno >= $this->getPageCount()) { - $this->fpdi->error('Pagenumber is wrong!'); - } - - $this->pageno = $pageno; - } - - /** - * Get page-resources from current page - * - * @return array - */ - function getPageResources() { - return $this->_getPageResources($this->pages[$this->pageno]); - } - - /** - * Get page-resources from /Page - * - * @param array $obj Array of pdf-data - */ - function _getPageResources ($obj) { // $obj = /Page - $obj = $this->pdf_resolve_object($this->c, $obj); - - // If the current object has a resources - // dictionary associated with it, we use - // it. Otherwise, we move back to its - // parent object. - if (isset ($obj[1][1]['/Resources'])) { - $res = $this->pdf_resolve_object($this->c, $obj[1][1]['/Resources']); - if ($res[0] == PDF_TYPE_OBJECT) - return $res[1]; - return $res; - } else { - if (!isset ($obj[1][1]['/Parent'])) { - return false; - } else { - $res = $this->_getPageResources($obj[1][1]['/Parent']); - if ($res[0] == PDF_TYPE_OBJECT) - return $res[1]; - return $res; - } - } - } - - - /** - * Get content of current page - * - * If more /Contents is an array, the streams are concated - * - * @return string - */ - function getContent() { - $buffer = ''; - - if (isset($this->pages[$this->pageno][1][1]['/Contents'])) { - $contents = $this->_getPageContent($this->pages[$this->pageno][1][1]['/Contents']); - foreach($contents AS $tmp_content) { - $buffer .= $this->_rebuildContentStream($tmp_content) . ' '; - } - } - - return $buffer; - } - - - /** - * Resolve all content-objects - * - * @param array $content_ref - * @return array - */ - function _getPageContent($content_ref) { - $contents = array(); - - if ($content_ref[0] == PDF_TYPE_OBJREF) { - $content = $this->pdf_resolve_object($this->c, $content_ref); - if ($content[1][0] == PDF_TYPE_ARRAY) { - $contents = $this->_getPageContent($content[1]); - } else { - $contents[] = $content; - } - } else if ($content_ref[0] == PDF_TYPE_ARRAY) { - foreach ($content_ref[1] AS $tmp_content_ref) { - $contents = array_merge($contents,$this->_getPageContent($tmp_content_ref)); - } - } - - return $contents; - } - - - /** - * Rebuild content-streams - * - * @param array $obj - * @return string - */ - function _rebuildContentStream($obj) { - $filters = array(); - - if (isset($obj[1][1]['/Filter'])) { - $_filter = $obj[1][1]['/Filter']; - - if ($_filter[0] == PDF_TYPE_OBJREF) { - $tmpFilter = $this->pdf_resolve_object($this->c, $_filter); - $_filter = $tmpFilter[1]; - } - - if ($_filter[0] == PDF_TYPE_TOKEN) { - $filters[] = $_filter; - } else if ($_filter[0] == PDF_TYPE_ARRAY) { - $filters = $_filter[1]; - } - } - - $stream = $obj[2][1]; - - foreach ($filters AS $_filter) { - switch ($_filter[1]) { - case '/FlateDecode': - case '/Fl': - // $stream .= "\x0F\x0D"; // in an errorious stream this suffix could work - // $stream .= "\x0A"; - // $stream .= "\x0D"; - if (function_exists('gzuncompress')) { - $stream = (strlen($stream) > 0) ? @gzuncompress($stream) : ''; - } else { - $this->error(sprintf('To handle %s filter, please compile php with zlib support.',$_filter[1])); - } - - if ($stream === false) { - $this->error('Error while decompressing stream.'); - } - break; - case '/LZWDecode': - include_once('filters/FilterLZW_FPDI.php'); - $decoder = new FilterLZW_FPDI($this->fpdi); - $stream = $decoder->decode($stream); - break; - case '/ASCII85Decode': - include_once('filters/FilterASCII85_FPDI.php'); - $decoder = new FilterASCII85_FPDI($this->fpdi); - $stream = $decoder->decode($stream); - break; - case null: - $stream = $stream; - break; - default: - $this->error(sprintf('Unsupported Filter: %s',$_filter[1])); - } - } - - return $stream; - } - - - /** - * Get a Box from a page - * Arrayformat is same as used by fpdf_tpl - * - * @param array $page a /Page - * @param string $box_index Type of Box @see $availableBoxes - * @param float Scale factor from user space units to points - * @return array - */ - function getPageBox($page, $box_index, $k) { - $page = $this->pdf_resolve_object($this->c, $page); - $box = null; - if (isset($page[1][1][$box_index])) - $box =& $page[1][1][$box_index]; - - if (!is_null($box) && $box[0] == PDF_TYPE_OBJREF) { - $tmp_box = $this->pdf_resolve_object($this->c, $box); - $box = $tmp_box[1]; - } - - if (!is_null($box) && $box[0] == PDF_TYPE_ARRAY) { - $b =& $box[1]; - return array('x' => $b[0][1] / $k, - 'y' => $b[1][1] / $k, - 'w' => abs($b[0][1] - $b[2][1]) / $k, - 'h' => abs($b[1][1] - $b[3][1]) / $k, - 'llx' => min($b[0][1], $b[2][1]) / $k, - 'lly' => min($b[1][1], $b[3][1]) / $k, - 'urx' => max($b[0][1], $b[2][1]) / $k, - 'ury' => max($b[1][1], $b[3][1]) / $k, - ); - } else if (!isset ($page[1][1]['/Parent'])) { - return false; - } else { - return $this->getPageBox($this->pdf_resolve_object($this->c, $page[1][1]['/Parent']), $box_index, $k); - } - } - - /** - * Get all page boxes by page no - * - * @param int The page number - * @param float Scale factor from user space units to points - * @return array - */ - function getPageBoxes($pageno, $k) { - return $this->_getPageBoxes($this->pages[$pageno - 1], $k); - } - - /** - * Get all boxes from /Page - * - * @param array a /Page - * @return array - */ - function _getPageBoxes($page, $k) { - $boxes = array(); - - foreach($this->availableBoxes AS $box) { - if ($_box = $this->getPageBox($page, $box, $k)) { - $boxes[$box] = $_box; - } - } - - return $boxes; - } - - /** - * Get the page rotation by pageno - * - * @param integer $pageno - * @return array - */ - function getPageRotation($pageno) { - return $this->_getPageRotation($this->pages[$pageno - 1]); - } - - function _getPageRotation($obj) { // $obj = /Page - $obj = $this->pdf_resolve_object($this->c, $obj); - if (isset ($obj[1][1]['/Rotate'])) { - $res = $this->pdf_resolve_object($this->c, $obj[1][1]['/Rotate']); - if ($res[0] == PDF_TYPE_OBJECT) - return $res[1]; - return $res; - } else { - if (!isset ($obj[1][1]['/Parent'])) { - return false; - } else { - $res = $this->_getPageRotation($obj[1][1]['/Parent']); - if ($res[0] == PDF_TYPE_OBJECT) - return $res[1]; - return $res; - } - } - } - - /** - * Read all /Page(es) - * - * @param object pdf_context - * @param array /Pages - * @param array the result-array - */ - function read_pages(&$c, &$pages, &$result) { - // Get the kids dictionary - $_kids = $this->pdf_resolve_object ($c, $pages[1][1]['/Kids']); - - if (!is_array($_kids)) - $this->error('Cannot find /Kids in current /Page-Dictionary'); - - if ($_kids[1][0] == PDF_TYPE_ARRAY) { - $kids = $_kids[1][1]; - } else { - $kids = $_kids[1]; - } - - foreach ($kids as $v) { - $pg = $this->pdf_resolve_object ($c, $v); - if ($pg[1][1]['/Type'][1] === '/Pages') { - // If one of the kids is an embedded - // /Pages array, resolve it as well. - $this->read_pages($c, $pg, $result); - } else { - $result[] = $pg; - } - } - } - - - - /** - * Get PDF-Version - * - * And reset the PDF Version used in FPDI if needed - */ - function getPDFVersion() { - parent::getPDFVersion(); - $this->fpdi->setPDFVersion(max($this->fpdi->getPDFVersion(), $this->pdfVersion)); - } +fpdi =& $fpdi; + + parent::pdf_parser($filename); + + // resolve Pages-Dictonary + $pages = $this->pdf_resolve_object($this->c, $this->root[1][1]['/Pages']); + + // Read pages + $this->read_pages($this->c, $pages, $this->pages); + + // count pages; + $this->page_count = count($this->pages); + } + + /** + * Overwrite parent::error() + * + * @param string $msg Error-Message + */ + function error($msg) { + $this->fpdi->error($msg); + } + + /** + * Get pagecount from sourcefile + * + * @return int + */ + function getPageCount() { + return $this->page_count; + } + + + /** + * Set pageno + * + * @param int $pageno Pagenumber to use + */ + function setPageno($pageno) { + $pageno = ((int) $pageno) - 1; + + if ($pageno < 0 || $pageno >= $this->getPageCount()) { + $this->fpdi->error('Pagenumber is wrong!'); + } + + $this->pageno = $pageno; + } + + /** + * Get page-resources from current page + * + * @return array + */ + function getPageResources() { + return $this->_getPageResources($this->pages[$this->pageno]); + } + + /** + * Get page-resources from /Page + * + * @param array $obj Array of pdf-data + */ + function _getPageResources ($obj) { // $obj = /Page + $obj = $this->pdf_resolve_object($this->c, $obj); + + // If the current object has a resources + // dictionary associated with it, we use + // it. Otherwise, we move back to its + // parent object. + if (isset ($obj[1][1]['/Resources'])) { + $res = $this->pdf_resolve_object($this->c, $obj[1][1]['/Resources']); + if ($res[0] == PDF_TYPE_OBJECT) + return $res[1]; + return $res; + } else { + if (!isset ($obj[1][1]['/Parent'])) { + return false; + } else { + $res = $this->_getPageResources($obj[1][1]['/Parent']); + if ($res[0] == PDF_TYPE_OBJECT) + return $res[1]; + return $res; + } + } + } + + + /** + * Get content of current page + * + * If more /Contents is an array, the streams are concated + * + * @return string + */ + function getContent() { + $buffer = ''; + + if (isset($this->pages[$this->pageno][1][1]['/Contents'])) { + $contents = $this->_getPageContent($this->pages[$this->pageno][1][1]['/Contents']); + foreach($contents AS $tmp_content) { + $buffer .= $this->_rebuildContentStream($tmp_content) . ' '; + } + } + + return $buffer; + } + + + /** + * Resolve all content-objects + * + * @param array $content_ref + * @return array + */ + function _getPageContent($content_ref) { + $contents = array(); + + if ($content_ref[0] == PDF_TYPE_OBJREF) { + $content = $this->pdf_resolve_object($this->c, $content_ref); + if ($content[1][0] == PDF_TYPE_ARRAY) { + $contents = $this->_getPageContent($content[1]); + } else { + $contents[] = $content; + } + } else if ($content_ref[0] == PDF_TYPE_ARRAY) { + foreach ($content_ref[1] AS $tmp_content_ref) { + $contents = array_merge($contents,$this->_getPageContent($tmp_content_ref)); + } + } + + return $contents; + } + + + /** + * Rebuild content-streams + * + * @param array $obj + * @return string + */ + function _rebuildContentStream($obj) { + $filters = array(); + + if (isset($obj[1][1]['/Filter'])) { + $_filter = $obj[1][1]['/Filter']; + + if ($_filter[0] == PDF_TYPE_OBJREF) { + $tmpFilter = $this->pdf_resolve_object($this->c, $_filter); + $_filter = $tmpFilter[1]; + } + + if ($_filter[0] == PDF_TYPE_TOKEN) { + $filters[] = $_filter; + } else if ($_filter[0] == PDF_TYPE_ARRAY) { + $filters = $_filter[1]; + } + } + + $stream = $obj[2][1]; + + foreach ($filters AS $_filter) { + switch ($_filter[1]) { + case '/FlateDecode': + case '/Fl': + // $stream .= "\x0F\x0D"; // in an errorious stream this suffix could work + // $stream .= "\x0A"; + // $stream .= "\x0D"; + if (function_exists('gzuncompress')) { + $stream = (strlen($stream) > 0) ? @gzuncompress($stream) : ''; + } else { + $this->error(sprintf('To handle %s filter, please compile php with zlib support.',$_filter[1])); + } + + if ($stream === false) { + $this->error('Error while decompressing stream.'); + } + break; + case '/LZWDecode': + include_once('filters/FilterLZW_FPDI.php'); + $decoder = new FilterLZW_FPDI($this->fpdi); + $stream = $decoder->decode($stream); + break; + case '/ASCII85Decode': + include_once('filters/FilterASCII85_FPDI.php'); + $decoder = new FilterASCII85_FPDI($this->fpdi); + $stream = $decoder->decode($stream); + break; + case null: + $stream = $stream; + break; + default: + $this->error(sprintf('Unsupported Filter: %s',$_filter[1])); + } + } + + return $stream; + } + + + /** + * Get a Box from a page + * Arrayformat is same as used by fpdf_tpl + * + * @param array $page a /Page + * @param string $box_index Type of Box @see $availableBoxes + * @param float Scale factor from user space units to points + * @return array + */ + function getPageBox($page, $box_index, $k) { + $page = $this->pdf_resolve_object($this->c, $page); + $box = null; + if (isset($page[1][1][$box_index])) + $box =& $page[1][1][$box_index]; + + if (!is_null($box) && $box[0] == PDF_TYPE_OBJREF) { + $tmp_box = $this->pdf_resolve_object($this->c, $box); + $box = $tmp_box[1]; + } + + if (!is_null($box) && $box[0] == PDF_TYPE_ARRAY) { + $b =& $box[1]; + return array('x' => $b[0][1] / $k, + 'y' => $b[1][1] / $k, + 'w' => abs($b[0][1] - $b[2][1]) / $k, + 'h' => abs($b[1][1] - $b[3][1]) / $k, + 'llx' => min($b[0][1], $b[2][1]) / $k, + 'lly' => min($b[1][1], $b[3][1]) / $k, + 'urx' => max($b[0][1], $b[2][1]) / $k, + 'ury' => max($b[1][1], $b[3][1]) / $k, + ); + } else if (!isset ($page[1][1]['/Parent'])) { + return false; + } else { + return $this->getPageBox($this->pdf_resolve_object($this->c, $page[1][1]['/Parent']), $box_index, $k); + } + } + + /** + * Get all page boxes by page no + * + * @param int The page number + * @param float Scale factor from user space units to points + * @return array + */ + function getPageBoxes($pageno, $k) { + return $this->_getPageBoxes($this->pages[$pageno - 1], $k); + } + + /** + * Get all boxes from /Page + * + * @param array a /Page + * @return array + */ + function _getPageBoxes($page, $k) { + $boxes = array(); + + foreach($this->availableBoxes AS $box) { + if ($_box = $this->getPageBox($page, $box, $k)) { + $boxes[$box] = $_box; + } + } + + return $boxes; + } + + /** + * Get the page rotation by pageno + * + * @param integer $pageno + * @return array + */ + function getPageRotation($pageno) { + return $this->_getPageRotation($this->pages[$pageno - 1]); + } + + function _getPageRotation($obj) { // $obj = /Page + $obj = $this->pdf_resolve_object($this->c, $obj); + if (isset ($obj[1][1]['/Rotate'])) { + $res = $this->pdf_resolve_object($this->c, $obj[1][1]['/Rotate']); + if ($res[0] == PDF_TYPE_OBJECT) + return $res[1]; + return $res; + } else { + if (!isset ($obj[1][1]['/Parent'])) { + return false; + } else { + $res = $this->_getPageRotation($obj[1][1]['/Parent']); + if ($res[0] == PDF_TYPE_OBJECT) + return $res[1]; + return $res; + } + } + } + + /** + * Read all /Page(es) + * + * @param object pdf_context + * @param array /Pages + * @param array the result-array + */ + function read_pages(&$c, &$pages, &$result) { + // Get the kids dictionary + $_kids = $this->pdf_resolve_object ($c, $pages[1][1]['/Kids']); + + if (!is_array($_kids)) + $this->error('Cannot find /Kids in current /Page-Dictionary'); + + if ($_kids[1][0] == PDF_TYPE_ARRAY) { + $kids = $_kids[1][1]; + } else { + $kids = $_kids[1]; + } + + foreach ($kids as $v) { + $pg = $this->pdf_resolve_object ($c, $v); + if ($pg[1][1]['/Type'][1] === '/Pages') { + // If one of the kids is an embedded + // /Pages array, resolve it as well. + $this->read_pages($c, $pg, $result); + } else { + $result[] = $pg; + } + } + } + + + + /** + * Get PDF-Version + * + * And reset the PDF Version used in FPDI if needed + */ + function getPDFVersion() { + parent::getPDFVersion(); + $this->fpdi->setPDFVersion(max($this->fpdi->getPDFVersion(), $this->pdfVersion)); + } } \ No newline at end of file diff --git a/htdocs/includes/fpdfi/pdf_context.php b/htdocs/includes/fpdfi/pdf_context.php index 435df1e83da..78b7b4ae6de 100755 --- a/htdocs/includes/fpdfi/pdf_context.php +++ b/htdocs/includes/fpdfi/pdf_context.php @@ -1,104 +1,104 @@ -file =& $f; - if (is_string($this->file)) - $this->_mode = 1; - $this->reset(); - } - - // Optionally move the file - // pointer to a new location - // and reset the buffered data - - function reset($pos = null, $l = 100) { - if ($this->_mode == 0) { - if (!is_null ($pos)) { - fseek ($this->file, $pos); - } - - $this->buffer = $l > 0 ? fread($this->file, $l) : ''; - $this->length = strlen($this->buffer); - if ($this->length < $l) - $this->increase_length($l - $this->length); - } else { - $this->buffer = $this->file; - $this->length = strlen($this->buffer); - } - $this->offset = 0; - $this->stack = array(); - } - - // Make sure that there is at least one - // character beyond the current offset in - // the buffer to prevent the tokenizer - // from attempting to access data that does - // not exist - - function ensure_content() { - if ($this->offset >= $this->length - 1) { - return $this->increase_length(); - } else { - return true; - } - } - - // Forcefully read more data into the buffer - - function increase_length($l = 100) { - if ($this->_mode == 0 && feof($this->file)) { - return false; - } else if ($this->_mode == 0) { - $totalLength = $this->length + $l; - do { - $toRead = $totalLength - $this->length; - if ($toRead < 1) - break; - - $this->buffer .= fread($this->file, $toRead); - } while ((($this->length = strlen($this->buffer)) != $totalLength) && !feof($this->file)); - - return true; - } else { - return false; - } - } - } +file =& $f; + if (is_string($this->file)) + $this->_mode = 1; + $this->reset(); + } + + // Optionally move the file + // pointer to a new location + // and reset the buffered data + + function reset($pos = null, $l = 100) { + if ($this->_mode == 0) { + if (!is_null ($pos)) { + fseek ($this->file, $pos); + } + + $this->buffer = $l > 0 ? fread($this->file, $l) : ''; + $this->length = strlen($this->buffer); + if ($this->length < $l) + $this->increase_length($l - $this->length); + } else { + $this->buffer = $this->file; + $this->length = strlen($this->buffer); + } + $this->offset = 0; + $this->stack = array(); + } + + // Make sure that there is at least one + // character beyond the current offset in + // the buffer to prevent the tokenizer + // from attempting to access data that does + // not exist + + function ensure_content() { + if ($this->offset >= $this->length - 1) { + return $this->increase_length(); + } else { + return true; + } + } + + // Forcefully read more data into the buffer + + function increase_length($l = 100) { + if ($this->_mode == 0 && feof($this->file)) { + return false; + } else if ($this->_mode == 0) { + $totalLength = $this->length + $l; + do { + $toRead = $totalLength - $this->length; + if ($toRead < 1) + break; + + $this->buffer .= fread($this->file, $toRead); + } while ((($this->length = strlen($this->buffer)) != $totalLength) && !feof($this->file)); + + return true; + } else { + return false; + } + } + } } \ No newline at end of file diff --git a/htdocs/includes/fpdfi/pdf_parser.php b/htdocs/includes/fpdfi/pdf_parser.php index 4c6dd8e83e3..238e10c0def 100755 --- a/htdocs/includes/fpdfi/pdf_parser.php +++ b/htdocs/includes/fpdfi/pdf_parser.php @@ -1,719 +1,719 @@ -filename = $filename; - - $this->f = @fopen($this->filename, 'rb'); - - if (!$this->f) - $this->error(sprintf('Cannot open %s !', $filename)); - - $this->getPDFVersion(); - - $this->c = new pdf_context($this->f); - - // Read xref-Data - $this->xref = array(); - $this->pdf_read_xref($this->xref, $this->pdf_find_xref()); - - // Check for Encryption - $this->getEncryption(); - - // Read root - $this->pdf_read_root(); - } - - /** - * Close the opened file - */ - function closeFile() { - if (isset($this->f) && is_resource($this->f)) { - fclose($this->f); - unset($this->f); - } - } - - /** - * Print Error and die - * - * @param string $msg Error-Message - */ - function error($msg) { - die('PDF-Parser Error: ' . $msg); - } - - /** - * Check Trailer for Encryption - */ - function getEncryption() { - if (isset($this->xref['trailer'][1]['/Encrypt'])) { - $this->error('File is encrypted!'); - } - } - - /** - * Find/Return /Root - * - * @return array - */ - function pdf_find_root() { - if ($this->xref['trailer'][1]['/Root'][0] != PDF_TYPE_OBJREF) { - $this->error('Wrong Type of Root-Element! Must be an indirect reference'); - } - - return $this->xref['trailer'][1]['/Root']; - } - - /** - * Read the /Root - */ - function pdf_read_root() { - // read root - $this->root = $this->pdf_resolve_object($this->c, $this->pdf_find_root()); - } - - /** - * Get PDF-Version - * - * And reset the PDF Version used in FPDI if needed - */ - function getPDFVersion() { - fseek($this->f, 0); - preg_match('/\d\.\d/',fread($this->f, 16), $m); - if (isset($m[0])) - $this->pdfVersion = $m[0]; - return $this->pdfVersion; - } - - /** - * Find the xref-Table - */ - function pdf_find_xref() { - $toRead = 1500; - - $stat = fseek ($this->f, -$toRead, SEEK_END); - if ($stat === -1) { - fseek ($this->f, 0); - } - $data = fread($this->f, $toRead); - - $pos = strlen($data) - strpos(strrev($data), strrev('startxref')); - $data = substr($data, $pos); - - if (!preg_match('/\s*(\d+).*$/s', $data, $matches)) { - $this->error('Unable to find pointer to xref table'); - } - - return (int) $matches[1]; - } - - /** - * Read xref-table - * - * @param array $result Array of xref-table - * @param integer $offset of xref-table - */ - function pdf_read_xref(&$result, $offset) { - $o_pos = $offset-min(20, $offset); - fseek($this->f, $o_pos); // set some bytes backwards to fetch errorious docs - - $data = fread($this->f, 100); - - $xrefPos = strrpos($data, 'xref'); - - if ($xrefPos === false) { - fseek($this->f, $offset); - $c = new pdf_context($this->f); - $xrefStreamObjDec = $this->pdf_read_value($c); - - if (is_array($xrefStreamObjDec) && isset($xrefStreamObjDec[0]) && $xrefStreamObjDec[0] == PDF_TYPE_OBJDEC) { - $this->error(sprintf('This document (%s) probably uses a compression technique which is not supported by the free parser shipped with FPDI.', $this->filename)); - } else { - $this->error('Unable to find xref table.'); - } - } - - if (!isset($result['xref_location'])) { - $result['xref_location'] = $o_pos + $xrefPos; - $result['max_object'] = 0; - } - - $cylces = -1; - $bytesPerCycle = 100; - - fseek($this->f, $o_pos = $o_pos + $xrefPos + 4); // set the handle directly after the "xref"-keyword - $data = fread($this->f, $bytesPerCycle); - - while (($trailerPos = strpos($data, 'trailer', max($bytesPerCycle * $cylces++, 0))) === false && !feof($this->f)) { - $data .= fread($this->f, $bytesPerCycle); - } - - if ($trailerPos === false) { - $this->error('Trailer keyword not found after xref table'); - } - - $data = substr($data, 0, $trailerPos); - - // get Line-Ending - preg_match_all("/(\r\n|\n|\r)/", substr($data, 0, 100), $m); // check the first 100 bytes for linebreaks - - $differentLineEndings = count(array_unique($m[0])); - if ($differentLineEndings > 1) { - $lines = preg_split("/(\r\n|\n|\r)/", $data, -1, PREG_SPLIT_NO_EMPTY); - } else { - $lines = explode($m[0][1], $data); - } - - $data = $differentLineEndings = $m = null; - unset($data, $differentLineEndings, $m); - - $linesCount = count($lines); - - $start = 1; - - for ($i = 0; $i < $linesCount; $i++) { - $line = trim($lines[$i]); - if ($line) { - $pieces = explode(' ', $line); - $c = count($pieces); - switch($c) { - case 2: - $start = (int)$pieces[0]; - $end = $start + (int)$pieces[1]; - if ($end > $result['max_object']) - $result['max_object'] = $end; - break; - case 3: - if (!isset($result['xref'][$start])) - $result['xref'][$start] = array(); - - if (!array_key_exists($gen = (int) $pieces[1], $result['xref'][$start])) { - $result['xref'][$start][$gen] = $pieces[2] == 'n' ? (int) $pieces[0] : null; - } - $start++; - break; - default: - $this->error('Unexpected data in xref table'); - } - } - } - - $lines = $pieces = $line = $start = $end = $gen = null; - unset($lines, $pieces, $line, $start, $end, $gen); - - fseek($this->f, $o_pos + $trailerPos + 7); - - $c = new pdf_context($this->f); - $trailer = $this->pdf_read_value($c); - - $c = null; - unset($c); - - if (!isset($result['trailer'])) { - $result['trailer'] = $trailer; - } - - if (isset($trailer[1]['/Prev'])) { - $this->pdf_read_xref($result, $trailer[1]['/Prev'][1]); - } - - $trailer = null; - unset($trailer); - - return true; - } - - /** - * Reads an Value - * - * @param object $c pdf_context - * @param string $token a Token - * @return mixed - */ - function pdf_read_value(&$c, $token = null) { - if (is_null($token)) { - $token = $this->pdf_read_token($c); - } - - if ($token === false) { - return false; - } - - switch ($token) { - case '<': - // This is a hex string. - // Read the value, then the terminator - - $pos = $c->offset; - - while(1) { - - $match = strpos ($c->buffer, '>', $pos); - - // If you can't find it, try - // reading more data from the stream - - if ($match === false) { - if (!$c->increase_length()) { - return false; - } else { - continue; - } - } - - $result = substr ($c->buffer, $c->offset, $match - $c->offset); - $c->offset = $match + 1; - - return array (PDF_TYPE_HEX, $result); - } - - break; - case '<<': - // This is a dictionary. - - $result = array(); - - // Recurse into this function until we reach - // the end of the dictionary. - while (($key = $this->pdf_read_token($c)) !== '>>') { - if ($key === false) { - return false; - } - - if (($value = $this->pdf_read_value($c)) === false) { - return false; - } - - // Catch missing value - if ($value[0] == PDF_TYPE_TOKEN && $value[1] == '>>') { - $result[$key] = array(PDF_TYPE_NULL); - break; - } - - $result[$key] = $value; - } - - return array (PDF_TYPE_DICTIONARY, $result); - - case '[': - // This is an array. - - $result = array(); - - // Recurse into this function until we reach - // the end of the array. - while (($token = $this->pdf_read_token($c)) !== ']') { - if ($token === false) { - return false; - } - - if (($value = $this->pdf_read_value($c, $token)) === false) { - return false; - } - - $result[] = $value; - } - - return array (PDF_TYPE_ARRAY, $result); - - case '(' : - // This is a string - $pos = $c->offset; - - $openBrackets = 1; - do { - for (; $openBrackets != 0 && $pos < $c->length; $pos++) { - switch (ord($c->buffer[$pos])) { - case 0x28: // '(' - $openBrackets++; - break; - case 0x29: // ')' - $openBrackets--; - break; - case 0x5C: // backslash - $pos++; - } - } - } while($openBrackets != 0 && $c->increase_length()); - - $result = substr($c->buffer, $c->offset, $pos - $c->offset - 1); - $c->offset = $pos; - - return array (PDF_TYPE_STRING, $result); - - case 'stream': - $o_pos = ftell($c->file)-strlen($c->buffer); - $o_offset = $c->offset; - - $c->reset($startpos = $o_pos + $o_offset); - - $e = 0; // ensure line breaks in front of the stream - if ($c->buffer[0] == chr(10) || $c->buffer[0] == chr(13)) - $e++; - if ($c->buffer[1] == chr(10) && $c->buffer[0] != chr(10)) - $e++; - - if ($this->actual_obj[1][1]['/Length'][0] == PDF_TYPE_OBJREF) { - $tmp_c = new pdf_context($this->f); - $tmp_length = $this->pdf_resolve_object($tmp_c, $this->actual_obj[1][1]['/Length']); - $length = $tmp_length[1][1]; - } else { - $length = $this->actual_obj[1][1]['/Length'][1]; - } - - if ($length > 0) { - $c->reset($startpos + $e,$length); - $v = $c->buffer; - } else { - $v = ''; - } - $c->reset($startpos + $e + $length + 9); // 9 = strlen("endstream") - - return array(PDF_TYPE_STREAM, $v); - - default : - if (is_numeric ($token)) { - // A numeric token. Make sure that - // it is not part of something else. - if (($tok2 = $this->pdf_read_token ($c)) !== false) { - if (is_numeric ($tok2)) { - - // Two numeric tokens in a row. - // In this case, we're probably in - // front of either an object reference - // or an object specification. - // Determine the case and return the data - if (($tok3 = $this->pdf_read_token ($c)) !== false) { - switch ($tok3) { - case 'obj': - return array (PDF_TYPE_OBJDEC, (int) $token, (int) $tok2); - case 'R': - return array (PDF_TYPE_OBJREF, (int) $token, (int) $tok2); - } - // If we get to this point, that numeric value up - // there was just a numeric value. Push the extra - // tokens back into the stack and return the value. - array_push ($c->stack, $tok3); - } - } - - array_push ($c->stack, $tok2); - } - - if ($token === (string)((int)$token)) - return array (PDF_TYPE_NUMERIC, (int)$token); - else - return array (PDF_TYPE_REAL, (float)$token); - } else if ($token == 'true' || $token == 'false') { - return array (PDF_TYPE_BOOLEAN, $token == 'true'); - } else if ($token == 'null') { - return array (PDF_TYPE_NULL); - } else { - // Just a token. Return it. - return array (PDF_TYPE_TOKEN, $token); - } - } - } - - /** - * Resolve an object - * - * @param object $c pdf_context - * @param array $obj_spec The object-data - * @param boolean $encapsulate Must set to true, cause the parsing and fpdi use this method only without this para - */ - function pdf_resolve_object(&$c, $obj_spec, $encapsulate = true) { - // Exit if we get invalid data - if (!is_array($obj_spec)) { - $ret = false; - return $ret; - } - - if ($obj_spec[0] == PDF_TYPE_OBJREF) { - - // This is a reference, resolve it - if (isset($this->xref['xref'][$obj_spec[1]][$obj_spec[2]])) { - - // Save current file position - // This is needed if you want to resolve - // references while you're reading another object - // (e.g.: if you need to determine the length - // of a stream) - - $old_pos = ftell($c->file); - - // Reposition the file pointer and - // load the object header. - - $c->reset($this->xref['xref'][$obj_spec[1]][$obj_spec[2]]); - - $header = $this->pdf_read_value($c); - - if ($header[0] != PDF_TYPE_OBJDEC || $header[1] != $obj_spec[1] || $header[2] != $obj_spec[2]) { - $toSearchFor = $obj_spec[1] . ' ' . $obj_spec[2] . ' obj'; - if (preg_match('/' . $toSearchFor . '/', $c->buffer)) { - $c->offset = strpos($c->buffer, $toSearchFor) + strlen($toSearchFor); - // reset stack - $c->stack = array(); - } else { - $this->error("Unable to find object ({$obj_spec[1]}, {$obj_spec[2]}) at expected location"); - } - } - - // If we're being asked to store all the information - // about the object, we add the object ID and generation - // number for later use - $result = array(); - $this->actual_obj =& $result; - if ($encapsulate) { - $result = array ( - PDF_TYPE_OBJECT, - 'obj' => $obj_spec[1], - 'gen' => $obj_spec[2] - ); - } - - // Now simply read the object data until - // we encounter an end-of-object marker - while(1) { - $value = $this->pdf_read_value($c); - if ($value === false || count($result) > 4) { - // in this case the parser coudn't find an endobj so we break here - break; - } - - if ($value[0] == PDF_TYPE_TOKEN && $value[1] === 'endobj') { - break; - } - - $result[] = $value; - } - - $c->reset($old_pos); - - if (isset($result[2][0]) && $result[2][0] == PDF_TYPE_STREAM) { - $result[0] = PDF_TYPE_STREAM; - } - - return $result; - } - } else { - return $obj_spec; - } - } - - - - /** - * Reads a token from the file - * - * @param object $c pdf_context - * @return mixed - */ - function pdf_read_token(&$c) - { - // If there is a token available - // on the stack, pop it out and - // return it. - - if (count($c->stack)) { - return array_pop($c->stack); - } - - // Strip away any whitespace - - do { - if (!$c->ensure_content()) { - return false; - } - $c->offset += strspn($c->buffer, " \n\r\t", $c->offset); - } while ($c->offset >= $c->length - 1); - - // Get the first character in the stream - - $char = $c->buffer[$c->offset++]; - - switch ($char) { - - case '[': - case ']': - case '(': - case ')': - - // This is either an array or literal string - // delimiter, Return it - - return $char; - - case '<': - case '>': - - // This could either be a hex string or - // dictionary delimiter. Determine the - // appropriate case and return the token - - if ($c->buffer[$c->offset] == $char) { - if (!$c->ensure_content()) { - return false; - } - $c->offset++; - return $char . $char; - } else { - return $char; - } - - case '%': - - // This is a comment - jump over it! - - $pos = $c->offset; - while(1) { - $match = preg_match("/(\r\n|\r|\n)/", $c->buffer, $m, PREG_OFFSET_CAPTURE, $pos); - if ($match === 0) { - if (!$c->increase_length()) { - return false; - } else { - continue; - } - } - - $c->offset = $m[0][1]+strlen($m[0][0]); - - return $this->pdf_read_token($c); - } - - default: - - // This is "another" type of token (probably - // a dictionary entry or a numeric value) - // Find the end and return it. - - if (!$c->ensure_content()) { - return false; - } - - while(1) { - - // Determine the length of the token - - $pos = strcspn($c->buffer, " %[]<>()\r\n\t/", $c->offset); - - if ($c->offset + $pos <= $c->length - 1) { - break; - } else { - // If the script reaches this point, - // the token may span beyond the end - // of the current buffer. Therefore, - // we increase the size of the buffer - // and try again--just to be safe. - - $c->increase_length(); - } - } - - $result = substr($c->buffer, $c->offset - 1, $pos + 1); - - $c->offset += $pos; - return $result; - } - } - } -} +filename = $filename; + + $this->f = @fopen($this->filename, 'rb'); + + if (!$this->f) + $this->error(sprintf('Cannot open %s !', $filename)); + + $this->getPDFVersion(); + + $this->c = new pdf_context($this->f); + + // Read xref-Data + $this->xref = array(); + $this->pdf_read_xref($this->xref, $this->pdf_find_xref()); + + // Check for Encryption + $this->getEncryption(); + + // Read root + $this->pdf_read_root(); + } + + /** + * Close the opened file + */ + function closeFile() { + if (isset($this->f) && is_resource($this->f)) { + fclose($this->f); + unset($this->f); + } + } + + /** + * Print Error and die + * + * @param string $msg Error-Message + */ + function error($msg) { + die('PDF-Parser Error: ' . $msg); + } + + /** + * Check Trailer for Encryption + */ + function getEncryption() { + if (isset($this->xref['trailer'][1]['/Encrypt'])) { + $this->error('File is encrypted!'); + } + } + + /** + * Find/Return /Root + * + * @return array + */ + function pdf_find_root() { + if ($this->xref['trailer'][1]['/Root'][0] != PDF_TYPE_OBJREF) { + $this->error('Wrong Type of Root-Element! Must be an indirect reference'); + } + + return $this->xref['trailer'][1]['/Root']; + } + + /** + * Read the /Root + */ + function pdf_read_root() { + // read root + $this->root = $this->pdf_resolve_object($this->c, $this->pdf_find_root()); + } + + /** + * Get PDF-Version + * + * And reset the PDF Version used in FPDI if needed + */ + function getPDFVersion() { + fseek($this->f, 0); + preg_match('/\d\.\d/',fread($this->f, 16), $m); + if (isset($m[0])) + $this->pdfVersion = $m[0]; + return $this->pdfVersion; + } + + /** + * Find the xref-Table + */ + function pdf_find_xref() { + $toRead = 1500; + + $stat = fseek ($this->f, -$toRead, SEEK_END); + if ($stat === -1) { + fseek ($this->f, 0); + } + $data = fread($this->f, $toRead); + + $pos = strlen($data) - strpos(strrev($data), strrev('startxref')); + $data = substr($data, $pos); + + if (!preg_match('/\s*(\d+).*$/s', $data, $matches)) { + $this->error('Unable to find pointer to xref table'); + } + + return (int) $matches[1]; + } + + /** + * Read xref-table + * + * @param array $result Array of xref-table + * @param integer $offset of xref-table + */ + function pdf_read_xref(&$result, $offset) { + $o_pos = $offset-min(20, $offset); + fseek($this->f, $o_pos); // set some bytes backwards to fetch errorious docs + + $data = fread($this->f, 100); + + $xrefPos = strrpos($data, 'xref'); + + if ($xrefPos === false) { + fseek($this->f, $offset); + $c = new pdf_context($this->f); + $xrefStreamObjDec = $this->pdf_read_value($c); + + if (is_array($xrefStreamObjDec) && isset($xrefStreamObjDec[0]) && $xrefStreamObjDec[0] == PDF_TYPE_OBJDEC) { + $this->error(sprintf('This document (%s) probably uses a compression technique which is not supported by the free parser shipped with FPDI.', $this->filename)); + } else { + $this->error('Unable to find xref table.'); + } + } + + if (!isset($result['xref_location'])) { + $result['xref_location'] = $o_pos + $xrefPos; + $result['max_object'] = 0; + } + + $cylces = -1; + $bytesPerCycle = 100; + + fseek($this->f, $o_pos = $o_pos + $xrefPos + 4); // set the handle directly after the "xref"-keyword + $data = fread($this->f, $bytesPerCycle); + + while (($trailerPos = strpos($data, 'trailer', max($bytesPerCycle * $cylces++, 0))) === false && !feof($this->f)) { + $data .= fread($this->f, $bytesPerCycle); + } + + if ($trailerPos === false) { + $this->error('Trailer keyword not found after xref table'); + } + + $data = substr($data, 0, $trailerPos); + + // get Line-Ending + preg_match_all("/(\r\n|\n|\r)/", substr($data, 0, 100), $m); // check the first 100 bytes for linebreaks + + $differentLineEndings = count(array_unique($m[0])); + if ($differentLineEndings > 1) { + $lines = preg_split("/(\r\n|\n|\r)/", $data, -1, PREG_SPLIT_NO_EMPTY); + } else { + $lines = explode($m[0][1], $data); + } + + $data = $differentLineEndings = $m = null; + unset($data, $differentLineEndings, $m); + + $linesCount = count($lines); + + $start = 1; + + for ($i = 0; $i < $linesCount; $i++) { + $line = trim($lines[$i]); + if ($line) { + $pieces = explode(' ', $line); + $c = count($pieces); + switch($c) { + case 2: + $start = (int)$pieces[0]; + $end = $start + (int)$pieces[1]; + if ($end > $result['max_object']) + $result['max_object'] = $end; + break; + case 3: + if (!isset($result['xref'][$start])) + $result['xref'][$start] = array(); + + if (!array_key_exists($gen = (int) $pieces[1], $result['xref'][$start])) { + $result['xref'][$start][$gen] = $pieces[2] == 'n' ? (int) $pieces[0] : null; + } + $start++; + break; + default: + $this->error('Unexpected data in xref table'); + } + } + } + + $lines = $pieces = $line = $start = $end = $gen = null; + unset($lines, $pieces, $line, $start, $end, $gen); + + fseek($this->f, $o_pos + $trailerPos + 7); + + $c = new pdf_context($this->f); + $trailer = $this->pdf_read_value($c); + + $c = null; + unset($c); + + if (!isset($result['trailer'])) { + $result['trailer'] = $trailer; + } + + if (isset($trailer[1]['/Prev'])) { + $this->pdf_read_xref($result, $trailer[1]['/Prev'][1]); + } + + $trailer = null; + unset($trailer); + + return true; + } + + /** + * Reads an Value + * + * @param object $c pdf_context + * @param string $token a Token + * @return mixed + */ + function pdf_read_value(&$c, $token = null) { + if (is_null($token)) { + $token = $this->pdf_read_token($c); + } + + if ($token === false) { + return false; + } + + switch ($token) { + case '<': + // This is a hex string. + // Read the value, then the terminator + + $pos = $c->offset; + + while(1) { + + $match = strpos ($c->buffer, '>', $pos); + + // If you can't find it, try + // reading more data from the stream + + if ($match === false) { + if (!$c->increase_length()) { + return false; + } else { + continue; + } + } + + $result = substr ($c->buffer, $c->offset, $match - $c->offset); + $c->offset = $match + 1; + + return array (PDF_TYPE_HEX, $result); + } + + break; + case '<<': + // This is a dictionary. + + $result = array(); + + // Recurse into this function until we reach + // the end of the dictionary. + while (($key = $this->pdf_read_token($c)) !== '>>') { + if ($key === false) { + return false; + } + + if (($value = $this->pdf_read_value($c)) === false) { + return false; + } + + // Catch missing value + if ($value[0] == PDF_TYPE_TOKEN && $value[1] == '>>') { + $result[$key] = array(PDF_TYPE_NULL); + break; + } + + $result[$key] = $value; + } + + return array (PDF_TYPE_DICTIONARY, $result); + + case '[': + // This is an array. + + $result = array(); + + // Recurse into this function until we reach + // the end of the array. + while (($token = $this->pdf_read_token($c)) !== ']') { + if ($token === false) { + return false; + } + + if (($value = $this->pdf_read_value($c, $token)) === false) { + return false; + } + + $result[] = $value; + } + + return array (PDF_TYPE_ARRAY, $result); + + case '(' : + // This is a string + $pos = $c->offset; + + $openBrackets = 1; + do { + for (; $openBrackets != 0 && $pos < $c->length; $pos++) { + switch (ord($c->buffer[$pos])) { + case 0x28: // '(' + $openBrackets++; + break; + case 0x29: // ')' + $openBrackets--; + break; + case 0x5C: // backslash + $pos++; + } + } + } while($openBrackets != 0 && $c->increase_length()); + + $result = substr($c->buffer, $c->offset, $pos - $c->offset - 1); + $c->offset = $pos; + + return array (PDF_TYPE_STRING, $result); + + case 'stream': + $o_pos = ftell($c->file)-strlen($c->buffer); + $o_offset = $c->offset; + + $c->reset($startpos = $o_pos + $o_offset); + + $e = 0; // ensure line breaks in front of the stream + if ($c->buffer[0] == chr(10) || $c->buffer[0] == chr(13)) + $e++; + if ($c->buffer[1] == chr(10) && $c->buffer[0] != chr(10)) + $e++; + + if ($this->actual_obj[1][1]['/Length'][0] == PDF_TYPE_OBJREF) { + $tmp_c = new pdf_context($this->f); + $tmp_length = $this->pdf_resolve_object($tmp_c, $this->actual_obj[1][1]['/Length']); + $length = $tmp_length[1][1]; + } else { + $length = $this->actual_obj[1][1]['/Length'][1]; + } + + if ($length > 0) { + $c->reset($startpos + $e,$length); + $v = $c->buffer; + } else { + $v = ''; + } + $c->reset($startpos + $e + $length + 9); // 9 = strlen("endstream") + + return array(PDF_TYPE_STREAM, $v); + + default : + if (is_numeric ($token)) { + // A numeric token. Make sure that + // it is not part of something else. + if (($tok2 = $this->pdf_read_token ($c)) !== false) { + if (is_numeric ($tok2)) { + + // Two numeric tokens in a row. + // In this case, we're probably in + // front of either an object reference + // or an object specification. + // Determine the case and return the data + if (($tok3 = $this->pdf_read_token ($c)) !== false) { + switch ($tok3) { + case 'obj': + return array (PDF_TYPE_OBJDEC, (int) $token, (int) $tok2); + case 'R': + return array (PDF_TYPE_OBJREF, (int) $token, (int) $tok2); + } + // If we get to this point, that numeric value up + // there was just a numeric value. Push the extra + // tokens back into the stack and return the value. + array_push ($c->stack, $tok3); + } + } + + array_push ($c->stack, $tok2); + } + + if ($token === (string)((int)$token)) + return array (PDF_TYPE_NUMERIC, (int)$token); + else + return array (PDF_TYPE_REAL, (float)$token); + } else if ($token == 'true' || $token == 'false') { + return array (PDF_TYPE_BOOLEAN, $token == 'true'); + } else if ($token == 'null') { + return array (PDF_TYPE_NULL); + } else { + // Just a token. Return it. + return array (PDF_TYPE_TOKEN, $token); + } + } + } + + /** + * Resolve an object + * + * @param object $c pdf_context + * @param array $obj_spec The object-data + * @param boolean $encapsulate Must set to true, cause the parsing and fpdi use this method only without this para + */ + function pdf_resolve_object(&$c, $obj_spec, $encapsulate = true) { + // Exit if we get invalid data + if (!is_array($obj_spec)) { + $ret = false; + return $ret; + } + + if ($obj_spec[0] == PDF_TYPE_OBJREF) { + + // This is a reference, resolve it + if (isset($this->xref['xref'][$obj_spec[1]][$obj_spec[2]])) { + + // Save current file position + // This is needed if you want to resolve + // references while you're reading another object + // (e.g.: if you need to determine the length + // of a stream) + + $old_pos = ftell($c->file); + + // Reposition the file pointer and + // load the object header. + + $c->reset($this->xref['xref'][$obj_spec[1]][$obj_spec[2]]); + + $header = $this->pdf_read_value($c); + + if ($header[0] != PDF_TYPE_OBJDEC || $header[1] != $obj_spec[1] || $header[2] != $obj_spec[2]) { + $toSearchFor = $obj_spec[1] . ' ' . $obj_spec[2] . ' obj'; + if (preg_match('/' . $toSearchFor . '/', $c->buffer)) { + $c->offset = strpos($c->buffer, $toSearchFor) + strlen($toSearchFor); + // reset stack + $c->stack = array(); + } else { + $this->error("Unable to find object ({$obj_spec[1]}, {$obj_spec[2]}) at expected location"); + } + } + + // If we're being asked to store all the information + // about the object, we add the object ID and generation + // number for later use + $result = array(); + $this->actual_obj =& $result; + if ($encapsulate) { + $result = array ( + PDF_TYPE_OBJECT, + 'obj' => $obj_spec[1], + 'gen' => $obj_spec[2] + ); + } + + // Now simply read the object data until + // we encounter an end-of-object marker + while(1) { + $value = $this->pdf_read_value($c); + if ($value === false || count($result) > 4) { + // in this case the parser coudn't find an endobj so we break here + break; + } + + if ($value[0] == PDF_TYPE_TOKEN && $value[1] === 'endobj') { + break; + } + + $result[] = $value; + } + + $c->reset($old_pos); + + if (isset($result[2][0]) && $result[2][0] == PDF_TYPE_STREAM) { + $result[0] = PDF_TYPE_STREAM; + } + + return $result; + } + } else { + return $obj_spec; + } + } + + + + /** + * Reads a token from the file + * + * @param object $c pdf_context + * @return mixed + */ + function pdf_read_token(&$c) + { + // If there is a token available + // on the stack, pop it out and + // return it. + + if (count($c->stack)) { + return array_pop($c->stack); + } + + // Strip away any whitespace + + do { + if (!$c->ensure_content()) { + return false; + } + $c->offset += strspn($c->buffer, " \n\r\t", $c->offset); + } while ($c->offset >= $c->length - 1); + + // Get the first character in the stream + + $char = $c->buffer[$c->offset++]; + + switch ($char) { + + case '[': + case ']': + case '(': + case ')': + + // This is either an array or literal string + // delimiter, Return it + + return $char; + + case '<': + case '>': + + // This could either be a hex string or + // dictionary delimiter. Determine the + // appropriate case and return the token + + if ($c->buffer[$c->offset] == $char) { + if (!$c->ensure_content()) { + return false; + } + $c->offset++; + return $char . $char; + } else { + return $char; + } + + case '%': + + // This is a comment - jump over it! + + $pos = $c->offset; + while(1) { + $match = preg_match("/(\r\n|\r|\n)/", $c->buffer, $m, PREG_OFFSET_CAPTURE, $pos); + if ($match === 0) { + if (!$c->increase_length()) { + return false; + } else { + continue; + } + } + + $c->offset = $m[0][1]+strlen($m[0][0]); + + return $this->pdf_read_token($c); + } + + default: + + // This is "another" type of token (probably + // a dictionary entry or a numeric value) + // Find the end and return it. + + if (!$c->ensure_content()) { + return false; + } + + while(1) { + + // Determine the length of the token + + $pos = strcspn($c->buffer, " %[]<>()\r\n\t/", $c->offset); + + if ($c->offset + $pos <= $c->length - 1) { + break; + } else { + // If the script reaches this point, + // the token may span beyond the end + // of the current buffer. Therefore, + // we increase the size of the buffer + // and try again--just to be safe. + + $c->increase_length(); + } + } + + $result = substr($c->buffer, $c->offset - 1, $pos + 1); + + $c->offset += $pos; + return $result; + } + } + } +} diff --git a/htdocs/includes/tcpdf/config/lang/bul.php b/htdocs/includes/tcpdf/config/lang/bul.php index d7bbaaf6a30..00a44ef03e4 100644 --- a/htdocs/includes/tcpdf/config/lang/bul.php +++ b/htdocs/includes/tcpdf/config/lang/bul.php @@ -1,47 +1,47 @@ - --- --- This program is free software; you can redistribute it and/or modify --- it under the terms of the GNU General Public License as published by --- the Free Software Foundation; either version 2 of the License, or --- (at your option) any later version. --- --- This program 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 General Public License for more details. --- --- You should have received a copy of the GNU General Public License --- along with this program. If not, see . --- --- ======================================================================== - -create table llx_c_availability -( - rowid integer AUTO_INCREMENT PRIMARY KEY, - code varchar(30) NOT NULL, - label varchar(60) NOT NULL, - active tinyint DEFAULT 1 NOT NULL - -)ENGINE=innodb; +-- ======================================================================== +-- Copyright (C) 2011 Philippe GRAND +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 2 of the License, or +-- (at your option) any later version. +-- +-- This program 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 General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see . +-- +-- ======================================================================== + +create table llx_c_availability +( + rowid integer AUTO_INCREMENT PRIMARY KEY, + code varchar(30) NOT NULL, + label varchar(60) NOT NULL, + active tinyint DEFAULT 1 NOT NULL + +)ENGINE=innodb; diff --git a/htdocs/langs/en_US/install.lang b/htdocs/langs/en_US/install.lang index f111bfad1d6..a5d3d5e7ce8 100644 --- a/htdocs/langs/en_US/install.lang +++ b/htdocs/langs/en_US/install.lang @@ -65,7 +65,7 @@ DatabaseSuperUserAccess=Database server - Superuser access CheckToCreateDatabase=Check box if database does not exist and must be created.
In this case, you must fill the login/password for superuser account at the bottom of this page. CheckToCreateUser=Check box if database owner does not exist and must be created.
In this case, you must choose its login and password and also fill the login/password for the superuser account at the bottom of this page. If this box is unchecked, owner database and its passwords must exists. Experimental=(experimental) -DatabaseRootLoginDescription=Login of the user allowed to create new databases or new users, useless if your database and your database login already exists (like when you're hosted by a web hosting provider). +DatabaseRootLoginDescription=Login of the user allowed to create new databases or new users, mandatory if your database or its owner does not already exists. KeepEmptyIfNoPassword=Leave empty if user has no password (avoid this) SaveConfigurationFile=Save values ConfigurationSaving=Saving configuration file diff --git a/htdocs/langs/es_ES/suppliers.lang b/htdocs/langs/es_ES/suppliers.lang index e500aea17bb..69846ff3daa 100644 --- a/htdocs/langs/es_ES/suppliers.lang +++ b/htdocs/langs/es_ES/suppliers.lang @@ -12,7 +12,7 @@ ShowSupplier=Mostrar proveedor OrderDate=Fecha de pedido BuyingPrice=Precio de compra BuyingPriceMin=Precio mínimo de compra -BuyingPriceMinShort=Precio mín compra +BuyingPriceMinShort=Precio mín. compra AddSupplierPrice=Añadir precio de proveedor ChangeSupplierPrice=Modificar precio de proveedor ErrorSupplierCountryIsNotDefined=El país de este proveedor no está definido, corrígalo en su ficha diff --git a/htdocs/langs/es_ES/withdrawals.lang b/htdocs/langs/es_ES/withdrawals.lang index bbbee4a6198..75156b22660 100644 --- a/htdocs/langs/es_ES/withdrawals.lang +++ b/htdocs/langs/es_ES/withdrawals.lang @@ -77,7 +77,7 @@ WithBankUsingRIB=Para las cuentas bancarias que utilizan CCC WithBankUsingBANBIC=Para las cuentas bancarias que utilizan el código BAN/BIC/SWIFT BankToReceiveWithdraw=Cuenta bancaria receptora de las domiciliaciones CreditDate=Abonada el -WithdrawalFileNotCapable=No es posible generar fichero bancario de domiciliacion para su pais +WithdrawalFileNotCapable=No es posible generar el fichero bancario de domiciliación para su país. ShowWithdraw=Ver domiciliación IfInvoiceNeedOnWithdrawPaymentWontBeClosed=Sin embargo, si la factura tiene pendiente algún pago por domiciliación, no será cerrada para permitir la gestión de la domiciliación. DoStandingOrdersBeforePayments=Esta pestaña le permite realizar una petición de domiciliación. Una vez terminada, puede ingresar el pago en la factura para proceder a su cierre. diff --git a/htdocs/langs/fr_FR/install.lang b/htdocs/langs/fr_FR/install.lang index da7fbe1b610..5a34feaf94e 100644 --- a/htdocs/langs/fr_FR/install.lang +++ b/htdocs/langs/fr_FR/install.lang @@ -65,7 +65,7 @@ DatabaseSuperUserAccess=Serveur de base de données - Accès super utilisateur CheckToCreateDatabase=Cochez cette option si la base de données n'existe pas et doit être créée.
Dans ce cas, il faut renseigner le login/mot de passe du super-utilisateur au bas de cette page. CheckToCreateUser=Cochez cette option si l'utilisateur propriétaire n'existe pas et doit être créé.
Dans ce cas, il faut renseigner le nom et mot de passe du propriétaire à créer ainsi que le login/mot de passe du superutilisateur au bas de cette page. Si la case n'est pas cochée, le nom et mot de passe du propriétaire doivent exister. Experimental=(expérimental) -DatabaseRootLoginDescription=Login de l'utilisateur de la base ayant les droits de création de bases de données ou de comptes pour la base, inutile si la base et son compte d'accès existent déjà (comme lorsque vous êtes chez un hébergeur). +DatabaseRootLoginDescription=Login de l'utilisateur de la base ayant les droits de création de bases de données ou de comptes pour la base, requis si la base ou son propriétaire n'existe pas déjà et doivent être créés. KeepEmptyIfNoPassword=Laissez vide si l'administrateur n'a pas de mot de passe SaveConfigurationFile=Enregistrement du fichier de configuration ConfigurationSaving=Enregistrement du fichier de configuration diff --git a/htdocs/projet/ganttview.php b/htdocs/projet/ganttview.php index 164a9ef6ce2..e3907604fed 100644 --- a/htdocs/projet/ganttview.php +++ b/htdocs/projet/ganttview.php @@ -32,7 +32,9 @@ require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php'; $id=GETPOST('id','int'); $ref=GETPOST('ref','alpha'); -$mine = $_REQUEST['mode']=='mine' ? 1 : 0; + +$mode = GETPOST('mode', 'alpha'); +$mine = ($mode == 'mine' ? 1 : 0); //if (! $user->rights->projet->all->lire) $mine=1; // Special for projects $object = new Project($db); @@ -99,7 +101,7 @@ if ($id > 0 || ! empty($ref)) $head=project_prepare_head($object); dol_fiche_head($head, $tab, $langs->trans("Project"),0,($object->public?'projectpub':'project')); - $param=($_REQUEST["mode"]=='mine'?'&mode=mine':''); + $param=($mode=='mine'?'&mode=mine':''); print ''; @@ -110,8 +112,11 @@ if ($id > 0 || ! empty($ref)) print $langs->trans("Ref"); print ''; diff --git a/htdocs/societe/agenda.php b/htdocs/societe/agenda.php index a377f5c6e4c..8c9b07abdb9 100644 --- a/htdocs/societe/agenda.php +++ b/htdocs/societe/agenda.php @@ -37,19 +37,19 @@ $socid = GETPOST('socid','int'); if ($user->societe_id) $socid=$user->societe_id; $result = restrictedArea($user, 'societe', $socid, '&societe'); -// Initialize technical object to manage hooks of thirdparties. Note that conf->hooks_modules contains array array -include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php'; -$hookmanager=new HookManager($db); -$hookmanager->initHooks(array('agendathirdparty')); +// Initialize technical object to manage hooks of thirdparties. Note that conf->hooks_modules contains array array +include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php'; +$hookmanager=new HookManager($db); +$hookmanager->initHooks(array('agendathirdparty')); /* * Actions */ -$parameters=array('id'=>$socid); -$reshook=$hookmanager->executeHooks('doActions',$parameters,$object,$action); // Note that $action and $object may have been modified by some hooks -$error=$hookmanager->error; $errors=array_merge($errors, (array) $hookmanager->errors); +$parameters=array('id'=>$socid); +$reshook=$hookmanager->executeHooks('doActions',$parameters,$object,$action); // Note that $action and $object may have been modified by some hooks +$error=$hookmanager->error; $errors=array_merge($errors, (array) $hookmanager->errors); diff --git a/htdocs/societe/info.php b/htdocs/societe/info.php index 240fdaaf66d..75caf00c714 100644 --- a/htdocs/societe/info.php +++ b/htdocs/societe/info.php @@ -37,21 +37,21 @@ $socid = GETPOST('socid','int'); if ($user->societe_id) $socid=$user->societe_id; $result = restrictedArea($user, 'societe', $socid, '&societe'); -// Initialize technical object to manage hooks of thirdparties. Note that conf->hooks_modules contains array array -include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php'; -$hookmanager=new HookManager($db); -$hookmanager->initHooks(array('infothirdparty')); +// Initialize technical object to manage hooks of thirdparties. Note that conf->hooks_modules contains array array +include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php'; +$hookmanager=new HookManager($db); +$hookmanager->initHooks(array('infothirdparty')); -/* - * Actions - */ - -$parameters=array('id'=>$socid); -$reshook=$hookmanager->executeHooks('doActions',$parameters,$object,$action); // Note that $action and $object may have been modified by some hooks -$error=$hookmanager->error; $errors=array_merge($errors, (array) $hookmanager->errors); - +/* + * Actions + */ + +$parameters=array('id'=>$socid); +$reshook=$hookmanager->executeHooks('doActions',$parameters,$object,$action); // Note that $action and $object may have been modified by some hooks +$error=$hookmanager->error; $errors=array_merge($errors, (array) $hookmanager->errors); + /* diff --git a/htdocs/theme/amarok/style.css.php b/htdocs/theme/amarok/style.css.php index a3e85c0ce82..dc2aa4479b5 100755 --- a/htdocs/theme/amarok/style.css.php +++ b/htdocs/theme/amarok/style.css.php @@ -77,9 +77,15 @@ $img_button=dol_buildpath($path.'/theme/amarok/img/button_bg.png',1); *, html { margin:0; padding:0; - font-size:100%; +font-size:100%; } +/*.fiche ul { + margin:0.5em; + padding:0.5em; + padding-left: 2em; +}*/ + body { background-color:#f5f5f5; @@ -517,38 +523,195 @@ div.vmenu { /* Panes for ECM or Filemanager */ /* ============================================================================== */ + #containerlayout .layout-with-no-border { - border:0 !important; - border-width:0 !important; + border: 0 !important; + border-width: 0 !important; } #containerlayout .layout-padding { - padding:2px !important; + padding: 2px !important; } -#containerlayout .ui-layout-pane {/* all 'panes' */ - background:#ffffff; - border:1px solid #bbbbbb; - padding:0px; - overflow:auto; +/* + * PANES and CONTENT-DIVs + */ +#containerlayout .ui-layout-pane { /* all 'panes' */ + background: #FFF; + border: 1px solid #BBB; + /* DO NOT add scrolling (or padding) to 'panes' that have a content-div, + otherwise you may get double-scrollbars - on the pane AND on the content-div + */ + padding: 0px; + overflow: auto; } - +/* (scrolling) content-div inside pane allows for fixed header(s) and/or footer(s) */ #containerlayout .ui-layout-content { - padding:10px; - position:relative; /* contain floated or positioned elements */ - overflow:auto; /* add scrolling to content-div */ + padding: 10px; + position: relative; /* contain floated or positioned elements */ + overflow: auto; /* add scrolling to content-div */ } -#containerlayout .pane-in.ecm-in-layout-center.ui-layout-pane.ui-layout-pane-center { - border:0px solid #bbbbbb; - border-bottom:1px solid #bbbbbb; +/* + * RESIZER-BARS + */ +.ui-layout-resizer { /* all 'resizer-bars' */ + width: browser->phone)?'8':'24'); ?>px !important; +} +.ui-layout-resizer-hover { /* affects both open and closed states */ +} +/* NOTE: It looks best when 'hover' and 'dragging' are set to the same color, + otherwise color shifts while dragging when bar can't keep up with mouse */ +/*.ui-layout-resizer-open-hover ,*/ /* hover-color to 'resize' */ +.ui-layout-resizer-dragging { /* resizer beging 'dragging' */ + background: #DDD; + width: browser->phone)?'8':'24'); ?>px; +} +.ui-layout-resizer-dragging { /* CLONED resizer being dragged */ + border-left: 1px solid #BBB; + border-right: 1px solid #BBB; +} +/* NOTE: Add a 'dragging-limit' color to provide visual feedback when resizer hits min/max size limits */ +.ui-layout-resizer-dragging-limit { /* CLONED resizer at min or max size-limit */ + background: #E1A4A4; /* red */ +} +.ui-layout-resizer-closed { + background-color: #DDDDDD; +} +.ui-layout-resizer-closed:hover { + background-color: #EEDDDD; +} +.ui-layout-resizer-sliding { /* resizer when pane is 'slid open' */ + opacity: .10; /* show only a slight shadow */ + filter: alpha(opacity=10); +} +.ui-layout-resizer-sliding-hover { /* sliding resizer - hover */ + opacity: 1.00; /* on-hover, show the resizer-bar normally */ + filter: alpha(opacity=100); +} +/* sliding resizer - add 'outside-border' to resizer on-hover */ +/* this sample illustrates how to target specific panes and states */ +/*.ui-layout-resizer-north-sliding-hover { border-bottom-width: 1px; } +.ui-layout-resizer-south-sliding-hover { border-top-width: 1px; } +.ui-layout-resizer-west-sliding-hover { border-right-width: 1px; } +.ui-layout-resizer-east-sliding-hover { border-left-width: 1px; } +*/ + +/* + * TOGGLER-BUTTONS + */ +.ui-layout-toggler { + browser->phone)) { ?> + border-top: 1px solid #AAA; /* match pane-border */ + border-right: 1px solid #AAA; /* match pane-border */ + border-bottom: 1px solid #AAA; /* match pane-border */ + background-color: #DDD; + top: 5px !important; + + diplay: none; + +} +.ui-layout-toggler-open { + height: 54px !important; + width: browser->phone)?'7':'22'); ?>px !important; + -moz-border-radius:0px 10px 10px 0px; + -webkit-border-radius:0px 10px 10px 0px; + border-radius:0px 10px 10px 0px; +} +.ui-layout-toggler-closed { + height: browser->phone)?'54':'2'); ?>px !important; + width: browser->phone)?'7':'22'); ?>px !important; + -moz-border-radius:0px 10px 10px 0px; + -webkit-border-radius:0px 10px 10px 0px; + border-radius:0px 10px 10px 0px; +} +.ui-layout-toggler .content { /* style the text we put INSIDE the togglers */ + color: #666; + font-size: 12px; + font-weight: bold; + width: 100%; + padding-bottom: 0.35ex; /* to 'vertically center' text inside text-span */ } -#containerlayout .pane-in.ecm-in-layout-south.layout-padding.ui-layout-pane.ui-layout-pane-south { - border:0px solid #bbbbbb; - border-top:1px solid #bbbbbb; +/* hide the toggler-button when the pane is 'slid open' */ +.ui-layout-resizer-sliding ui-layout-toggler { + display: none; } +.ui-layout-north { + height: browser->phone)?'54':'21'); ?>px !important; +} + + +/* ECM */ + +#containerlayout .ecm-layout-pane { /* all 'panes' */ + background: #FFF; + border: 1px solid #BBB; + /* DO NOT add scrolling (or padding) to 'panes' that have a content-div, + otherwise you may get double-scrollbars - on the pane AND on the content-div + */ + padding: 0px; + overflow: auto; +} +/* (scrolling) content-div inside pane allows for fixed header(s) and/or footer(s) */ +#containerlayout .ecm-layout-content { + padding: 10px; + position: relative; /* contain floated or positioned elements */ + overflow: auto; /* add scrolling to content-div */ +} + +.ecm-layout-toggler { + border-top: 1px solid #AAA; /* match pane-border */ + border-right: 1px solid #AAA; /* match pane-border */ + border-bottom: 1px solid #AAA; /* match pane-border */ + background-color: #CCC; + } +.ecm-layout-toggler-open { + height: 48px !important; + width: 6px !important; + -moz-border-radius:0px 10px 10px 0px; + -webkit-border-radius:0px 10px 10px 0px; + border-radius:0px 10px 10px 0px; +} +.ecm-layout-toggler-closed { + height: 48px !important; + width: 6px !important; +} + +.ecm-layout-toggler .content { /* style the text we put INSIDE the togglers */ + color: #666; + font-size: 12px; + font-weight: bold; + width: 100%; + padding-bottom: 0.35ex; /* to 'vertically center' text inside text-span */ +} +#ecm-layout-west-resizer { + width: 6px !important; +} + +.ecm-layout-resizer { /* all 'resizer-bars' */ + border: 1px solid #BBB; + border-width: 0; + } +.ecm-layout-resizer-closed { +} + +.ecm-in-layout-center { + border-left: 1px !important; + border-right: 0px !important; + border-top: 0px !important; +} + +.ecm-in-layout-south { + border-left: 0px !important; + border-right: 0px !important; + border-bottom: 0px !important; + padding: 4px 0 4px 4px !important; +} + + + /* ============================================================================== */ /* Onglets */ /* ============================================================================== */ @@ -1003,6 +1166,9 @@ div.error { * Other */ +.product_line_stock_ok { color: #002200; } +.product_line_stock_too_low { color: #664400; } + .fieldrequired { font-weight:bold; color:#333333; @@ -1024,6 +1190,40 @@ div.titre { padding-bottom:2px; } +#dolpaymenttable { width: 600px; font-size: 13px; } +#tablepublicpayment { border: 1px solid #CCCCCC !important; width: 100%; } +#tablepublicpayment .CTableRow1 { background-color: #F0F0F0 !important; } +#tablepublicpayment tr.liste_total { border-bottom: 1px solid #CCCCCC !important; } +#tablepublicpayment tr.liste_total td { border-top: none; } + +#divsubscribe { width: 700px; } +#tablesubscribe { width: 100%; } + +div.table-border { + display:table; + width: 100%; + border-collapse: collapse; + border: 1px solid #DDD; +} +div.table-border-row { + display:table-row; +} +div.table-key-border-col { + display:table-cell; + width: 25%; + vertical-align:top; + padding: 1px 2px 1px 1px; + border: 1px solid #DDD; + border-collapse: collapse; +} +div.table-val-border-col { + display:table-cell; + width:auto; + padding: 1px 2px 1px 1px; + border: 1px solid #DDD; + border-collapse: collapse; +} + /* ============================================================================== */ /* Formulaire confirmation (When Ajax JQuery is used) */ @@ -1636,3 +1836,133 @@ span.cke_skin_kama {padding:0px !important;} /* ============================================================================== */ .template-upload {height:72px !important;} + + +/* ============================================================================== */ +/* JSGantt */ +/* ============================================================================== */ + +div.scroll2 { + width: px !important; +} + + +/* ============================================================================== */ +/* jFileTree */ +/* ============================================================================== */ + +.ecmfiletree { + width: 99%; + height: 99%; + background: #FFF; + padding-left: 2px; + font-weight: normal; +} + +.fileview { + width: 99%; + height: 99%; + background: #FFF; + padding-left: 2px; + padding-top: 4px; + font-weight: normal; +} + +div.filedirelem { + position: relative; + display: block; + text-decoration: none; +} + +ul.filedirelem { + padding: 2px; + margin: 0 5px 5px 5px; +} +ul.filedirelem li { + list-style: none; + padding: 2px; + margin: 0 10px 20px 10px; + width: 160px; + height: 120px; + text-align: center; + display: block; + float: ; + border: solid 1px #DDDDDD; +} + +ui-layout-north { + +} + +ul.ecmjqft { + font-size: 11px; + line-height: 16px; + padding: 0px; + margin: 0px; + font-weight: normal; +} + +ul.ecmjqft li { + list-style: none; + padding: 0px; + padding-left: 20px; + margin: 0px; + white-space: nowrap; + display: block; +} + +ul.ecmjqft a { + line-height: 16px; + vertical-align: middle; + color: #333; + padding: 0px 0px; + font-weight:normal; + display: inline-block !important; +/* float: left;*/ +} +ul.ecmjqft a:active { + font-weight: bold !important; +} +ul.ecmjqft a:hover { + text-decoration: underline; +} +div.ecmjqft { + vertical-align: middle; + display: inline-block !important; + text-align: right; + position:absolute; + right:4px; +} + +/* Core Styles */ +.ecmjqft LI.directory { font-weight:normal; background: url() left top no-repeat; } +.ecmjqft LI.expanded { font-weight:normal; background: url() left top no-repeat; } +.ecmjqft LI.wait { font-weight:normal; background: url() left top no-repeat; } + + + +/* ============================================================================== */ +/* jNotify */ +/* ============================================================================== */ + +.jnotify-container { + position: fixed !important; +global->MAIN_JQUERY_JNOTIFY_BOTTOM)) { ?> + top: auto !important; + bottom: 4px !important; + + text-align: center; + min-width: 500px; + width: auto; + padding-left: 10px !important; + padding-right: 10px !important; +} + +/* use or not ? */ +div.jnotify-background { + opacity : 0.95 !important; + -moz-box-shadow: 4px 4px 4px #AAA !important; + -webkit-box-shadow: 4px 4px 4px #AAA !important; + box-shadow: 4px 4px 4px #AAA !important; +} + diff --git a/htdocs/user/fiche.php b/htdocs/user/fiche.php index 30a81270280..787595e49e8 100644 --- a/htdocs/user/fiche.php +++ b/htdocs/user/fiche.php @@ -307,9 +307,27 @@ if ($action == 'update' && ! $_POST["cancel"]) if (! $error) { - $db->begin(); $object->fetch($id); + // Test if new login + if (GETPOST("login") && GETPOST("login") != $object->login) + { + dol_syslog("New login ".$object->login." is requested. We test it does not exists."); + $tmpuser=new User($db); + $result=$tmpuser->fetch(0, GETPOST("login")); + if ($result > 0) + { + $message='
'.$langs->trans("ErrorLoginAlreadyExists").'
'; + $action="edit"; // Go back to create page + $error++; + } + } + } + + if (! $error) + { + $db->begin(); + $object->oldcopy=dol_clone($object); $object->lastname = GETPOST("nom"); @@ -454,6 +472,12 @@ if ($action == 'update' && ! $_POST["cancel"]) { $message.='
'.$langs->trans("UserModified").'
'; $db->commit(); + + $login=$_SESSION["dol_login"]; + if ($login && $login == $object->oldcopy->login && $object->oldcopy->login != $object->login) // Current user has changed its login + { + $_SESSION["dol_login"]=$object->login; // Set new login to avoid disconnect at next page + } } else { @@ -769,7 +793,7 @@ if (($action == 'create') || ($action == 'adduserldap')) else { // We do not use a field password but a field text to show new password to use. - print ''; + print ''; } } print ''; @@ -1648,7 +1672,7 @@ else } else if ($caneditpassword) { - $text=''; + $text=''; if ($dolibarr_main_authentication && $dolibarr_main_authentication == 'http') { $text=$form->textwithpicto($text,$langs->trans("DolibarrInHttpAuthenticationSoPasswordUseless",$dolibarr_main_authentication),1,'warning'); diff --git a/scripts/company/export-contacts-xls-example.php b/scripts/company/export-contacts-xls-example.php index bdef2e43d40..83e7c9e165c 100644 --- a/scripts/company/export-contacts-xls-example.php +++ b/scripts/company/export-contacts-xls-example.php @@ -30,7 +30,7 @@ $path=dirname(__FILE__).'/'; // Test if batch mode if (substr($sapi_type, 0, 3) == 'cgi') { - echo "Error: You ar usingr PH for CGI. To execute ".$script_file." from command line, you must use PHP for CLI mode.\n"; + echo "Error: You are using PHP for CGI. To execute ".$script_file." from command line, you must use PHP for CLI mode.\n"; exit; } diff --git a/scripts/company/sync_contacts_dolibarr2ldap.php b/scripts/company/sync_contacts_dolibarr2ldap.php index e80443430b1..f0adfe682ef 100644 --- a/scripts/company/sync_contacts_dolibarr2ldap.php +++ b/scripts/company/sync_contacts_dolibarr2ldap.php @@ -30,7 +30,7 @@ $path=dirname(__FILE__).'/'; // Test if batch mode if (substr($sapi_type, 0, 3) == 'cgi') { - echo "Error: You ar usingr PH for CGI. To execute ".$script_file." from command line, you must use PHP for CLI mode.\n"; + echo "Error: You are using PHP for CGI. To execute ".$script_file." from command line, you must use PHP for CLI mode.\n"; exit; } diff --git a/scripts/invoices/rebuild_merge_pdf.php b/scripts/invoices/rebuild_merge_pdf.php index c44ed149c03..5b2b4aedb2f 100644 --- a/scripts/invoices/rebuild_merge_pdf.php +++ b/scripts/invoices/rebuild_merge_pdf.php @@ -29,7 +29,7 @@ $path=dirname(__FILE__).'/'; // Test if batch mode if (substr($sapi_type, 0, 3) == 'cgi') { - echo "Error: You ar usingr PH for CGI. To execute ".$script_file." from command line, you must use PHP for CLI mode.\n"; + echo "Error: You are using PHP for CGI. To execute ".$script_file." from command line, you must use PHP for CLI mode.\n"; exit; } diff --git a/scripts/members/sync_members_dolibarr2ldap.php b/scripts/members/sync_members_dolibarr2ldap.php index af564b6f67b..43d5964707c 100755 --- a/scripts/members/sync_members_dolibarr2ldap.php +++ b/scripts/members/sync_members_dolibarr2ldap.php @@ -30,7 +30,7 @@ $path=dirname(__FILE__).'/'; // Test if batch mode if (substr($sapi_type, 0, 3) == 'cgi') { - echo "Error: You ar usingr PH for CGI. To execute ".$script_file." from command line, you must use PHP for CLI mode.\n"; + echo "Error: You are using PHP for CGI. To execute ".$script_file." from command line, you must use PHP for CLI mode.\n"; exit; } diff --git a/scripts/members/sync_members_ldap2dolibarr.php b/scripts/members/sync_members_ldap2dolibarr.php index 7e7d55fbf90..618a090b4c1 100755 --- a/scripts/members/sync_members_ldap2dolibarr.php +++ b/scripts/members/sync_members_ldap2dolibarr.php @@ -30,7 +30,7 @@ $path=dirname(__FILE__).'/'; // Test if batch mode if (substr($sapi_type, 0, 3) == 'cgi') { - echo "Error: You ar usingr PH for CGI. To execute ".$script_file." from command line, you must use PHP for CLI mode.\n"; + echo "Error: You are using PHP for CGI. To execute ".$script_file." from command line, you must use PHP for CLI mode.\n"; exit; } diff --git a/scripts/user/sync_groups_dolibarr2ldap.php b/scripts/user/sync_groups_dolibarr2ldap.php index 32086f51752..71af532b098 100755 --- a/scripts/user/sync_groups_dolibarr2ldap.php +++ b/scripts/user/sync_groups_dolibarr2ldap.php @@ -30,7 +30,7 @@ $path=dirname(__FILE__).'/'; // Test if batch mode if (substr($sapi_type, 0, 3) == 'cgi') { - echo "Error: You ar usingr PH for CGI. To execute ".$script_file." from command line, you must use PHP for CLI mode.\n"; + echo "Error: You are using PHP for CGI. To execute ".$script_file." from command line, you must use PHP for CLI mode.\n"; exit; } diff --git a/scripts/user/sync_users_dolibarr2ldap.php b/scripts/user/sync_users_dolibarr2ldap.php index a4931d91d32..3d36549f494 100755 --- a/scripts/user/sync_users_dolibarr2ldap.php +++ b/scripts/user/sync_users_dolibarr2ldap.php @@ -30,7 +30,7 @@ $path=dirname(__FILE__).'/'; // Test if batch mode if (substr($sapi_type, 0, 3) == 'cgi') { - echo "Error: You ar usingr PH for CGI. To execute ".$script_file." from command line, you must use PHP for CLI mode.\n"; + echo "Error: You are using PHP for CGI. To execute ".$script_file." from command line, you must use PHP for CLI mode.\n"; exit; } diff --git a/scripts/user/sync_users_ldap2dolibarr.php b/scripts/user/sync_users_ldap2dolibarr.php index e94c2cd618a..f4c908fb150 100755 --- a/scripts/user/sync_users_ldap2dolibarr.php +++ b/scripts/user/sync_users_ldap2dolibarr.php @@ -30,7 +30,7 @@ $path=dirname(__FILE__).'/'; // Test if batch mode if (substr($sapi_type, 0, 3) == 'cgi') { - echo "Error: You ar usingr PH for CGI. To execute ".$script_file." from command line, you must use PHP for CLI mode.\n"; + echo "Error: You are using PHP for CGI. To execute ".$script_file." from command line, you must use PHP for CLI mode.\n"; exit; }
'; // Define a complementary filter for search of next/prev ref. - $objectsListId = $object->getProjectsAuthorizedForUser($user,$mine,1); - $object->next_prev_filter=" rowid in (".$objectsListId.")"; + if (! $user->rights->projet->all->lire) + { + $projectsListId = $object->getProjectsAuthorizedForUser($user,$mine,0); + $object->next_prev_filter=" rowid in (".(count($projectsListId)?join(',',array_keys($projectsListId)):'0').")"; + } print $form->showrefnav($object, 'ref', $linkback, 1, 'ref', 'ref', '', $param); print '