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/build/exe/doliwamp/doliwamp.iss b/build/exe/doliwamp/doliwamp.iss index 1dd37f24700..4aebbdb0814 100644 --- a/build/exe/doliwamp/doliwamp.iss +++ b/build/exe/doliwamp/doliwamp.iss @@ -22,8 +22,7 @@ AppVerName=DoliWamp-3.3.0-beta OutputBaseFilename=DoliWamp-3.3.0-beta ; Define full path from wich all relative path are defined ; You must modify this to put here your dolibarr root directory -;SourceDir=C:\Documents and Settings\ldestailleur\git\dolibarr_old -;SourceDir=Z:\home\ldestailleur\git\dolibarr_veryold +;SourceDir=Z:\home\ldestailleur\git\dolibarrxxx SourceDir=..\..\.. ; ----- End of change ;OutputManifestFile=build\doliwampbuild.log @@ -33,7 +32,7 @@ AppPublisherURL=http://www.nltechno.com AppSupportURL=http://www.dolibarr.org AppUpdatesURL=http://www.dolibarr.org AppComments=DoliWamp includes Dolibarr, Apache, PHP and Mysql softwares. -AppCopyright=Copyright (C) 2008-2012 Laurent Destailleur, NLTechno +AppCopyright=Copyright (C) 2008-2013 Laurent Destailleur, NLTechno DefaultDirName=c:\dolibarr DefaultGroupName=Dolibarr ;LicenseFile=COPYING @@ -88,12 +87,12 @@ Name: "{app}\bin\apache\apache2.2.11\logs" ; Stop/start Source: "build\exe\doliwamp\stopdoliwamp.bat"; DestDir: "{app}\"; Flags: ignoreversion; AfterInstall: close() Source: "build\exe\doliwamp\startdoliwamp.bat"; DestDir: "{app}\"; Flags: ignoreversion; +Source: "build\exe\doliwamp\install_services.bat.install"; DestDir: "{app}\"; Flags: ignoreversion; +Source: "build\exe\doliwamp\uninstall_services.bat.install"; DestDir: "{app}\"; Flags: ignoreversion; Source: "build\exe\doliwamp\removefiles.bat"; DestDir: "{app}\"; Flags: ignoreversion; Source: "build\exe\doliwamp\rundoliwamp.bat.install"; DestDir: "{app}\"; Flags: ignoreversion; Source: "build\exe\doliwamp\rundolihelp.bat.install"; DestDir: "{app}\"; Flags: ignoreversion; Source: "build\exe\doliwamp\rundoliadmin.bat.install"; DestDir: "{app}\"; Flags: ignoreversion; -Source: "build\exe\doliwamp\install_services.bat.install"; DestDir: "{app}\"; Flags: ignoreversion; -Source: "build\exe\doliwamp\uninstall_services.bat.install"; DestDir: "{app}\"; Flags: ignoreversion; Source: "build\exe\doliwamp\mysqlinitpassword.bat.install"; DestDir: "{app}\"; Flags: ignoreversion; Source: "build\exe\doliwamp\mysqltestinstall.bat.install"; DestDir: "{app}\"; Flags: ignoreversion; Source: "build\exe\doliwamp\startdoliwamp_manual_donotuse.bat.install"; DestDir: "{app}\"; Flags: ignoreversion; diff --git a/dev/finddosfiles.sh b/dev/finddosfiles.sh new file mode 100755 index 00000000000..f77859ba1ea --- /dev/null +++ b/dev/finddosfiles.sh @@ -0,0 +1,15 @@ +#!/bin/sh +#------------------------------------------------------ +# Script to find files that are not Unix encoded +# +# Laurent Destailleur - eldy@users.sourceforge.net +#------------------------------------------------------ +# Usage: finddosfiles.sh +#------------------------------------------------------ + +# To detec +find . -type f -iname "*.php" -exec file "{}" + | grep CRLF + +# To convert +#find . -type f -iname "*.php" -exec dos2unix "{}" +; + diff --git a/dev/initdata/savedemo.sh b/dev/initdata/savedemo.sh index 2dd19e55fd4..dc1141f504b 100755 --- a/dev/initdata/savedemo.sh +++ b/dev/initdata/savedemo.sh @@ -188,6 +188,7 @@ export list=" --ignore-table=$base.llx_cabinetmed_examenprescrit --ignore-table=$base.llx_cabinetmed_motifcons --ignore-table=$base.llx_cabinetmed_patient + --ignore-table=$base.llx_cabinetmed_societe --ignore-table=$base.llx_publi_c_contact_list --ignore-table=$base.llx_publi_c_dnd_list --ignore-table=$base.llx_publi_c_method_list 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 065a39db3f3..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"); @@ -950,7 +950,7 @@ class Adherent extends CommonObject $this->db->begin(); - // Update link to third party + // Remove link to third party onto any other members if ($thirdpartyid > 0) { $sql = "UPDATE ".MAIN_DB_PREFIX."adherent SET fk_soc = null"; @@ -960,7 +960,7 @@ class Adherent extends CommonObject $resql = $this->db->query($sql); } - // Update link to third party + // Add link to third party for current member $sql = "UPDATE ".MAIN_DB_PREFIX."adherent SET fk_soc = ".($thirdpartyid>0 ? $thirdpartyid : 'null'); $sql.= " WHERE rowid = ".$this->id; diff --git a/htdocs/categories/categorie.php b/htdocs/categories/categorie.php index 011e500eed4..2557da5a030 100644 --- a/htdocs/categories/categorie.php +++ b/htdocs/categories/categorie.php @@ -85,84 +85,96 @@ 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); +$hookmanager->initHooks(array('categorycard')); + /* * Actions */ -//Suppression d'un objet d'une categorie -if ($removecat > 0) +$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)) { - if ($type==0 && ($user->rights->produit->creer || $user->rights->service->creer)) + //Suppression d'un objet d'une categorie + if ($removecat > 0) { - require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; - $object = new Product($db); - $result = $object->fetch($id, $ref); - $elementtype = 'product'; - } - if ($type==1 && $user->rights->societe->creer) - { - $object = new Societe($db); - $result = $object->fetch($objectid); - } - if ($type==2 && $user->rights->societe->creer) - { - $object = new Societe($db); - $result = $object->fetch($objectid); - } - if ($type == 3 && $user->rights->adherent->creer) - { - require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php'; - $object = new Adherent($db); - $result = $object->fetch($objectid); - } - $cat = new Categorie($db); - $result=$cat->fetch($removecat); + if ($type==0 && ($user->rights->produit->creer || $user->rights->service->creer)) + { + require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; + $object = new Product($db); + $result = $object->fetch($id, $ref); + $elementtype = 'product'; + } + if ($type==1 && $user->rights->societe->creer) + { + $object = new Societe($db); + $result = $object->fetch($objectid); + } + if ($type==2 && $user->rights->societe->creer) + { + $object = new Societe($db); + $result = $object->fetch($objectid); + } + if ($type == 3 && $user->rights->adherent->creer) + { + require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php'; + $object = new Adherent($db); + $result = $object->fetch($objectid); + } + $cat = new Categorie($db); + $result=$cat->fetch($removecat); - $result=$cat->del_type($object,$elementtype); -} + $result=$cat->del_type($object,$elementtype); + } -// Add object into a category -if ($parent > 0) -{ - if ($type==0 && ($user->rights->produit->creer || $user->rights->service->creer)) + // Add object into a category + if ($parent > 0) { - require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; - $object = new Product($db); - $result = $object->fetch($id, $ref); - $elementtype = 'product'; - } - if ($type==1 && $user->rights->societe->creer) - { - $object = new Societe($db); - $result = $object->fetch($objectid); - $elementtype = 'fournisseur'; - } - if ($type==2 && $user->rights->societe->creer) - { - $object = new Societe($db); - $result = $object->fetch($objectid); - $elementtype = 'societe'; - } - if ($type==3 && $user->rights->adherent->creer) - { - require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php'; - $object = new Adherent($db); - $result = $object->fetch($objectid); - $elementtype = 'member'; - } - $cat = new Categorie($db); - $result=$cat->fetch($parent); + if ($type==0 && ($user->rights->produit->creer || $user->rights->service->creer)) + { + require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; + $object = new Product($db); + $result = $object->fetch($id, $ref); + $elementtype = 'product'; + } + if ($type==1 && $user->rights->societe->creer) + { + $object = new Societe($db); + $result = $object->fetch($objectid); + $elementtype = 'fournisseur'; + } + if ($type==2 && $user->rights->societe->creer) + { + $object = new Societe($db); + $result = $object->fetch($objectid); + $elementtype = 'societe'; + } + if ($type==3 && $user->rights->adherent->creer) + { + require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php'; + $object = new Adherent($db); + $result = $object->fetch($objectid); + $elementtype = 'member'; + } + $cat = new Categorie($db); + $result=$cat->fetch($parent); - $result=$cat->add_type($object,$elementtype); - if ($result >= 0) - { - $mesg='
'.$langs->trans("WasAddedSuccessfully",$cat->label).'
'; - } - else - { - if ($cat->error == 'DB_ERROR_RECORD_ALREADY_EXISTS') $mesg='
'.$langs->trans("ObjectAlreadyLinkedToCategory").'
'; - else $mesg=$langs->trans("Error").' '.$cat->error; + $result=$cat->add_type($object,$elementtype); + if ($result >= 0) + { + $mesg='
'.$langs->trans("WasAddedSuccessfully",$cat->label).'
'; + } + else + { + if ($cat->error == 'DB_ERROR_RECORD_ALREADY_EXISTS') $mesg='
'.$langs->trans("ObjectAlreadyLinkedToCategory").'
'; + else $mesg=$langs->trans("Error").' '.$cat->error; + } } } 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/facture.php b/htdocs/compta/facture.php index 75a67be6bff..2c4bbf372a0 100644 --- a/htdocs/compta/facture.php +++ b/htdocs/compta/facture.php @@ -5,7 +5,7 @@ * Copyright (C) 2005 Marc Barilley / Ocebo * Copyright (C) 2005-2012 Regis Houssin * Copyright (C) 2006 Andre Cianfarani - * Copyright (C) 2010-2012 Juanjo Menent + * Copyright (C) 2010-2013 Juanjo Menent * Copyright (C) 2012 Christophe Battarel * * This program is free software; you can redistribute it and/or modify @@ -593,7 +593,8 @@ else if ($action == 'confirm_converttoreduc' && $confirm == 'yes' && $user->righ */ else if ($action == 'add' && $user->rights->facture->creer) { - $object->socid=GETPOST('socid','int'); + if ($socid>0) + $object->socid=GETPOST('socid','int'); $db->begin(); @@ -732,6 +733,12 @@ else if ($action == 'add' && $user->rights->facture->creer) // Standard or deposit or proforma invoice if (($_POST['type'] == 0 || $_POST['type'] == 3 || $_POST['type'] == 4) && $_POST['fac_rec'] <= 0) { + if (GETPOST('socid','int')<1) + { + $error++; + setEventMessage($langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("Customer")),'errors'); + } + $datefacture = dol_mktime(12, 0, 0, $_POST['remonth'], $_POST['reday'], $_POST['reyear']); if (empty($datefacture)) { @@ -1727,7 +1734,7 @@ if ($action == 'create') print_fiche_titre($langs->trans('NewBill')); $soc = new Societe($db); - if ($socid) $res=$soc->fetch($socid); + if ($socid>0) $res=$soc->fetch($socid); if (! empty($origin) && ! empty($originid)) { @@ -1804,7 +1811,7 @@ if ($action == 'create') print ''.$langs->trans('Ref').''.$langs->trans('Draft').''; // Factures predefinies - if (empty($origin) && empty($originid)) + if (empty($origin) && empty($originid) && $socid>0) { $sql = 'SELECT r.rowid, r.titre, r.total_ttc'; $sql.= ' FROM '.MAIN_DB_PREFIX.'facture_rec as r'; @@ -1834,16 +1841,27 @@ if ($action == 'create') $db->free($resql); } else - { + { dol_print_error($db); } } // Tiers - print ''.$langs->trans('Customer').''; - print $soc->getNomUrl(1); - print ''; - print ''; + print ''; + print ''.$langs->trans('Customer').''; + if($socid>0) + { + print ''; + print $soc->getNomUrl(1); + print ''; + print ''; + } + else + { + print ''; + print $form->select_company('','socid','s.client = 1',1); + print ''; + } print ''."\n"; // Type de facture @@ -1916,72 +1934,77 @@ if ($action == 'create') print $desc; print ''."\n"; } - - // Replacement - print ''; - print ''; - print ''; - $text=$langs->trans("InvoiceReplacementAsk").' '; - $text.=''; - $desc=$form->textwithpicto($text,$langs->transnoentities("InvoiceReplacementDesc"),1); - print $desc; - print ''."\n"; - - // Credit note - print ''; - print ''; - print ''; - $text=$langs->transnoentities("InvoiceAvoirAsk").' '; - // $text.=''; - $text.=''; - $desc=$form->textwithpicto($text,$langs->transnoentities("InvoiceAvoirDesc"),1); - print $desc; - print ''."\n"; - - print ''; - print ''; - - // Discounts for third party - print ''.$langs->trans('Discounts').''; - if ($soc->remise_client) print $langs->trans("CompanyHasRelativeDiscount",''.$soc->remise_client.''); - else print $langs->trans("CompanyHasNoRelativeDiscount"); - print ' ('.$langs->trans("EditRelativeDiscount").')'; - print '. '; - print '
'; - if ($absolute_discount) print $langs->trans("CompanyHasAbsoluteDiscount",''.price($absolute_discount).'',$langs->trans("Currency".$conf->currency)); - else print $langs->trans("CompanyHasNoAbsoluteDiscount"); - print ' ('.$langs->trans("EditGlobalDiscounts").')'; - print '.'; - print ''; - + + if ($socid>0) + { + // Replacement + print ''; + print ''; + print ''; + $text=$langs->trans("InvoiceReplacementAsk").' '; + $text.=''; + $desc=$form->textwithpicto($text,$langs->transnoentities("InvoiceReplacementDesc"),1); + print $desc; + print ''."\n"; + + // Credit note + print ''; + print ''; + print ''; + $text=$langs->transnoentities("InvoiceAvoirAsk").' '; + // $text.=''; + $text.=''; + $desc=$form->textwithpicto($text,$langs->transnoentities("InvoiceAvoirDesc"),1); + print $desc; + print ''."\n"; + } + print ''; + print ''; + + if($socid>0) + { + // Discounts for third party + print ''.$langs->trans('Discounts').''; + if ($soc->remise_client) print $langs->trans("CompanyHasRelativeDiscount",''.$soc->remise_client.''); + else print $langs->trans("CompanyHasNoRelativeDiscount"); + print ' ('.$langs->trans("EditRelativeDiscount").')'; + print '. '; + print '
'; + if ($absolute_discount) print $langs->trans("CompanyHasAbsoluteDiscount",''.price($absolute_discount).'',$langs->trans("Currency".$conf->currency)); + else print $langs->trans("CompanyHasNoAbsoluteDiscount"); + print ' ('.$langs->trans("EditGlobalDiscounts").')'; + print '.'; + print ''; + } + // Date invoice print ''.$langs->trans('Date').''; $form->select_date($dateinvoice,'','','','',"add",1,1); @@ -1998,7 +2021,7 @@ if ($action == 'create') print ''; // Project - if (! empty($conf->projet->enabled)) + if (! empty($conf->projet->enabled) && $socid>0) { $langs->load('projects'); print ''.$langs->trans('Project').''; 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/extrafields.class.php b/htdocs/core/class/extrafields.class.php index 87e3eb5dce7..b387537165b 100755 --- a/htdocs/core/class/extrafields.class.php +++ b/htdocs/core/class/extrafields.class.php @@ -52,7 +52,8 @@ class ExtraFields 'int'=>'Int', 'double'=>'Float', 'date'=>'Date', - 'datetime'=>'DateAndTime' + 'datetime'=>'DateAndTime', + 'boolean'=>'Boolean' ); /** @@ -135,7 +136,14 @@ class ExtraFields if (isset($attrname) && $attrname != '' && preg_match("/^\w[a-zA-Z0-9-_]*$/",$attrname)) { - $field_desc = array('type'=>$type, 'value'=>$length, 'null'=>($required?'NOT NULL':'NULL')); + if ($type=='boolean') { + $typedb='int'; + $lengthdb='1'; + } else { + $typedb=$type; + $lengthdb=$length; + } + $field_desc = array('type'=>$typedb, 'value'=>$lengthdb, 'null'=>($required?'NOT NULL':'NULL')); $result=$this->db->DDLAddField(MAIN_DB_PREFIX.$table, $attrname, $field_desc); if ($result > 0) { @@ -304,7 +312,14 @@ class ExtraFields if (isset($attrname) && $attrname != '' && preg_match("/^\w[a-zA-Z0-9-_]*$/",$attrname)) { - $field_desc = array('type'=>$type, 'value'=>$length, 'null'=>($required?'NOT NULL':'NULL')); + if ($type=='boolean') { + $typedb='int'; + $lengthdb='1'; + } else { + $typedb=$type; + $lengthdb=$length; + } + $field_desc = array('type'=>$typedb, 'value'=>$lengthdb, 'null'=>($required?'NOT NULL':'NULL')); $result=$this->db->DDLUpdateField(MAIN_DB_PREFIX.$table, $attrname, $field_desc); if ($result > 0) { @@ -487,7 +502,7 @@ class ExtraFields function showInputField($key,$value,$moreparam='') { global $conf; - + $label=$this->attribute_label[$key]; $type =$this->attribute_type[$key]; $size =$this->attribute_size[$key]; @@ -534,6 +549,16 @@ class ExtraFields $doleditor=new DolEditor('options_'.$key,$value,'',200,'dolibarr_notes','In',false,false,! empty($conf->fckeditor->enabled) && $conf->global->FCKEDITOR_ENABLE_SOCIETE,5,100); $out=$doleditor->Create(1); } + else if ($type == 'boolean') + { + $checked=''; + if (!empty($value)) { + $checked=' checked="checked" value="1" '; + } else { + $checked=' value="1" '; + } + $out=''; + } // Add comments if ($type == 'date') $out.=' (YYYY-MM-DD)'; elseif ($type == 'datetime') $out.=' (YYYY-MM-DD HH:MM:SS)'; @@ -550,6 +575,7 @@ class ExtraFields */ function showOutputField($key,$value,$moreparam='') { + $label=$this->attribute_label[$key]; $type=$this->attribute_type[$key]; $size=$this->attribute_size[$key]; @@ -568,6 +594,14 @@ class ExtraFields { $showsize=10; } + elseif ($type == 'boolean') + { + $checked=''; + if (!empty($value)) { + $checked=' checked="checked" '; + } + $value=''; + } else { $showsize=round($size); diff --git a/htdocs/core/class/hookmanager.class.php b/htdocs/core/class/hookmanager.class.php index 91db5b31419..d18f1fafa0b 100755 --- a/htdocs/core/class/hookmanager.class.php +++ b/htdocs/core/class/hookmanager.class.php @@ -115,7 +115,7 @@ class HookManager * @param Object &$object Object to use hooks on * @param string &$action Action code on calling page ('create', 'edit', 'view', 'add', 'update', 'delete'...) * @return mixed For doActions,formObjectOptions: Return 0 if we want to keep standard actions, >0 if if want to stop standard actions, <0 means KO. - * For printSearchForm,printLeftBlock,printTopRightMenu,formAddObjectLine,...: Return HTML string. TODO Must always return an int and things to print into ->resprints. + * For printSearchForm,printLeftBlock,printTopRightMenu,formAddObjectLine,...: Return HTML string. TODO Must always return an int and things to print into ->resprints. * Can also return some values into an array ->results. * $this->error or this->errors are also defined by class called by this function if error. */ @@ -136,6 +136,8 @@ class HookManager { foreach($modules as $module => $actionclassinstance) { + //print 'class='.get_class($actionclassinstance).' method='.$method.' action='.$action; + // jump to next class if method does not exists if (! method_exists($actionclassinstance,$method)) continue; // test to avoid to run twice a hook, when a module implements several active contexts @@ -178,7 +180,7 @@ class HookManager } } - if ($method != 'doActions' && $method != 'formObjectOptions') return $this->resPrint; // TODO remove this. When there is something to print, ->resPrint is filled. + if ($method != 'doActions' && $method != 'formObjectOptions') return $this->resPrint; // TODO remove this. When there is something to print, ->resPrint is filled. return ($error?-1:$resaction); } 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/menus/standard/eldy.lib.php b/htdocs/core/menus/standard/eldy.lib.php index 7fdff999410..51e61dfb6c9 100644 --- a/htdocs/core/menus/standard/eldy.lib.php +++ b/htdocs/core/menus/standard/eldy.lib.php @@ -1,7 +1,7 @@ * Copyright (C) 2010 Regis Houssin - * Copyright (C) 2012 Juanjo Menent + * Copyright (C) 2012-2013 Juanjo Menent * * 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 @@ -913,7 +913,7 @@ function print_left_eldy_menu($db,$menu_array_before,$menu_array_after) $newmenu->add("/compta/facture/list.php?leftmenu=customers_bills",$langs->trans("BillsCustomers"),0,$user->rights->facture->lire, '', $mainmenu, 'customers_bills'); if (empty($user->societe_id)) { - $newmenu->add("/compta/clients.php?action=facturer&leftmenu=customers_bills",$langs->trans("NewBill"),1,$user->rights->facture->creer); + $newmenu->add("/compta/facture.php?action=create&leftmenu=customers_bills",$langs->trans("NewBill"),1,$user->rights->facture->creer); } $newmenu->add("/compta/facture/fiche-rec.php?leftmenu=customers_bills",$langs->trans("Repeatables"),1,$user->rights->facture->lire); 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/admin_extrafields.tpl.php b/htdocs/core/tpl/admin_extrafields.tpl.php index d8f23a4c183..f2ce0efa59b 100644 --- a/htdocs/core/tpl/admin_extrafields.tpl.php +++ b/htdocs/core/tpl/admin_extrafields.tpl.php @@ -29,6 +29,7 @@ else if (type == 'int') { size.val('10').removeAttr('disabled'); } else if (type == 'text') { size.val('2000').removeAttr('disabled'); } else if (type == 'varchar') { size.val('255').removeAttr('disabled'); } + else if (type == 'boolean') { size.val('').attr('disabled','disabled'); unique.attr('disabled','disabled');} else size.val('').attr('disabled','disabled'); } init_typeoffields(); diff --git a/htdocs/core/tpl/admin_extrafields_add.tpl.php b/htdocs/core/tpl/admin_extrafields_add.tpl.php index d28fe1c33b2..3215c235281 100644 --- a/htdocs/core/tpl/admin_extrafields_add.tpl.php +++ b/htdocs/core/tpl/admin_extrafields_add.tpl.php @@ -31,6 +31,7 @@ else if (type == 'int') { size.val('10').removeAttr('disabled'); unique.removeAttr('disabled','disabled'); } else if (type == 'text') { size.val('2000').removeAttr('disabled'); unique.attr('disabled','disabled').removeAttr('checked'); } else if (type == 'varchar') { size.val('255').removeAttr('disabled'); unique.removeAttr('disabled','disabled'); } + else if (type == 'boolean') { size.val('').attr('disabled','disabled'); unique.attr('disabled','disabled');} else size.val('').attr('disabled','disabled'); } init_typeoffields(''); diff --git a/htdocs/core/tpl/admin_extrafields_edit.tpl.php b/htdocs/core/tpl/admin_extrafields_edit.tpl.php index d681d7cf82c..4df48df6702 100644 --- a/htdocs/core/tpl/admin_extrafields_edit.tpl.php +++ b/htdocs/core/tpl/admin_extrafields_edit.tpl.php @@ -31,6 +31,7 @@ else if (type == 'int') { size.removeAttr('disabled'); } else if (type == 'text') { size.removeAttr('disabled'); unique.attr('disabled','disabled').removeAttr('checked'); } else if (type == 'varchar') { size.removeAttr('disabled'); } + else if (type == 'boolean') { size.val('').attr('disabled','disabled'); unique.attr('disabled','disabled');} else size.val('').attr('disabled','disabled'); } init_typeoffields(jQuery("#type").val()); 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/filefunc.inc.php b/htdocs/filefunc.inc.php index 35404140050..739a2372430 100755 --- a/htdocs/filefunc.inc.php +++ b/htdocs/filefunc.inc.php @@ -29,7 +29,7 @@ * \brief File that include conf.php file and commons lib like functions.lib.php */ -if (! defined('DOL_VERSION')) define('DOL_VERSION','3.3.0-beta'); +if (! defined('DOL_VERSION')) define('DOL_VERSION','3.4.0-alpha'); if (! defined('EURO')) define('EURO',chr(128)); // Define syslog constants 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 @@ -'2.9.0', 'to'=>'3.0.0'), array('from'=>'3.0.0', 'to'=>'3.1.0'), array('from'=>'3.1.0', 'to'=>'3.2.0'), - array('from'=>'3.2.0', 'to'=>'3.3.0') - ); + array('from'=>'3.2.0', 'to'=>'3.3.0'), + array('from'=>'3.3.0', 'to'=>'3.4.0') + ); $count=0; foreach ($migrationscript as $migarray) diff --git a/htdocs/install/doctemplates/invoices/template_invoice.odt b/htdocs/install/doctemplates/invoices/template_invoice.odt index 2d50e435221..2c43d353bbb 100644 Binary files a/htdocs/install/doctemplates/invoices/template_invoice.odt and b/htdocs/install/doctemplates/invoices/template_invoice.odt differ diff --git a/htdocs/install/mssql/functions/functions.sql b/htdocs/install/mssql/functions/functions.sql index f5e8ad59ae8..93766a22406 100644 Binary files a/htdocs/install/mssql/functions/functions.sql and b/htdocs/install/mssql/functions/functions.sql differ diff --git a/htdocs/install/mysql/migration/3.3.0-3.4.0.sql b/htdocs/install/mysql/migration/3.3.0-3.4.0.sql new file mode 100755 index 00000000000..0943c5aca11 --- /dev/null +++ b/htdocs/install/mysql/migration/3.3.0-3.4.0.sql @@ -0,0 +1,17 @@ +-- +-- Be carefull to requests order. +-- This file must be loaded by calling /install/index.php page +-- when current version is 3.4.0 or higher. +-- +-- To rename a table: ALTER TABLE llx_table RENAME TO llx_table_new; +-- To add a column: ALTER TABLE llx_table ADD COLUMN newcol varchar(60) NOT NULL DEFAULT '0' AFTER existingcol; +-- To rename a column: ALTER TABLE llx_table CHANGE COLUMN oldname newname varchar(60); +-- To drop a column: ALTER TABLE llx_table DROP COLUMN oldname; +-- To change type of field: ALTER TABLE llx_table MODIFY COLUMN name varchar(60); +-- To restrict request to Mysql version x.y use -- VMYSQLx.y +-- To restrict request to Pgsql version x.y use -- VPGSQLx.y + + +-- -- VPGSQL8.2 DELETE FROM llx_usergroup_user WHERE fk_user NOT IN (SELECT rowid from llx_user); +-- -- VMYSQL4.1 DELETE FROM llx_usergroup_user WHERE fk_usergroup NOT IN (SELECT rowid from llx_usergroup); + diff --git a/htdocs/install/mysql/tables/llx_c_availability.sql b/htdocs/install/mysql/tables/llx_c_availability.sql index 0292b90fb3a..437240820c2 100644 --- a/htdocs/install/mysql/tables/llx_c_availability.sql +++ b/htdocs/install/mysql/tables/llx_c_availability.sql @@ -1,26 +1,26 @@ --- ======================================================================== --- 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; +-- ======================================================================== +-- 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/admin.lang b/htdocs/langs/en_US/admin.lang index 6007be581fc..9ecda1dbcef 100644 --- a/htdocs/langs/en_US/admin.lang +++ b/htdocs/langs/en_US/admin.lang @@ -351,6 +351,7 @@ Int=Integer Float=Float DateAndTime=Date and hour Unique=Unique +Boolean=Boolean (Checkbox) LibraryToBuildPDF=Library used to build PDF WarningUsingFPDF=Warning: Your conf.php contains directive dolibarr_pdf_force_fpdf=1. This means you use the FPDF library to generate PDF files. This library is old and does not support a lot of features (Unicode, image transparency, cyrillic, arab and asiatic languages, ...), so you may experience errors during PDF generation.
To solve this and have a full support of PDF generation, please download TCPDF library, then comment or remove the line $dolibarr_pdf_force_fpdf=1, and add instead $dolibarr_lib_TCPDF_PATH='path_to_TCPDF_dir' LocalTaxDesc=Some countries apply 2 or 3 taxes on each invoice line. If this is the case, choose type for second and third tax and its rate. Possible type are:
1 : local tax apply on products and services without vat (vat is not applied on local tax)
2 : local tax apply on products and services before vat (vat is calculated on amount + localtax)
3 : local tax apply on products without vat (vat is not applied on local tax)
4 : local tax apply on products before vat (vat is calculated on amount + localtax)
5 : local tax apply on services without vat (vat is not applied on local tax)
6 : local tax apply on services before vat (vat is calculated on amount + localtax) 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/admin.lang b/htdocs/langs/fr_FR/admin.lang index d077ffedb4e..0effda388ec 100644 --- a/htdocs/langs/fr_FR/admin.lang +++ b/htdocs/langs/fr_FR/admin.lang @@ -346,6 +346,7 @@ TextLong=Texte long Int=Numérique entier Float=Décimal DateAndTime=Date et heure +Boolean=Booleen (Checkbox) LibraryToBuildPDF=Bibliothèque utilisée pour la génération des PDF WarningUsingFPDF=Attention: Votre fichier conf.php contient la directive dolibarr_pdf_force_fpdf=1. Cela signifie que vous utilisez la librairie FPDF pour générer vos fichiers PDF. Cette librairie est ancienne et ne couvre pas de nombreuses fonctionnalitée (Unicode, transparence des images, langues cyrillic, arabes ou asiatiques...), aussi vous pouvez rencontrez des problèmes durant la génération des PDF.
Pour résoudre cela et avoir un support complet de PDF, vous pouvez télécharger la librairie TCPDF puis commenter ou supprimer la ligne $dolibarr_pdf_force_fpdf=1, et ajouter à la place $dolibarr_lib_TCPDF_PATH='chemin_vers_TCPDF' LocalTaxDesc=Certains pays appliquent 2 voir 3 taux sur chaque ligne de facture. Si c'est le cas, choisissez le type du deuxième et troisième taux et sa valeur. Les types possibles sont:
1 : taxe locale sur les produits et services hors tva (la tva n'est pas appliquée sur la taxe locale)
2 : taxe locale sur les produits et services avant tva (la tva est appliquée sur le montant + la taxe locale)
3 : taxe locale uniquement sur les produits hors tva (la tva n'est pas appliquée sur la taxe locale)
4 : taxe locale uniquement sur les produits avant tva (la tva est appliquée sur le montant + la taxe locale)
5 : taxe locale uniquement sur les services hors tva (la tva n'est pas appliquée sur la taxe locale)
6 : taxe locale uniquement sur les service avant tva (la tva est appliquée sur le montant + la taxe locale) 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/main.inc.php b/htdocs/main.inc.php index 28e990aa298..97d5d78f467 100644 --- a/htdocs/main.inc.php +++ b/htdocs/main.inc.php @@ -912,13 +912,15 @@ function top_htmlhead($head, $title='', $disablejs=0, $disablehead=0, $arrayofjs print ''."\n"; // Output style sheets (optioncss='print' or ''). Note: $conf->css looks like '/theme/eldy/style.css.php' $themepath=dol_buildpath((empty($conf->global->MAIN_FORCETHEMEDIR)?'':$conf->global->MAIN_FORCETHEMEDIR).$conf->css,1); + $themesubdir=''; if (! empty($conf->modules_parts['theme'])) // This slow down { foreach($conf->modules_parts['theme'] as $reldir) { - if (file_exists(dol_buildpath($reldir.$conf->css, 0))) + if (file_exists(dol_buildpath($reldir.$conf->css, 0))) { $themepath=dol_buildpath($reldir.$conf->css, 1); + $themesubdir=$reldir; break; } } @@ -1063,7 +1065,7 @@ function top_htmlhead($head, $title='', $disablejs=0, $disablehead=0, $arrayofjs if (constant('JS_CKEDITOR')) $pathckeditor=JS_CKEDITOR; // To use external ckeditor js lib print ''."\n"; 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 b922db4c50d..8c9b07abdb9 100644 --- a/htdocs/societe/agenda.php +++ b/htdocs/societe/agenda.php @@ -37,11 +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')); + /* * 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/societe/info.php b/htdocs/societe/info.php index 21d3549ed86..75caf00c714 100644 --- a/htdocs/societe/info.php +++ b/htdocs/societe/info.php @@ -37,12 +37,29 @@ $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')); + + /* -* View -*/ + * Actions + */ -llxHeader(); +$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); + + + +/* + * View + */ + +$help_url='EN:Module_Third_Parties|FR:Module_Tiers|ES:Empresas'; +llxHeader('',$langs->trans("ThirdParty"),$help_url); $soc = new Societe($db); $soc->fetch($socid); 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/class/user.class.php b/htdocs/user/class/user.class.php index 441186179b3..6ae0315c143 100644 --- a/htdocs/user/class/user.class.php +++ b/htdocs/user/class/user.class.php @@ -980,6 +980,7 @@ class User extends CommonObject $this->lastname = $member->lastname; $this->firstname = $member->firstname; $this->email = $member->email; + $this->fk_member = $member->id; $this->pass = $member->pass; if (empty($login)) $login=strtolower(substr($member->firstname, 0, 4)) . strtolower(substr($member->lastname, 0, 4)); @@ -992,26 +993,26 @@ class User extends CommonObject if ($result > 0) { $result=$this->setPassword($user,$this->pass); - - $sql = "UPDATE ".MAIN_DB_PREFIX."user"; - $sql.= " SET fk_member=".$member->id; - if ($member->fk_soc) $sql.= ", fk_societe=".$member->fk_soc; - $sql.= " WHERE rowid=".$this->id; - - dol_syslog(get_class($this)."::create_from_member sql=".$sql, LOG_DEBUG); - $resql=$this->db->query($sql); - if ($resql) - { - $this->db->commit(); - return $this->id; - } - else - { - $this->error=$this->db->error(); - dol_syslog(get_class($this)."::create_from_member - 1 - ".$this->error, LOG_ERR); - - $this->db->rollback(); - return -1; + if ($member->fk_soc) { + $sql = "UPDATE ".MAIN_DB_PREFIX."user"; + $sql.= " SET fk_societe=".$member->fk_soc; + $sql.= " WHERE rowid=".$this->id; + + dol_syslog(get_class($this)."::create_from_member sql=".$sql, LOG_DEBUG); + $resql=$this->db->query($sql); + if ($resql) + { + $this->db->commit(); + return $this->id; + } + else + { + $this->error=$this->db->error(); + dol_syslog(get_class($this)."::create_from_member - 1 - ".$this->error, LOG_ERR); + + $this->db->rollback(); + return -1; + } } } else 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 b38917eb17c..fe071f7fd40 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; } diff --git a/test/phpunit/AdherentTest.php b/test/phpunit/AdherentTest.php index e6ed5ebdddb..03be97ecec2 100644 --- a/test/phpunit/AdherentTest.php +++ b/test/phpunit/AdherentTest.php @@ -139,7 +139,7 @@ class AdherentTest extends PHPUnit_Framework_TestCase /** * testAdherentFetch * - * @param int $id Id of object to fecth + * @param int $id Id of object to fetch * @return object Fetched object * * @depends testAdherentCreate @@ -161,13 +161,38 @@ class AdherentTest extends PHPUnit_Framework_TestCase return $localobject; } + /** + * testAdherentFetchLogin + * + * @param Adherent $localobject Member instance + * @return Adherent + * + * @depends testAdherentFetch + * The depends says test is run only if previous is ok + */ + public function testAdherentFetchLogin(Adherent $localobject) + { + global $conf,$user,$langs,$db; + $conf=$this->savconf; + $user=$this->savuser; + $langs=$this->savlangs; + $db=$this->savdb; + + $newobject = new Adherent($this->savdb); + $result = $newobject->fetch_login($localobject->login); + + $this->assertEquals($newobject, $localobject); + + return $localobject; + } + /** * testAdherentUpdate * * @param Adherent $localobject Member instance * @return Adherent * - * @depends testAdherentFetch + * @depends testAdherentFetchLogin * The depends says test is run only if previous is ok */ public function testAdherentUpdate(Adherent $localobject) @@ -225,6 +250,7 @@ class AdherentTest extends PHPUnit_Framework_TestCase $this->assertEquals($localobject->town, $newobject->town); $this->assertEquals($localobject->country_id, $newobject->country_id); $this->assertEquals('BE', $newobject->country_code); + $this->assertEquals('Belgium', $newobject->country); $this->assertEquals($localobject->statut, $newobject->statut); $this->assertEquals($localobject->phone, $newobject->phone); $this->assertEquals($localobject->phone_perso, $newobject->phone_perso); @@ -233,7 +259,8 @@ class AdherentTest extends PHPUnit_Framework_TestCase $this->assertEquals($localobject->naiss, $timestamp); $this->assertEquals($localobject->morphy, $newobject->morphy); - return $localobject; + //We return newobject because of new values + return $newobject; } /** @@ -258,8 +285,8 @@ class AdherentTest extends PHPUnit_Framework_TestCase '%NOM%,%SOCIETE%,%ADRESSE%,%CP%,%VILLE%,%PAYS%'; $expected = DOL_MAIN_URL_ROOT.','.$localobject->id.',0,New firstname,New name,New firstname New name,'. - 'New company,New address,New zip,New town,,newemail@newemail.com,'.dol_print_date($localobject->naiss,'day').',,'. - 'newlogin,dolibspec,New firstname,New name,New company,New address,New zip,New town,'; + 'New company,New address,New zip,New town,Belgium,newemail@newemail.com,'.dol_print_date($localobject->naiss,'day').',,'. + 'newlogin,dolibspec,New firstname,New name,New company,New address,New zip,New town,Belgium'; $result = $localobject->makeSubstitution($template); print __METHOD__." result=".$result."\n"; @@ -268,16 +295,107 @@ class AdherentTest extends PHPUnit_Framework_TestCase return $localobject; } + /** + * testAdherentSetUserId + * + * @param Adherent $localobject Member instance + * @return Adherent + * + * @depends testAdherentMakeSubstitution + * The depends says test is run only if previous is ok + */ + public function testAdherentSetUserId(Adherent $localobject) + { + global $conf,$user,$langs,$db; + $conf=$this->savconf; + $user=$this->savuser; + $langs=$this->savlangs; + $db=$this->savdb; + + //We associate member with user + $result = $localobject->setUserId($user->id); + print __METHOD__." id=".$localobject->id." result=".$result."\n"; + $this->assertEquals($result, 1); + + //We update user object + $user->fetch($user->id); + print __METHOD__." user id=".$user->id." fk_member=".$user->fk_member."\n"; + + $this->assertEquals($user->fk_member, $localobject->id); + + //We remove association with user + $result = $localobject->setUserId(0); + print __METHOD__." id=".$localobject->id." result=".$result."\n"; + $this->assertEquals($result, 1); + + //We update user object + $user->fetch($user->id); + print __METHOD__." user id=".$user->id." fk_member=".$user->fk_member."\n"; + + $this->assertNull($user->fk_member); + + return $localobject; + } + + /** + * testAdherentSetThirdPartyId + * + * @param Adherent $localobject Member instance + * @return Adherent + * + * @depends testAdherentSetUserId + * The depends says test is run only if previous is ok + */ + public function testAdherentSetThirdPartyId(Adherent $localobject) + { + global $conf,$user,$langs,$db; + $conf=$this->savconf; + $user=$this->savuser; + $langs=$this->savlangs; + $db=$this->savdb; + + //Create a Third Party + $thirdparty = new Societe($db); + $thirdparty->initAsSpecimen(); + $result = $thirdparty->create($user); + print __METHOD__." id=".$localobject->id." third party id=".$thirdparty->id." result=".$result."\n"; + $this->assertTrue($result > 0); + + //Set Third Party ID + $result = $localobject->setThirdPartyId($thirdparty->id); + $this->assertEquals($result, 1); + print __METHOD__." id=".$localobject->id." result=".$result."\n"; + + //Adherent is updated with new data + $localobject->fetch($localobject->id); + $this->assertEquals($localobject->fk_soc, $thirdparty->id); + print __METHOD__." id=".$localobject->id." result=".$result."\n"; + + //We remove the third party association + $result = $localobject->setThirdPartyId(0); + $this->assertEquals($result, 1); + + //And check if it has been updated + $localobject->fetch($localobject->id); + $this->assertNull($localobject->fk_soc); + + //Now we remove the third party + $result = $thirdparty->delete($thirdparty->id); + $this->assertEquals($result, 1); + + return $localobject; + } + /** * testAdherentValid * * @param Adherent $localobject Member instance * @return Adherent * - * @depends testAdherentMakeSubstitution + * @depends testAdherentSetThirdPartyId * The depends says test is run only if previous is ok */ - public function testAdherentValid(Adherent $localobject) + public function testAdherentValidate(Adherent $localobject) { global $conf,$user,$langs,$db; $conf=$this->savconf; @@ -298,7 +416,7 @@ class AdherentTest extends PHPUnit_Framework_TestCase * @param Adherent $localobject Member instance * @return int Id of object * - * @depends testAdherentValid + * @depends testAdherentValidate * The depends says test is run only if previous is ok */ public function testAdherentOther(Adherent $localobject) @@ -318,19 +436,56 @@ class AdherentTest extends PHPUnit_Framework_TestCase print __METHOD__." localobject->date_creation=".$localobject->date_creation."\n"; $this->assertNotEquals($localobject->date_creation, ''); - return $localobject->id; + return $localobject; + } + + /** + * testAdherentResiliate + * + * @param Adherent $localobject Member instance + * @return Adherent + * + * @depends testAdherentOther + * The depends says test is run only if previous is ok + */ + public function testAdherentResiliate(Adherent $localobject) + { + global $conf,$user,$langs,$db; + $conf=$this->savconf; + $user=$this->savuser; + $langs=$this->savlangs; + $db=$this->savdb; + + //Let's resilie un adherent + $result = $localobject->resiliate($user); + print __METHOD__." id=".$localobject->id." result=".$result."\n"; + $this->assertEquals($result, 1); + + //Is statut updated? + $this->assertEquals($localobject->statut, 0); + + //We update the object and let's check if it was updated on DB + $localobject->fetch($localobject->id); + $this->assertEquals($localobject->statut, 0); + + //Now that status=0, resiliate should return 0 + $result = $localobject->resiliate($user); + print __METHOD__." id=".$localobject->id." result=".$result."\n"; + $this->assertEquals($result, 0); + + return $localobject; } /** * testAdherentDelete * - * @param int $id Id of object to delete + * @param Adherent $localobject Member instance * @return void * - * @depends testAdherentOther + * @depends testAdherentResiliate * The depends says test is run only if previous is ok */ - public function testAdherentDelete($id) + public function testAdherentDelete($localobject) { global $conf,$user,$langs,$db; $conf=$this->savconf; @@ -338,10 +493,8 @@ class AdherentTest extends PHPUnit_Framework_TestCase $langs=$this->savlangs; $db=$this->savdb; - $localobject=new Adherent($this->savdb); - $result=$localobject->fetch($id); - $result=$localobject->delete($id); - print __METHOD__." id=".$id." result=".$result."\n"; + $result=$localobject->delete($localobject->id); + print __METHOD__." id=".$localobject->id." result=".$result."\n"; $this->assertLessThan($result, 0); return $result;
'; // 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 '