* Copyright (C) 2003 Jean-Louis Bergamo * Copyright (C) 2004-2008 Laurent Destailleur * Copyright (C) 2004 Sebastien Di Cintio * Copyright (C) 2004 Benoit Mortier * Copyright (C) 2004 Christophe Combelles * Copyright (C) 2005-2007 Regis Houssin * Copyright (C) 2008 Raphael Bertrand (Resultic) * * 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, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * or see http://www.gnu.org/ */ /** * \file htdocs/lib/functions.lib.php * \brief A set of functions for Dolibarr * This file contains all frequently used functions. * \version $Id$ */ // For compatibility during upgrade if (! defined('DOL_DOCUMENT_ROOT')) define('DOL_DOCUMENT_ROOT', '..'); if (! defined('ADODB_DATE_VERSION')) include_once(DOL_DOCUMENT_ROOT."/includes/adodbtime/adodb-time.inc.php"); /** * \brief Renvoi vrai si l'email est syntaxiquement valide * \param address adresse email (Ex: "toto@titi.com", "John Do ") * \return boolean true si email valide, false sinon */ function ValidEmail($address) { if (eregi(".*<(.+)>", $address, $regs)) { $address = $regs[1]; } if (eregi("^[^@ ]+@([a-zA-Z0-9\-]+\.)+([a-zA-Z0-9\-]{2}|coop|aero|biz|com|edu|gov|info|int|mil|name|net|org)\$",$address)) { return true; } else { return false; } } /** * \brief Renvoi vrai si l'email a un nom de domaine qui r�soud via dns * \param mail adresse email (Ex: "toto@titi.com", "John Do ") * \return boolean true si email valide, false sinon */ function check_mail($mail) { list($user, $domain) = split("@", $mail, 2); if (checkdnsrr($domain, "MX")) { return true; } else { return false; } } /** * \brief Clean a string to use it as a file name. * \param str String to clean * \param newstr String to replace bad chars by * \return string String cleaned (a-zA-Z_) */ function sanitizeFileName($str,$newstr='_') { return dol_string_nospecial(dol_string_unaccent($str),$newstr); } /** * \brief Clean a string from all accent characters * \param str String to clean * \return string Cleaned string */ function dol_string_unaccent($str) { if (utf8_check($str)) { $string = rawurlencode($str); $replacements = array( '%C3%80' => 'A','%C3%81' => 'A', '%C3%88' => 'E','%C3%89' => 'E', '%C3%8C' => 'I','%C3%8D' => 'I', '%C3%92' => 'O','%C3%93' => 'O', '%C3%99' => 'U','%C3%9A' => 'U', '%C3%A0' => 'a','%C3%A1' => 'a','%C3%A2' => 'a', '%C3%A8' => 'e','%C3%A9' => 'e','%C3%AA' => 'e','%C3%AB' => 'e', '%C3%AC' => 'i','%C3%AD' => 'i', '%C3%B2' => 'o','%C3%B3' => 'o', '%C3%B9' => 'u','%C3%BA' => 'u' ); $string=strtr($string, $replacements); return rawurldecode($string); } else { $string = strtr($str, "xC0\xC1\xC2\xC3\xC5\xC7 \xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF\xD0\xD1 \xD2\xD3\xD4\xD5\xD8\xD9\xDA\xDB\xDD \xE0\xE1\xE2\xE3\xE5\xE7\xE8\xE9\xEA\xEB \xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4\xF5\xF8 \xF9\xFA\xFB\xFD\xFF", "AAAAAC EEEEIIIIDN OOOOOUUUY aaaaaceeee iiiidnooooo uuuyy"); $string = strtr($string, array("\xC4"=>"Ae", "\xC6"=>"AE", "\xD6"=>"Oe", "\xDC"=>"Ue", "\xDE"=>"TH", "\xDF"=>"ss", "\xE4"=>"ae", "\xE6"=>"ae", "\xF6"=>"oe", "\xFC"=>"ue", "\xFE"=>"th")); return $string; } } /** * \brief Clean a string from all punctuation characters * \param str String to clean * \param newstr String to replace bad chars by * \return string Cleaned string */ function dol_string_nospecial($str,$newstr='_') { $forbidden_chars_to_underscore=array(" ","'","/","\\",":","*","?","\"","<",">","|","[","]",",",";","="); //$forbidden_chars_to_remove=array("(",")"); $forbidden_chars_to_remove=array(); return str_replace($forbidden_chars_to_underscore,$newstr,str_replace($forbidden_chars_to_remove,"",$str)); } /** * \brief Returns text escaped for inclusion in javascript code * \param $stringtoescape String to escape * \return string Escaped string */ function dol_escape_js($stringtoescape) { // escape quotes and backslashes, newlines, etc. return strtr($stringtoescape, array('\\'=>'\\\\',"'"=>"\\'",'"'=>'\\"',"\r"=>'\\r',"\n"=>'\\n',''<\/')); } /** * \brief Envoi des messages dolibarr dans un fichier ou dans syslog * Pour fichier: fichier defini par SYSLOG_FILE * Pour syslog: facility defini par SYSLOG_FACILITY * \param message Message a tracer. Ne doit pas etre traduit si level = LOG_ERR * \param level Niveau de l'erreur * \remarks Cette fonction n'a un effet que si le module syslog est active. * Warning, les fonctions syslog sont buggues sous Windows et generent des * fautes de protection memoire. Pour resoudre, utiliser le loggage fichier, * au lieu du loggage syslog (configuration du module). * Si SYSLOG_FILE_NO_ERROR defini, on ne gere pas erreur ecriture log * \remarks On Windows LOG_ERR=4, LOG_WARNING=5, LOG_NOTICE=LOG_INFO=LOG_DEBUG=6 * On Linux LOG_ERR=3, LOG_WARNING=4, LOG_INFO=6, LOG_DEBUG=7 */ function dolibarr_syslog($message, $level=LOG_INFO) { global $conf,$user,$langs; if (! empty($conf->syslog->enabled)) { //print $level.' - '.$conf->global->SYSLOG_LEVEL.' - '.$conf->syslog->enabled." \n"; if ($level > $conf->global->SYSLOG_LEVEL) return; // Load error message files if this is an error message (rare) if ($level == LOG_ERR) { $langs->load("errors"); if ($message != $langs->trans($message)) $message = $langs->trans($message); } // Add user to log message $login='???'; if (is_object($user) && $user->id) $login=$user->login; $message=sprintf("%-8s",$login)." ".$message; // Check if log is to a file (SYSLOG_FILE defined) or to syslog if (defined("SYSLOG_FILE") && SYSLOG_FILE) { $filelog=SYSLOG_FILE; $filelog=eregi_replace('DOL_DATA_ROOT',DOL_DATA_ROOT,$filelog); if (defined("SYSLOG_FILE_NO_ERROR")) $file=@fopen($filelog,"a+"); else $file=fopen($filelog,"a+"); if ($file) { $ip='unknown_ip'; if (! empty($_SERVER["REMOTE_ADDR"])) $ip=$_SERVER["REMOTE_ADDR"]; $liblevelarray=array(LOG_ERR=>'ERROR',LOG_WARNING=>'WARN',LOG_INFO=>'INFO',LOG_DEBUG=>'DEBUG'); $liblevel=$liblevelarray[$level]; if (! $liblevel) $liblevel='UNDEF'; $message=strftime("%Y-%m-%d %H:%M:%S",time())." ".sprintf("%-5s",$liblevel)." ".$ip." ".$message; fwrite($file,$message."\n"); fclose($file); // This is for log file, we do not change permissions // If enable html log tag enabled and url parameter log defined, we show output log on HTML comments if (! empty($conf->global->MAIN_ENABLE_LOG_HTML) && ! empty($_GET["log"])) { print "\n\n\n"; } } elseif (! defined("SYSLOG_FILE_NO_ERROR")) { $langs->load("main"); print $langs->trans("ErrorFailedToOpenFile",$filelog); } } else { if (function_exists('openlog')) // This function does not exists on some ISP (Ex: Free in France) { //define_syslog_variables(); already defined in master.inc.php if (defined("MAIN_SYSLOG_FACILITY") && MAIN_SYSLOG_FACILITY) { $facility = constant("MAIN_SYSLOG_FACILITY"); } elseif (defined("SYSLOG_FACILITY") && SYSLOG_FACILITY) { // Exemple: SYSLOG_FACILITY vaut LOG_USER qui vaut 8. On a besoin de 8 dans $facility. $facility = constant("SYSLOG_FACILITY"); } else { $facility = LOG_USER; } openlog("dolibarr", LOG_PID | LOG_PERROR, $facility); if (! $level) { syslog(LOG_ERR, $message); } else { syslog($level, $message); } closelog(); } } } } /** \brief Affiche le header d'une fiche \param links Tableau de titre d'onglets \param active 0=onglet non actif, 1=onglet actif \param title Titre tabelau ("" par defaut) \param notab 0=Add tab header, 1=no tab header */ function dolibarr_fiche_head($links, $active='0', $title='', $notab=0) { print "\n".'
'."\n"; // Affichage titre if ($title) { $limittitle=30; print ''; print ((!defined('MAIN_USE_SHORT_TITLE')) || (defined('MAIN_USE_SHORT_TITLE') && MAIN_USE_SHORT_TITLE)) ? dolibarr_trunc($title,$limittitle) : $title; print ''; } // Affichage onglets for ($i = 0 ; $i < sizeof($links) ; $i++) { if ($links[$i][2] == 'image') { print ''.$links[$i][1].''."\n"; } else { //print "x $i $active ".$links[$i][2]." z"; if ((is_numeric($active) && $i == $active) || (! is_numeric($active) && $active == $links[$i][2])) { print ''.$links[$i][1].''."\n"; } else { print ''.$links[$i][1].''."\n"; } } } print "
\n"; if (! $notab) print '
'."\n\n"; } /** \brief Sauvegarde parametrage personnel \param db Handler d'acc�s base \param user Objet utilisateur \param url Si defini, on sauve parametre du tableau tab dont cl� = (url avec sortfield, sortorder, begin et page) Si non defini on sauve tous parametres du tableau tab \param tab Tableau (cl�=>valeur) des param�tres a sauvegarder \return int <0 si ko, >0 si ok */ function dolibarr_set_user_page_param($db, &$user, $url='', $tab) { // Verification parametres if (sizeof($tab) < 1) return -1; $db->begin(); // On efface anciens param�tres pour toutes les cl� dans $ta $sql = "DELETE FROM ".MAIN_DB_PREFIX."user_param"; $sql.= " WHERE fk_user = ".$user->id; if ($url) $sql.=" AND page='".$url."'"; else $sql.=" AND page=''"; // Page ne peut etre null $sql.= " AND param in ("; $i=0; foreach ($tab as $key => $value) { if ($i > 0) $sql.=','; $sql.="'".$key."'"; $i++; } $sql.= ")"; dolibarr_syslog("functions.lib::dolibarr_set_user_page_param $sql"); $resql=$db->query($sql); if (! $resql) { dolibarr_print_error($db); $db->rollback(); exit; } foreach ($tab as $key => $value) { // On positionne nouveaux param�tres if ($value && (! $url || in_array($key,array('sortfield','sortorder','begin','page')))) { $sql = "INSERT INTO ".MAIN_DB_PREFIX."user_param(fk_user,page,param,value)"; $sql.= " VALUES (".$user->id.","; if ($url) $sql.= " '".urlencode($url)."',"; else $sql.= " '',"; $sql.= " '".$key."','".addslashes($value)."');"; dolibarr_syslog("functions.lib::dolibarr_set_user_page_param $sql"); $result=$db->query($sql); if (! $result) { dolibarr_print_error($db); $db->rollback(); exit; } $user->page_param[$key] = $value; } } $db->commit(); return 1; } /** \brief Formattage des nombres \param ca valeur a formater \return int valeur format�e */ function dolibarr_print_ca($ca) { global $langs,$conf; if ($ca > 1000) { $cat = round(($ca / 1000),2); $cat = "$cat K".$langs->trans("Currency".$conf->monnaie); } else { $cat = round($ca,2); $cat = "$cat ".$langs->trans("Currency".$conf->monnaie); } if ($ca > 1000000) { $cat = round(($ca / 1000000),2); $cat = "$cat M".$langs->trans("Currency".$conf->monnaie); } return $cat; } /** \brief Effectue un d�calage de date par rapport a une dur�e \param time Date timestamp ou au format YYYY-MM-DD \param duration_value Valeur de la dur�e a ajouter \param duration_unit Unit� de la dur�e a ajouter (d, m, y) \return int Nouveau timestamp */ function dolibarr_time_plus_duree($time,$duration_value,$duration_unit) { if ($duration_value == 0) return $time; if ($duration_value > 0) $deltastring="+".abs($duration_value); if ($duration_value < 0) $deltastring="-".abs($duration_value); if ($duration_unit == 'd') { $deltastring.=" day"; } if ($duration_unit == 'm') { $deltastring.=" month"; } if ($duration_unit == 'y') { $deltastring.=" year"; } return strtotime($deltastring,$time); } /** * \brief Output date in a string format according to language $conf->language * \param time GM Timestamps date (or 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM:SS' in server TZ) * \param format Output date format * "%d %b %Y", * "%d/%m/%Y %H:%M", * "%d/%m/%Y %H:%M:%S", * "day", "daytext", "dayhour", "dayhourldap", "dayhourtext" * \param to_gmt false=output string if for local server TZ users, true=output string is for GMT users * \param outputlangs Object lang that contains charset_output property to define output * This means output is endoded in UTF-8 in default case. * \return string Formated date or '' if time is null */ function dolibarr_print_date($time,$format='',$to_gmt=false,$outputlangs='') { global $conf,$langs; // Si format non defini, on prend $conf->format_date_text_short sinon %Y-%m-%d %H:%M:%S if (! $format) $format=(isset($conf->format_date_text_short) ? $conf->format_date_text_short : '%Y-%m-%d %H:%M:%S'); if ($format == 'day') $format=$conf->format_date_short; if ($format == 'hour') $format=$conf->format_hour_short; if ($format == 'daytext') $format=$conf->format_date_text; if ($format == 'daytextshort') $format=$conf->format_date_text_short; if ($format == 'dayhour') $format=$conf->format_date_hour_short; if ($format == 'dayhourtext') $format=$conf->format_date_hour_text; if ($format == 'dayhourtextshort') $format=$conf->format_date_hour_text_short; if ($format == 'dayhourlog') $format='%Y%m%d%H%M%S'; if ($format == 'dayhourldap') $format='%Y%m%d%H%M%SZ'; if ($format == 'dayhourxcard') $format='%Y%m%dT%H%M%SZ'; // If date undefined or "", we return "" if (strlen($time) == 0) return ''; // $time=0 allowed (it means 01/01/1970 00:00:00) // Analyse de la date (deprecated) if (eregi('^([0-9]+)\-([0-9]+)\-([0-9]+) ?([0-9]+)?:?([0-9]+)?:?([0-9]+)?',$time,$reg)) { // This part of code should not be used. dolibarr_syslog("Functions.lib::dolibarr_print_date function call with deprecated parameter", LOG_WARNING); // Date est au format 'YYYY-MM-DD' ou 'YYYY-MM-DD HH:MM:SS' $syear = $reg[1]; $smonth = $reg[2]; $sday = $reg[3]; $shour = $reg[4]; $smin = $reg[5]; $ssec = $reg[6]; $ret=adodb_strftime($format,dolibarr_mktime($shour,$smin,$ssec,$smonth,$sday,$syear),$to_gmt); } else { // Date is a timestamps $ret=adodb_strftime($format,$time,$to_gmt); } // What is page code of texts from strftime functions ? $pagecodefrom='ISO-8859-1'; $localtime=setlocale(LC_TIME,0); if (eregi('UTF',$localtime)) $pagecodefrom='UTF-8'; if (! is_object($outputlangs)) $outputlangs=$langs; return $outputlangs->convToOutputCharset($ret,$pagecodefrom); } /** * \brief Convert a GM string date into a GM Timestamps date * \param string Date in a string * YYYYMMDD * YYYYMMDDHHMMSS * DD/MM/YY ou DD/MM/YYYY * DD/MM/YY HH:MM:SS ou DD/MM/YYYY HH:MM:SS * \return date Date * \example 19700101020000 -> 7200 */ function dolibarr_stringtotime($string) { if (eregi('^([0-9]+)\/([0-9]+)\/([0-9]+) ?([0-9]+)?:?([0-9]+)?:?([0-9]+)?',$string,$reg)) { // This part of code should not be used. dolibarr_syslog("Functions.lib::dolibarr_stringtotime call to function with deprecated parameter", LOG_WARN); // Date est au format 'DD/MM/YY' ou 'DD/MM/YY HH:MM:SS' // Date est au format 'DD/MM/YYYY' ou 'DD/MM/YYYY HH:MM:SS' $sday = $reg[1]; $smonth = $reg[2]; $syear = $reg[3]; $shour = $reg[4]; $smin = $reg[5]; $ssec = $reg[6]; if ($syear < 50) $syear+=1900; if ($syear >= 50 && $syear < 100) $syear+=2000; $string=sprintf("%04d%02d%02d%02d%02d%02d",$syear,$smonth,$sday,$shour,$smin,$ssec); } $string=eregi_replace('[^0-9]','',$string); $tmp=$string.'000000'; $date=dolibarr_mktime(substr($tmp,8,2),substr($tmp,10,2),substr($tmp,12,2),substr($tmp,4,2),substr($tmp,6,2),substr($tmp,0,4),1); return $date; } /** * \brief Return an array with date info * \param timestamp Timestamp * \param fast Fast mode * \return array Array of informations * If no fast mode: * 'seconds' => $secs, * 'minutes' => $min, * 'hours' => $hour, * 'mday' => $day, * 'wday' => $dow, * 'mon' => $month, * 'year' => $year, * 'yday' => floor($secsInYear/$_day_power), * 'weekday' => gmdate('l',$_day_power*(3+$dow)), * 'month' => gmdate('F',mktime(0,0,0,$month,2,1971)), * 0 => $origd * If fast mode: * 'seconds' => $secs, * 'minutes' => $min, * 'hours' => $hour, * 'mday' => $day, * 'mon' => $month, * 'year' => $year, * 'yday' => floor($secsInYear/$_day_power), * 'leap' => $leaf, * 'ndays' => $ndays * \remarks PHP getdate is restricted to the years 1901-2038 on Unix and 1970-2038 on Windows */ function dolibarr_getdate($timestamp,$fast=false) { $usealternatemethod=false; if ($timestamp <= 0) $usealternatemethod=true; // <= 1970 if ($timestamp >= 2145913200) $usealternatemethod=true; // >= 2038 if ($usealternatemethod) { $arrayinfo=adodb_getdate($timestamp,$fast); } else { $arrayinfo=getdate($timestamp); } return $arrayinfo; } /** * Retourne une date fabriquee depuis infos. * Remplace la fonction mktime non implementee sous Windows si annee < 1970 * PHP mktime is restricted to the years 1901-2038 on Unix and 1970-2038 on Windows * @param hour Hour (can be -1 for undefined) * @param minute Minute (can be -1 for undefined) * @param second Second (can be -1 for undefined) * @param month Month * @param day Day * @param year Year * @param gm Time gm * @param check No check on parameters (Can use day 32, etc...) * @return timestamp Date en timestamp, '' if error */ function dolibarr_mktime($hour,$minute,$second,$month,$day,$year,$gm=0,$check=1) { //print "- ".$hour.",".$minute.",".$second.",".$month.",".$day.",".$year.",".$_SERVER["WINDIR"]." -"; // Clean parameters if ($hour == -1) $hour=0; if ($minute == -1) $minute=0; if ($second == -1) $second=0; // Check parameters if ($check) { if (! $month || ! $day) return ''; if ($day > 31) return ''; if ($month > 12) return ''; if ($hour < 0 || $hour > 24) return ''; if ($minute< 0 || $minute > 60) return ''; if ($second< 0 || $second > 60) return ''; } $usealternatemethod=false; if ($year <= 1970) $usealternatemethod=true; // <= 1970 if ($year >= 2038) $usealternatemethod=true; // >= 2038 if ($usealternatemethod || $gm) // Si time gm, seule adodb peut convertir { /* // On peut utiliser strtotime pour obtenir la traduction. // strtotime is ok for range: Vendredi 13 D�cembre 1901 20:45:54 GMT au Mardi 19 Janvier 2038 03:14:07 GMT. $montharray=array(1=>'january',2=>'february',3=>'march',4=>'april',5=>'may',6=>'june', 7=>'july',8=>'august',9=>'september',10=>'october',11=>'november',12=>'december'); $string=$day." ".$montharray[0+$month]." ".$year." ".$hour.":".$minute.":".$second." GMT"; $date=strtotime($string); print "- ".$string." ".$date." -"; */ $date=adodb_mktime($hour,$minute,$second,$month,$day,$year,0,$gm); } else { $date=mktime($hour,$minute,$second,$month,$day,$year); } return $date; } /** * \brief Returns formated date * \param fmt Format (Exemple: 'Y-m-d H:i:s') * \param timestamp Date. Exemple: Si timestamp=0 et gm=1, renvoi 01/01/1970 00:00:00 * \param gm 1 if timestamp was built with gmmktime, 0 if timestamp was build with mktime * \return string Formated date */ function dolibarr_date($fmt, $timestamp, $gm=0) { $usealternatemethod=false; if ($timestamp <= 0) $usealternatemethod=true; if ($timestamp >= 2145913200) $usealternatemethod=true; if ($usealternatemethod || $gm) // Si time gm, seule adodb peut convertir { $string=adodb_date($fmt,$timestamp,$gm); } else { $string=date($fmt,$timestamp); } return $string; } /** * \brief Affiche les informations d'un objet * \param object objet a afficher */ function dolibarr_print_object_info($object) { global $langs; $langs->load("other"); if (isset($object->user_creation) && $object->user_creation->fullname) print $langs->trans("CreatedBy")." : " . $object->user_creation->fullname . '
'; if (isset($object->date_creation)) print $langs->trans("DateCreation")." : " . dolibarr_print_date($object->date_creation,"dayhourtext") . '
'; if (isset($object->user_modification) && $object->user_modification->fullname) print $langs->trans("ModifiedBy")." : " . $object->user_modification->fullname . '
'; if (isset($object->date_modification)) print $langs->trans("DateLastModification")." : " . dolibarr_print_date($object->date_modification,"dayhourtext") . '
'; if (isset($object->user_validation) && $object->user_validation->fullname) print $langs->trans("ValidatedBy")." : " . $object->user_validation->fullname . '
'; if (isset($object->date_validation)) print $langs->trans("DateValidation")." : " . dolibarr_print_date($object->date_validation,"dayhourtext") . '
'; if (isset($object->user_cloture) && $object->user_cloture->fullname ) print $langs->trans("ClosedBy")." : " . $object->user_cloture->fullname . '
'; if (isset($object->date_cloture)) print $langs->trans("DateClosing")." : " . dolibarr_print_date($object->date_cloture,"dayhourtext") . '
'; if (isset($object->user_rappro) && $object->user_rappro->fullname ) print $langs->trans("ConciliatedBy")." : " . $object->user_rappro->fullname . '
'; if (isset($object->date_rappro)) print $langs->trans("DateConciliating")." : " . dolibarr_print_date($object->date_rappro,"dayhourtext") . '
'; } /** * \brief Format phone numbers according to country * \param phone Phone number to format * \param country Country to use for formatting * \param cid Id of contact if known * \param socid Id of third party if known * \param nolinks true means no HTML links is added * \param separ separation between numbers for a better visibility example : xx.xx.xx.xx.xx * \return string Formated phone number */ function dolibarr_print_phone($phone,$country="FR",$cid=0,$socid=0,$nolinks=false,$separ=" ") { global $conf,$user; $phone = ereg_replace("[ .-]","",trim($phone)); if (empty($phone)) { return ''; } $newphone=$phone; if (strtoupper($country) == "FR") { // France if (strlen($phone) == 10) { $newphone=substr($newphone,0,2).$separ.substr($newphone,2,2).$separ.substr($newphone,4,2).$separ.substr($newphone,6,2).$separ.substr($newphone,8,2); } elseif (strlen($newphone) == 7) { $newphone=substr($newphone,0,3).$separ.substr($newphone,3,2).$separ.substr($newphone,5,2); } elseif (strlen($newphone) == 9) { $newphone=substr($newphone,0,2).$separ.substr($newphone,2,3).$separ.substr($newphone,5,2).$separ.substr($newphone,7,2); } elseif (strlen($newphone) == 11) { $newphone=substr($newphone,0,3).$separ.substr($newphone,3,2).$separ.substr($newphone,5,2).$separ.substr($newphone,7,2).$separ.substr($newphone,9,2); } elseif (strlen($newphone) == 12) { $newphone=substr($newphone,0,4).$separ.substr($newphone,4,2).$separ.substr($newphone,6,2).$separ.substr($newphone,8,2).$separ.substr($newphone,10,2); } } if (empty($nolinks)) { if (($cid || $socid) && $conf->agenda->enabled && $user->rights->agenda->myactions->create) { $newphone=''.$newphone.''; } $clicktodiallink=dol_print_phone_link($phone); if ($clicktodiallink) { $newphone='
'.$newphone.' '.$clicktodiallink.'
'; } } return $newphone; } /** * \brief Return string with formated size * \param size Size to print * \return string Link */ function dol_print_size($size) { global $langs; return $size.' '.$langs->trans("Bytes"); } /** * \brief Show Url link * \param url Url to show * \param target Target for link * \param max Max number of characters to show * \return string HTML Link */ function dol_print_url($url,$target='_blank',$max=32) { if (empty($url)) return ''; $link=''; if (! eregi('^http',$url)) $link.='http://'; $link.=dolibarr_trunc($url,$max); $link.=''; return $link; } /** * \brief Show EMail link * \param email EMail to show * \param max Max number of characters to show * \return string HTML Link */ function dol_print_email($email,$max=32) { $link=''; $link.=dolibarr_trunc($email,$max); $link.=''; return $link; } /** * \brief Show click to dial link * \param phone Phone to call * \param option Type of picto * \return string Link */ function dol_print_phone_link($phone,$option=0) { global $conf,$user; $link=''; //if (! empty($conf->global->CLICKTODIAL_URL)) if ($conf->clicktodial->enabled) { // Cleaning phone number $phone = ereg_replace("[ .-]","",trim($phone)); $url = sprintf($conf->global->CLICKTODIAL_URL, urlencode($phone), urlencode($user->clicktodial_poste), urlencode($user->clicktodial_login), urlencode($user->clicktodial_password)); $link.=''.img_phone("default",0).''; } return $link; } /** * Make a strlen call. Works even in mbstring module not enabled * * @param unknown_type $string * @param unknown_type $stringencoding * @return unknown */ function dol_strlen($string,$stringencoding='') { global $langs; if (empty($stringencoding)) $stringencoding=$langs->charset_output; $ret=''; if (function_exists('mb_strlen')) { $ret=mb_strlen($string,$stringencoding); } else { $ret=strlen($string); } return $ret; } /** * Make a substring. Works even in mbstring module not enabled * * @param unknown_type $string * @param unknown_type $start * @param unknown_type $length * @param unknown_type $stringencoding * @return unknown */ function dol_substr($string,$start,$length,$stringencoding='') { global $langs; if (empty($stringencoding)) $stringencoding=$langs->charset_output; $ret=''; if (function_exists('mb_substr')) { $ret=mb_substr($string,$start,$length,$stringencoding); } else { $ret=substr($string,$start,$length); } return $ret; } /** * \brief Truncate a string to a particular length adding '...' if string larger than length * \param string String to truncate * \param size Max string size. 0 for no limit. * \param trunc Where to trunc: right, left, middle * \return string Truncated string * \remarks USE_SHORT_TITLE=0 can disable all truncings */ function dolibarr_trunc($string,$size=40,$trunc='right',$stringencoding='') { global $conf; if ($size==0) return $string; if (! defined('USE_SHORT_TITLE') || (defined('USE_SHORT_TITLE') && USE_SHORT_TITLE)) { // We go always here if ($trunc == 'right') { if (dol_strlen($string,$stringencoding) > $size) return dol_substr($string,0,$size,$stringencoding).'...'; else return $string; } if ($trunc == 'middle') { if (dol_strlen($string,$stringencoding) > 2 && dol_strlen($string,$stringencoding) > $size) { $size1=round($size/2); $size2=round($size/2); return dol_substr($string,0,$size1,$stringencoding).'...'.dol_substr($string,dol_strlen($string,$stringencoding) - $size2,$size2,$stringencoding); } else return $string; } if ($trunc == 'left') { if (dol_strlen($string,$stringencoding) > $size) return '...'.dol_substr($string,dol_strlen($string,$stringencoding) - $size,$size,$stringencoding); else return $string; } } else { return $string; } } /** * \brief Complete une chaine a une taille donnee par des espaces * \param string Chaine a completer * \param size Longueur de la chaine. * \param side 0=Completion a droite, 1=Completion a gauche * \param char Chaine de completion * \return string Chaine complete */ function dolibarr_pad($string,$size,$side,$char=' ') { $taille=sizeof($string); $i=0; while($i < ($size - $taille)) { if ($side > 0) $string.=$char; else $string=$char.$string; $i++; } return $string; } /** * \brief Affiche picto propre a une notion/module (fonction g�n�rique) * \param alt Texte sur le alt de l'image * \param object Objet pour lequel il faut afficher le logo (exemple: user, group, action, bill, contract, propal, product, ...) * \return string Retourne tag img */ function img_object($alt, $object) { global $conf,$langs; return ''.$alt.''; } /** * \brief Affiche picto (fonction generique) * \param alt Texte sur le alt de l'image * \param picto Nom de l'image a afficher (Si pas d'extension, on met '.png') * \param options Attribut supplementaire a la balise img * \param pictoisfullpath If 1, image path is a full path * \return string Retourne tag img */ function img_picto($alt, $picto, $options='', $pictoisfullpath=0) { global $conf; if (! eregi('(\.png|\.gif)$',$picto)) $picto.='.png'; if ($pictoisfullpath) return ''.$alt.''; return ''.$alt.''; } /** \brief Affiche picto (fonction g�n�rique) \param alt Texte sur le alt de l'image \param picto Nom de l'image a afficher (Si pas d'extension, on met '.png') \param options Attribut supplementaire a la balise img \param pictoisfullpath If 1, image path is a full path \return string Retourne tag img */ function img_picto_common($alt, $picto, $options='', $pictoisfullpath=0) { global $conf; if (! eregi('(\.png|\.gif)$',$picto)) $picto.='.png'; if ($pictoisfullpath) return ''.$alt.''; return ''.$alt.''; } /** * \brief Affiche logo action * \param alt Texte sur le alt de l'image * \param numaction Determine image action * \return string Retourne tag img */ function img_action($alt = "default", $numaction) { global $conf,$langs; if ($alt=="default") { if ($numaction == -1) $alt=$langs->trans("ChangeDoNotContact"); if ($numaction == 0) $alt=$langs->trans("ChangeNeverContacted"); if ($numaction == 1) $alt=$langs->trans("ChangeToContact"); if ($numaction == 2) $alt=$langs->trans("ChangeContactInProcess"); if ($numaction == 3) $alt=$langs->trans("ChangeContactDone"); } return ''.$alt.''; } /** \brief Affiche logo fichier \param alt Texte sur le alt de l'image \return string Retourne tag img */ function img_file($alt = "default") { global $conf,$langs; if ($alt=="default") $alt=$langs->trans("Show"); return ''.$alt.''; } /** \brief Affiche logo refresh \param alt Texte sur le alt de l'image \return string Retourne tag img */ function img_refresh($alt = "default") { global $conf,$langs; if ($alt=="default") $alt=$langs->trans("Refresh"); return ''.$alt.''; } /** * \brief Affiche logo dossier * \param alt Texte sur le alt de l'image * \return string Retourne tag img */ function img_folder($alt = "default") { global $conf,$langs; if ($alt=="default") $alt=$langs->trans("Dossier"); return ''.$alt.''; } /** * \brief Affiche logo nouveau fichier * \param alt Texte sur le alt de l'image * \return string Retourne tag img */ function img_file_new($alt = "default") { global $conf,$langs; if ($alt=="default") $alt=$langs->trans("Show"); return ''.$alt.''; } /** \brief Affiche logo pdf \param alt Texte sur le alt de l'image \param $size Taille de l'icone : 3 = 16x16px , 2 = 14x14px \return string Retourne tag img */ function img_pdf($alt = "default",$size=3) { global $conf,$langs; if ($alt=="default") $alt=$langs->trans("Show"); return ''.$alt.''; } /** * \brief Affiche logo + * \param alt Texte sur le alt de l'image * \return string Retourne tag img */ function img_edit_add($alt = "default") { global $conf,$langs; if ($alt=="default") $alt=$langs->trans("Add"); return ''.$alt.''; } /** * \brief Affiche logo - * \param alt Texte sur le alt de l'image * \return string Retourne tag img */ function img_edit_remove($alt = "default") { global $conf,$langs; if ($alt=="default") $alt=$langs->trans("Remove"); return ''.$alt.''; } /** * \brief Affiche logo editer/modifier fiche * \param alt Texte sur le alt de l'image * \param float Si il faut y mettre le style "float: right" * \return string Retourne tag img */ function img_edit($alt = "default", $float=0, $other='') { global $conf,$langs; if ($alt=="default") $alt=$langs->trans("Modify"); $img=''.$alt.'trans("View"); $img=''.$alt.'trans("Delete"); return ''.$alt.''; } /** * \brief Affiche logo help avec curseur "?" * \return string Retourne tag img */ function img_help($usehelpcursor=1,$usealttitle=1) { global $conf,$langs; $s ='theme.'/img/info.png" border="0"'; if ($usealttitle) $s.=' alt="'.$langs->trans("Info").'" title="'.$langs->trans("Info").'"'; $s.='>'; return $s; } /** * \brief Affiche logo info * \param alt Texte sur le alt de l'image * \return string Retourne tag img */ function img_info($alt = "default") { global $conf,$langs; if ($alt=="default") $alt=$langs->trans("Informations"); return ''.$alt.''; } /** * \brief Affiche logo warning * \param alt Texte sur le alt de l'image * \param float Si il faut afficher le style "float: right" * \return string Retourne tag img */ function img_warning($alt = "default",$float=0) { global $conf,$langs; if ($alt=="default") $alt=$langs->trans("Warning"); $img=''.$alt.'trans("Error"); return ''.$alt.''; } /** * \brief Affiche logo telephone * \param alt Texte sur le alt de l'image * \param option Choose of logo * \return string Retourne tag img */ function img_phone($alt = "default",$option=0) { global $conf,$langs; if ($alt=="default") $alt=$langs->trans("Call"); $img='call_out'; if ($option == 1) $img='call'; $img='object_commercial'; return ''.$alt.''; } /** \brief Affiche logo suivant \param alt Texte sur le alt de l'image \return string Retourne tag img */ function img_next($alt = "default") { global $conf,$langs; if ($alt=="default") { $alt=$langs->trans("Next"); } return ''.$alt.''; } /** \brief Affiche logo pr�c�dent \param alt Texte sur le alt de l'image \return string Retourne tag img */ function img_previous($alt = "default") { global $conf,$langs; if ($alt=="default") $alt=$langs->trans("Previous"); return ''.$alt.''; } /** \brief Affiche logo bas \param alt Texte sur le alt de l'image \param selected Affiche version "selected" du logo \return string Retourne tag img */ function img_down($alt = "default", $selected=0) { global $conf,$langs; if ($alt=="default") $alt=$langs->trans("Down"); if ($selected) return ''.$alt.''; else return ''.$alt.''; } /** \brief Affiche logo haut \param alt Texte sur le alt de l'image \param selected Affiche version "selected" du logo \return string Retourne tag img */ function img_up($alt = "default", $selected=0) { global $conf,$langs; if ($alt=="default") $alt=$langs->trans("Up"); if ($selected) return ''.$alt.''; else return ''.$alt.''; } /** \brief Affiche logo gauche \param alt Texte sur le alt de l'image \param selected Affiche version "selected" du logo \return string Retourne tag img */ function img_left($alt = "default", $selected=0) { global $conf,$langs; if ($alt=="default") $alt=$langs->trans("Left"); if ($selected) return ''.$alt.''; else return ''.$alt.''; } /** \brief Affiche logo droite \param alt Texte sur le alt de l'image \param selected Affiche version "selected" du logo \return string Retourne tag img */ function img_right($alt = "default", $selected=0) { global $conf,$langs; if ($alt=="default") $alt=$langs->trans("Right"); if ($selected) return ''.$alt.''; else return ''.$alt.''; } /** \brief Affiche logo tick \param alt Texte sur le alt de l'image \return string Retourne tag img */ function img_tick($alt = "default") { global $conf,$langs; if ($alt=="default") $alt=$langs->trans("Active"); return ''.$alt.''; } /** \brief Affiche le logo tick si allow \param allow Authorise ou non \return string Retourne tag img */ function img_allow($allow) { global $conf,$langs; if ($alt=="default") $alt=$langs->trans("Active"); if ($allow == 1) { return ''.$alt.''; } else { return "-"; } } /** * \brief Show mime picto * \param file Filename * \param alt Alternate text * \return string Return img tag */ function img_mime($file,$alt='') { $mime='other'; if (eregi('\.pdf',$file)) { $mime='pdf'; } if (eregi('\.(html|htm)',$file)) { $mime='html'; } if (eregi('\.txt',$file)) { $mime='other'; } if (eregi('\.php',$file)) { $mime='php'; } if (eregi('\.pl',$file)) { $mime='pl'; } if (eregi('\.js',$file)) { $mime='jscript'; } if (eregi('\.(png|bmp|jpg|jpeg|gif)',$file)) $mime='image'; if (eregi('\.(mp3|ogg|au)',$file)) $mime='audio'; if (eregi('\.(avi|mvw|divx|xvid)',$file)) $mime='video'; if (eregi('\.(zip|rar|gz|tgz|z|cab|bz2)',$file)) $mime='archive'; if (empty($alt)) $alt='Mime type: '.$mime; $mime.='.png'; return ''.$alt.''; } /** * \brief Affiche info admin * \param text Text info * \param infoonimgalt Info is shown on alt of star picto * \return string String with info text */ function info_admin($texte,$infoonimgalt=0) { global $conf,$langs; $s=''; if ($infoonimgalt) { $s.=img_picto($texte,'star'); } else { $s.='
'; $s.=img_picto($langs->trans("InfoAdmin"),'star'); $s.=' '; $s.=$texte; $s.='
'; } return $s; } /** * \brief Check permissions of a user to show a page and an object. * \param user User to check * \param feature Feature to check (in most cases, it's module name) * \param objectid Object ID if we want to check permission on on object (optionnal) * \param dbtablename Table name where object is stored. Not used if objectid is null (optionnel) * \param feature2 Feature to check (second level of permission) * \param dbt_socfield Field name for socid foreign key if not fk_soc. (optionnel) */ function restrictedArea($user, $feature='societe', $objectid=0, $dbtablename='',$feature2='',$dbt_socfield='fk_soc') { global $db; //print "$user->id, $feature, $objectid, $dbtablename, ".$user->rights->societe->contact->lire; // Check read permission from module // TODO Replace "feature" param by permission for reading $readok=1; if ($feature == 'societe') { if (! $user->rights->societe->lire && ! $user->rights->fournisseur->lire) $readok=0; } else if ($feature == 'contact') { if (! $user->rights->societe->contact->lire) $readok=0; } else if ($feature == 'prelevement') { if (! $user->rights->prelevement->bons->lire) $readok=0; } else if ($feature == 'commande_fournisseur') { if (! $user->rights->fournisseur->commande->lire) $readok=0; } else if ($feature == 'cheque') { if (! $user->rights->banque->cheque) $readok=0; } else if (! empty($feature2)) // This should be used for future changes { if (empty($user->rights->$feature->$feature2->lire) && empty($user->rights->$feature->$feature2->read)) $readok=0; } else if (! empty($feature)) // This is for old permissions { if (empty($user->rights->$feature->lire) && empty($user->rights->$feature->read)) $readok=0; } if (! $readok) accessforbidden(); //print "Read access is ok"; // Check write permission from module $createok=1; if ($_GET["action"] == 'create' || $_POST["action"] == 'create') { if ($feature == 'societe') { if (! $user->rights->societe->creer && ! $user->rights->fournisseur->creer) $createok=0; } else if ($feature == 'contact') { if (! $user->rights->societe->contact->creer) $createok=0; } else if ($feature == 'prelevement') { if (! $user->rights->prelevement->bons->creer) $createok=0; } else if ($feature == 'commande_fournisseur') { if (! $user->rights->fournisseur->commande->creer) $createok=0; } else if ($feature == 'banque') { if (! $user->rights->banque->modifier) $createok=0; } else if ($feature == 'cheque') { if (! $user->rights->banque->cheque) $createok=0; } else if (! empty($feature2)) // This should be used for future changes { if (empty($user->rights->$feature->$feature2->creer) && empty($user->rights->$feature->$feature2->write)) $createok=0; } else if (! empty($feature)) // This is for old permissions { if (empty($user->rights->$feature->creer) && empty($user->rights->$feature->write)) $createok=0; } if (! $createok) accessforbidden(); //print "Write access is ok"; } // If we have a particular object to check permissions on if ($objectid) { $sql=''; // Check permission for external users if ($user->societe_id > 0) { if ($feature == 'societe') { if ($user->societe_id <> $objectid) accessforbidden(); } else { // If dbtable not defined, we use same name for table than module name if (!$dbtablename) $dbtablename = $feature; $sql = "SELECT dbt.fk_soc"; $sql.= " FROM ".MAIN_DB_PREFIX.$dbtablename." as dbt"; $sql.= " WHERE dbt.rowid = ".$objectid; $sql.= " AND dbt.fk_soc = ".$user->societe_id; } } // Check permission for internal users that are restricted on their objects else if (! $user->rights->societe->client->voir) { if ($feature == 'societe') { $sql = "SELECT sc.fk_soc"; $sql.= " FROM ".MAIN_DB_PREFIX."societe_commerciaux as sc"; $sql.= " WHERE sc.fk_soc = ".$objectid." AND sc.fk_user = ".$user->id; } else { if (!$dbtablename) $dbtablename = $feature; // Si dbtable non defini, meme nom que le module $sql = "SELECT sc.fk_soc"; $sql.= " FROM ".MAIN_DB_PREFIX.$dbtablename." as dbt"; $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON sc.fk_soc = dbt.".$dbt_socfield; $sql.= " WHERE dbt.rowid = ".$objectid; $sql.= " AND IFNULL(sc.fk_user, ".$user->id.") = ".$user->id; } } //print $sql; if ($sql) { $resql=$db->query($sql); if ($resql) { if ($db->num_rows($resql) == 0) accessforbidden(); } else { dolibarr_syslog("functions.lib::restrictedArea sql=".$sql, LOG_ERR); accessforbidden(); } } } return 1; } /** \brief Affiche message erreur de type acces interdit et arrete le programme \param message Force error message \param printheader Affiche avant le header \remarks L'appel a cette fonction termine le code. */ function accessforbidden($message='',$printheader=1) { global $user, $langs; $langs->load("other"); if ($printheader && function_exists("llxHeader")) llxHeader(); print '
'; if (! $message) print $langs->trans("ErrorForbidden"); else print $message; print '
'; print '
'; if ($user->login) { print $langs->trans("CurrentLogin").': '.$user->login.'
'; print $langs->trans("ErrorForbidden2",$langs->trans("Home"),$langs->trans("Users")); } elseif (! empty($_SERVER["REMOTE_USER"])) { print $langs->trans("CurrentLogin").': '.$_SERVER["REMOTE_USER"]."
"; print $langs->trans("ErrorForbidden2",$langs->trans("Home"),$langs->trans("Users")); } else { print $langs->trans("ErrorForbidden3"); } if (function_exists("llxFooter")) llxFooter(); exit(0); } /** * \brief Affiche message erreur system avec toutes les informations pour faciliter le diagnostic et la remont�e des bugs. * On doit appeler cette fonction quand une erreur technique bloquante est rencontree. * Toutefois, il faut essayer de ne l'appeler qu'au sein de pages php, les classes devant * renvoyer leur erreur par l'intermediaire de leur propriete "error". * \param db Database handler * \param error Chaine erreur ou tableau de chaines erreur complementaires a afficher */ function dolibarr_print_error($db='',$error='') { global $conf,$langs,$argv; $syslog = ''; // Si erreur intervenue avant chargement langue if (! $langs) { require_once(DOL_DOCUMENT_ROOT ."/translate.class.php"); $langs = new Translate("", $conf); } $langs->load("main"); if ($_SERVER['DOCUMENT_ROOT']) // Mode web { print $langs->trans("DolibarrHasDetectedError").".
\n"; print $langs->trans("InformationToHelpDiagnose").":

\n"; print "".$langs->trans("Dolibarr").": ".DOL_VERSION."
\n";; print "".$langs->trans("Date").": ".dolibarr_print_date(time(),'dayhourlog')."
\n";; if (isset($conf->global->MAIN_FEATURES_LEVEL)) print "".$langs->trans("LevelOfFeature").": ".$conf->global->MAIN_FEATURES_LEVEL."
\n";; print "".$langs->trans("Server").": ".$_SERVER["SERVER_SOFTWARE"]."
\n";; print "".$langs->trans("RequestedUrl").": ".$_SERVER["REQUEST_URI"]."
\n";; print "".$langs->trans("Referer").": ".$_SERVER["HTTP_REFERER"]."
\n";; $syslog.="url=".$_SERVER["REQUEST_URI"]; $syslog.=", query_string=".$_SERVER["QUERY_STRING"]; } else // Mode CLI { print '> '.$langs->transnoentities("ErrorInternalErrorDetected").":\n".$argv[0]."\n"; $syslog.="pid=".getmypid(); } if (is_object($db)) { if ($_SERVER['DOCUMENT_ROOT']) // Mode web { print "
\n"; print "".$langs->trans("DatabaseTypeManager").": ".$db->type."
\n"; print "".$langs->trans("RequestLastAccessInError").": ".($db->lastqueryerror()?$db->lastqueryerror():$langs->trans("ErrorNoRequestInError"))."
\n"; print "".$langs->trans("ReturnCodeLastAccessInError").": ".($db->lasterrno()?$db->lasterrno():$langs->trans("ErrorNoRequestInError"))."
\n"; print "".$langs->trans("InformationLastAccessInError").": ".($db->lasterror()?$db->lasterror():$langs->trans("ErrorNoRequestInError"))."
\n"; } else // Mode CLI { print '> '.$langs->transnoentities("DatabaseTypeManager").":\n".$db->type."\n"; print '> '.$langs->transnoentities("RequestLastAccessInError").":\n".($db->lastqueryerror()?$db->lastqueryerror():$langs->trans("ErrorNoRequestInError"))."\n"; print '> '.$langs->transnoentities("ReturnCodeLastAccessInError").":\n".($db->lasterrno()?$db->lasterrno():$langs->trans("ErrorNoRequestInError"))."\n"; print '> '.$langs->transnoentities("InformationLastAccessInError").":\n".($db->lasterror()?$db->lasterror():$langs->trans("ErrorNoRequestInError"))."\n"; } $syslog.=", sql=".$db->lastquery(); $syslog.=", db_error=".$db->lasterror(); } if ($error) { $langs->load("errors"); if (is_array($error)) $errors=$error; else $errors=array($error); foreach($errors as $msg) { $msg=$langs->trans($msg); if ($_SERVER['DOCUMENT_ROOT']) // Mode web { print "".$langs->trans("Message").": ".$msg."
\n" ; } else // Mode CLI { print '> '.$langs->transnoentities("Message").":\n".$msg."\n" ; } $syslog.=", msg=".$msg; } } dolibarr_syslog("Error ".$syslog, LOG_ERR); } /** * \brief Deplacer les fichiers telecharg�s, apres quelques controles divers * \param src_file Source filename * \param dest_file Target filename * \param allowoverwrite Overwrite if exists * \return int >0 if OK, <0 if KO, Name of virus if virus found */ function dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite) { global $conf; $file_name = $dest_file; // If we need to make a virus scan if ($conf->global->MAIN_USE_AVSCAN) { require_once(DOL_DOCUMENT_ROOT.'/lib/security.lib.php'); $malware = dol_avscan_file($src_file); if ($malware) return $malware; } // Security: // On renomme les fichiers avec extention script web car si on a mis le rep // documents dans un rep de la racine web (pas bien), cela permet d'executer // du code a la demande. if (eregi('\.htm|\.html|\.php|\.pl|\.cgi$',$file_name)) { $file_name.= '.noexe'; } // Security: // On interdit fichiers caches, remontees de repertoire ainsi que les pipes dans // les noms de fichiers. if (eregi('^\.',$src_file) || eregi('\.\.',$src_file) || eregi('[<>|]',$src_file)) { dolibarr_syslog("Refused to deliver file ".$src_file); return -1; } // Security: // On interdit fichiers caches, remontees de repertoire ainsi que les pipe dans // les noms de fichiers. if (eregi('^\.',$dest_file) || eregi('\.\.',$dest_file) || eregi('[<>|]',$dest_file)) { dolibarr_syslog("Refused to deliver file ".$dest_file); return -1; } // Check if destination file already exists if (! $allowoverwrite) { if (file_exists($file_name)) { dolibarr_syslog("Functions.lib::dol_move_uploaded_file File ".$file_name." already exists", LOG_WARNING); return -2; } } // Move file $return=move_uploaded_file($src_file, $file_name); if ($return) { if (! empty($conf->global->MAIN_UMASK)) @chmod($file_name, octdec($conf->global->MAIN_UMASK)); dolibarr_syslog("Functions.lib::dol_move_uploaded_file Success to move ".$src_file." to ".$file_name." - Umask=".$conf->global->MAIN_UMASK, LOG_DEBUG); return 1; } else { dolibarr_syslog("Functions.lib::dol_move_uploaded_file Failed to move ".$src_file." to ".$file_name, LOG_ERR); return -3; } } /** * \brief Show title line of an array * \param name libelle champ * \param file url pour clic sur tri * \param field champ de tri * \param begin ("" par defaut) * \param options ("" par defaut) * \param td options de l'attribut td ("" par defaut) * \param sortfield nom du champ sur lequel est effectue le tri du tableau * \param sortorder ordre du tri */ function print_liste_field_titre($name, $file, $field, $begin="", $options="", $td="", $sortfield="", $sortorder="") { global $conf; //print "$name, $file, $field, $begin, $options, $td, $sortfield, $sortorder
\n"; // Le champ de tri est mis en evidence. // Exemple si (sortfield,field)=("nom","xxx.nom") ou (sortfield,field)=("nom","nom") if ($sortfield == $field || $sortfield == ereg_replace("^[^\.]+\.","",$field)) { print ''; } else { print ''; } print $name; // If this is a sort field if ($field) { //print " "; print ''; if (! $sortorder) { print ''.img_down("A-Z",0).''; print ''.img_up("Z-A",0).''; } else { if ($field != $sortfield) { print ''.img_down("A-Z",0).''; print ''.img_up("Z-A",0).''; } else { $sortorder=strtoupper($sortorder); if ($sortorder == 'DESC' ) { print ''.img_down("A-Z",0).''; print ''.img_up("Z-A",1).''; } if ($sortorder == 'ASC' ) { print ''.img_down("A-Z",1).''; print ''.img_up("Z-A",0).''; } } } } print ""; } /** * \brief Affichage d'un titre * \param titre Le titre a afficher */ function print_titre($titre) { print '
'.$titre.'
'; } /** * \brief Affichage d'un titre d'une fiche, align� a gauche * \param titre Le titre a afficher * \param mesg Message suplementaire a afficher a droite * \param picto Icon to use before title (should be a 32x32 transparent png file) * \param pictoisfullpath 1=Icon name is a full absolute url of image */ function print_fiche_titre($titre, $mesg='', $picto='title.gif', $pictoisfullpath=0) { print "\n"; print ''; if ($picto && $titre) print ''; print ''; if (strlen($mesg)) { print ''; } print '
'.img_picto('',$picto, '', $pictoisfullpath).''; print '
'.$titre.'
'; print '
'.$mesg.'
'."\n"; } /** * \brief Print a title with navigation controls for pagination * \param titre Title to show (required) * \param page Numero of page (required) * \param file Url of page (required) * \param options parametres complementaires lien ('' par defaut) * \param sortfield champ de tri ('' par defaut) * \param sortorder ordre de tri ('' par defaut) * \param center chaine du centre ('' par defaut) * \param num number of records found by select with limit+1 * \param totalnboflines Total number of records/lines for all pages (if known) * \param picto Icon to use before title (should be a 32x32 transparent png file) * \param pictoisfullpath 1=Icon name is a full absolute url of image */ function print_barre_liste($titre, $page, $file, $options='', $sortfield='', $sortorder='', $center='', $num=-1, $totalnboflines=0, $picto='title.gif', $pictoisfullpath=0) { global $conf,$langs; if ($num > $conf->liste_limit or $num == -1) { $nextpage = 1; } else { $nextpage = 0; } print ''; $pagelist = ''; // Left if ($page > 0 || $num > $conf->liste_limit) { if ($totalnboflines) { if ($picto && $titre) print ''; print ''; $maxnbofpage=10; $nbpages=ceil($totalnboflines/$conf->liste_limit); $cpt=($page-$maxnbofpage); if ($cpt < 0) { $cpt=0; } $pagelist.=$langs->trans('Page'); if ($cpt>=1) { $pagelist.=' 1'; if ($cpt >= 2) $pagelist.=' ...'; } do { if($cpt==$page) { $pagelist.= ' '.($page+1).''; } else { $pagelist.= ' '.($cpt+1).''; } $cpt++; } while ($cpt < $nbpages && $cpt<=$page+$maxnbofpage); if ($cpt<$nbpages) { if ($cpt<$nbpages-1) $pagelist.= ' ...'; $pagelist.= ' '.$nbpages.''; } } else { if ($picto && $titre) print ''; print ''; } } else { if ($picto && $titre) print ''; print ''; } // Center if ($center) { print ''; } // Right print ''; print '
'.img_picto('',$picto, '', $pictoisfullpath).''; print '
'.$titre.'
'; print '
'.img_picto('',$picto, '', $pictoisfullpath).''; print '
'.$titre.'
'; $pagelist.= $langs->trans('Page').' '.($page+1); print '
'.img_picto('',$picto, '', $pictoisfullpath).'
'.$titre.'
'.$center.''; if ($sortfield) $options .= "&sortfield=".$sortfield; if ($sortorder) $options .= "&sortorder=".$sortorder; // Affichage des fleches de navigation print_fleche_navigation($page,$file,$options,$nextpage,$pagelist); print '
'; } /** * \brief Fonction servant a afficher les fleches de navigation dans les pages de listes * \param page Numero of page * \param file Lien * \param options Autres parametres d'url a propager dans les liens ("" par defaut) * \param nextpage Faut-il une page suivante * \param betweenarraows HTML Content to show between arrows */ function print_fleche_navigation($page,$file,$options='',$nextpage,$betweenarrows='') { global $conf, $langs; if ($page > 0) { print ''.img_previous($langs->trans("Previous")).''; } if ($betweenarrows) print ($page > 0?' ':'').$betweenarrows.($nextpage>0?' ':''); if ($nextpage > 0) { print ''.img_next($langs->trans("Next")).''; } } /** * \brief Effacement d'un fichier * \param file Fichier a effacer ou masque de fichier a effacer * \param boolean true if file deleted, false if error */ function dol_delete_file($file) { $ok=true; foreach (glob($file) as $filename) { $ok=unlink($filename); if ($ok) dolibarr_syslog("Removed file $filename",LOG_DEBUG); else dolibarr_syslog("Failed to remove file $filename",LOG_ERR); } return $ok; } /** \brief Effacement d'un r�pertoire \param file R�pertoire a effacer */ function dol_delete_dir($dir) { return rmdir($dir); } /** \brief Effacement d'un r�pertoire $dir et de son arborescence \param file R�pertoire a effacer \param count Compteur pour comptage nb elements supprim�s \return int Nombre de fichier+rep�rtoires supprim�s */ function dol_delete_dir_recursive($dir,$count=0) { if ($handle = opendir("$dir")) { while (false !== ($item = readdir($handle))) { if ($item != "." && $item != "..") { if (is_dir("$dir/$item")) { $count=dol_delete_dir_recursive("$dir/$item",$count); } else { unlink("$dir/$item"); $count++; //echo " removing $dir/$item
\n"; } } } closedir($handle); rmdir($dir); $count++; //echo "removing $dir
\n"; } //echo "return=".$count; return $count; } /** * \brief Fonction qui retourne un taux de tva formate pour visualisation * \remarks Fonction utilisee dans les pdf et les pages html * \param rate Rate value to format (19.6 19,6 19.6% 19,6%,...) * \param foundpercent Add a percent % sign in output * \param info_bits Miscellanous information on vat * \return string Chaine avec montant formate (19,6 ou 19,6% ou 8.5% *) */ function vatrate($rate,$addpercent=false,$info_bits=0) { // Test for compatibility if (eregi('%',$rate)) { $rate=eregi_replace('%','',$rate); $addpercent=true; } if (eregi('\*',$rate) || eregi(MAIN_LABEL_MENTION_NPR,$rate)) { $rate=eregi_replace('\*','',$rate); $info_bits |= 1; } $ret=price($rate,0,'',0,0).($addpercent?'%':''); if ($info_bits & 1) $ret.=' '.MAIN_LABEL_MENTION_NPR; return $ret; } /** * \brief Fonction qui formate un montant pour visualisation * \remarks Fonction utilisee dans les pdf et les pages html * \param amount Montant a formater * \param html Type de formatage, html ou pas (par defaut) * \param outlangs Objet langs pour formatage text * \param trunc 1=Tronque affichage si trop de decimales,0=Force le non troncage * \param rounding Nbre decimals minimum. * \return string Chaine avec montant formate * \seealso price2num Revert function of price */ function price($amount, $html=0, $outlangs='', $trunc=1, $rounding=2) { global $langs,$conf; $nbdecimal=$rounding; // Output separators by default (french) $dec=','; $thousand=' '; // If $outlangs not forced, we use use language if (! is_object($outlangs)) $outlangs=$langs; if ($outlangs->trans("SeparatorDecimal") != "SeparatorDecimal") $dec=$outlangs->trans("SeparatorDecimal"); if ($outlangs->trans("SeparatorThousand")!= "SeparatorThousand") $thousand=$outlangs->trans("SeparatorThousand"); //print "amount=".$amount." html=".$html." trunc=".$trunc." nbdecimal=".$nbdecimal." dec=".$dec." thousand=".$thousand; //print "amount=".$amount."-"; $amount = ereg_replace(',','.',$amount); // should be useless //print $amount."-"; $datas = split('\.',$amount); $decpart = $datas[1]; $decpart = eregi_replace('0+$','',$decpart); // Supprime les 0 de fin de partie decimale //print "decpart=".$decpart."
"; $end=''; // We increase nbdecimal if there is more decimal than asked (to not loose information) if (strlen($decpart) > $nbdecimal) $nbdecimal=strlen($decpart); // Si on depasse max if ($trunc && $nbdecimal > $conf->global->MAIN_MAX_DECIMALS_SHOWN) { $nbdecimal=$conf->global->MAIN_MAX_DECIMALS_SHOWN; if (eregi('\.\.\.',$conf->global->MAIN_MAX_DECIMALS_SHOWN)) { // Si un affichage est tronque, on montre des ... $end='...'; } } // Format number if ($html) { $output=ereg_replace(' ',' ',number_format($amount, $nbdecimal, $dec, $thousand)); } else { $output=number_format($amount, $nbdecimal, $dec, $thousand); } $output.=$end; return $output; } /** * \brief Fonction qui retourne un numerique conforme SQL, depuis un montant issu d'une saisie * utilisateur. * \remarks Fonction a appeler sur montants saisis avant un insert en base * \param amount Montant a formater * \param rounding 'MU'=Round to Max unit price (MAIN_MAX_DECIMALS_UNIT) * 'MT'=Round to Max for totals with Tax (MAIN_MAX_DECIMALS_TOT) * 'MS'=Round to Max Shown (MAIN_MAX_DECIMALS_SHOWN) * ''=No rounding * \return string Montant au format numerique universel et SQL (Exemple: '99.99999') * \seealso price Fonction inverse de price2num */ function price2num($amount,$rounding='',$alreadysqlnb=-1) { global $langs,$conf; // Round PHP function does not allow number like '1,234.56' nor '1.234,56' nor '1 234,56' // Numbers must be '1234.56' // Decimal delimiter for database SQL request must be '.' $dec=','; $thousand=' '; if ($langs->trans("SeparatorDecimal") != "SeparatorDecimal") $dec=$langs->trans("SeparatorDecimal"); if ($langs->trans("SeparatorThousand")!= "SeparatorThousand") $thousand=$langs->trans("SeparatorThousand"); // Convert value to universal number format (no thousand separator, '.' as decimal separator) if ($alreadysqlnb != 1) // If not a PHP number or unknown, we change format { //print 'ZZ'.$nbofdec.'=>'.$amount.'
'; // Convert amount to format with dolibarr dec and thousand (this is because PHP convert a number // to format defined by LC_NUMERIC after a calculation and we want source format to be like defined by Dolibarr setup. if (is_numeric($amount)) { $nbofdec=max(0,strlen($amount-intval($amount))-2); $amount=number_format($amount,$nbofdec,$dec,$thousand); } //print "QQ".$amount.'
'; // Now make replace (the main goal of function) if ($thousand != ',' && $thousand != '.') $amount=str_replace(',','.',$amount); // To accept 2 notations for french users $amount=str_replace(' ','',$amount); // To avoid spaces $amount=str_replace($thousand,'',$amount); // Replace of thousand before replace of dec to avoid pb if thousand is . $amount=str_replace($dec,'.',$amount); } // Now if rounding required if ($rounding) { $nbofdectoround=''; if ($rounding == 'MU') $nbofdectoround=$conf->global->MAIN_MAX_DECIMALS_UNIT; elseif ($rounding == 'MT') $nbofdectoround=$conf->global->MAIN_MAX_DECIMALS_TOT; elseif ($rounding == 'MS') $nbofdectoround=$conf->global->MAIN_MAX_DECIMALS_SHOWN; elseif ($rounding == '2') $nbofdectoround=2; // For admin info page if (strlen($nbofdectoround)) $amount = round($amount,$nbofdectoround); // $nbofdectoround can be 0. else return 'ErrorBadParameterProvidedToFunction'; //print 'ZZ'.$nbofdec.'-'.$nbofdectoround.'=>'.$amount.'
'; // Convert amount to format with dolibarr dec and thousand (this is because PHP convert a number // to format defined by LC_NUMERIC after a calculation and we want source format to be defined by Dolibarr setup. if (is_numeric($amount)) { $nbofdec=max(0,strlen($amount-intval($amount))-2); $amount=number_format($amount,min($nbofdec,$nbofdectoround),$dec,$thousand); // Convert amount to format with dolibarr dec and thousand } //print "RR".$amount.'
'; // Always make replace because each math function (like round) replace // with local values and we want a number that has a SQL string format x.y if ($thousand != ',' && $thousand != '.') $amount=str_replace(',','.',$amount); // To accept 2 notations for french users $amount=str_replace(' ','',$amount); // To avoid spaces $amount=str_replace($thousand,'',$amount); // Replace of thousand before replace of dec to avoid pb if thousand is . $amount=str_replace($dec,'.',$amount); } return $amount; } /** * \brief Return vat rate of a product in a particular selling country */ function get_product_vat_for_country($idprod, $countrycode) { global $db; $product=new Product($db); $product->fetch($idprod); // \TODO Read rate according to countrycode // For the moment only one rate supported return $product->tva_tx; } /** * \brief Fonction qui renvoie la tva d'une ligne (en fonction du vendeur, acheteur et taux du produit) * \remarks Si vendeur non assujeti a TVA, TVA par d�faut=0. Fin de r�gle. * Si le (pays vendeur = pays acheteur) alors TVA par d�faut=TVA du produit vendu. Fin de r�gle. * Si (vendeur et acheteur dans Communaute europeenne) et (bien vendu = moyen de transports neuf comme auto, bateau, avion) alors TVA par d�faut=0 (La TVA doit �tre pay� par acheteur au centre d'impots de son pays et non au vendeur). Fin de r�gle. * Si (vendeur et acheteur dans Communaute europeenne) et (acheteur = particulier ou entreprise sans num TVA intra) alors TVA par d�faut=TVA du produit vendu. Fin de r�gle * Si (vendeur et acheteur dans Communaute europeenne) et (acheteur = entreprise avec num TVA) intra alors TVA par d�faut=0. Fin de r�gle * Sinon TVA proposee par defaut=0. Fin de regle. * \param societe_vendeuse Objet societe vendeuse * \param societe_acheteuse Objet societe acheteuse * \param taux_produit Taux par defaut du produit vendu (old way to get product vat rate) * \param idprod Id product (new way to get product vat rate) * \return float Taux de tva a appliquer, -1 si ne peut etre d�termin� */ function get_default_tva($societe_vendeuse, $societe_acheteuse, $taux_produit, $idprod=0) { if (!is_object($societe_vendeuse)) return -1; if (!is_object($societe_acheteuse)) return -1; dolibarr_syslog("get_default_tva vendeur_assujeti=".$societe_vendeuse->tva_assuj." pays_vendeur=".$societe_vendeuse->pays_code.", seller in cee=".$societe_vendeuse->isInEEC().", pays_acheteur=".$societe_acheteuse->pays_code.", buyer in cee=".$societe_acheteuse->isInEEC().", taux_produit(deprecated)=".$taux_produit.", idprod=".$idprod); // Si vendeur non assujeti a TVA (tva_assuj vaut 0/1 ou franchise/reel) if (is_numeric($societe_vendeuse->tva_assuj) && ! $societe_vendeuse->tva_assuj) return 0; if (! is_numeric($societe_vendeuse->tva_assuj) && $societe_vendeuse->tva_assuj=='franchise') return 0; // Si le (pays vendeur = pays acheteur) alors la TVA par d�faut=TVA du produit vendu. Fin de r�gle. //if (is_object($societe_acheteuse) && ($societe_vendeuse->pays_id == $societe_acheteuse->pays_id) && ($societe_acheteuse->tva_assuj == 1 || $societe_acheteuse->tva_assuj == 'reel')) // Le test ci-dessus ne devrait pas etre necessaire. Me signaler l'exemple du cas juridique concercn� si le test suivant n'est pas suffisant. if ($societe_vendeuse->pays_id == $societe_acheteuse->pays_id) { if ($idprod) return get_product_vat_for_country($idprod,$societe_vendeuse->pays_code); if (strlen($taux_produit) == 0) return -1; // Si taux produit = '', on ne peut d�terminer taux tva return $taux_produit; } // Si (vendeur et acheteur dans Communaut� europ�enne) et (bien vendu = moyen de transports neuf comme auto, bateau, avion) alors TVA par d�faut=0 (La TVA doit �tre pay� par l'acheteur au centre d'impots de son pays et non au vendeur). Fin de r�gle. // Non g�r� // Si (vendeur et acheteur dans Communaut� europ�enne) et (acheteur = particulier ou entreprise sans num TVA intra) alors TVA par d�faut=TVA du produit vendu. Fin de r�gle if (($societe_vendeuse->isInEEC() && $societe_acheteuse->isInEEC()) && ! $societe_acheteuse->tva_intra) { if ($idprod) return get_product_vat_for_country($idprod,$societe_vendeuse->pays_code); if (strlen($taux_produit) == 0) return -1; // Si taux produit = '', on ne peut d�terminer taux tva return $taux_produit; } // Si (vendeur et acheteur dans Communaut� europ�enne) et (acheteur = entreprise avec num TVA intra) alors TVA par d�faut=0. Fin de r�gle if (($societe_vendeuse->isInEEC() && $societe_acheteuse->isInEEC()) && $societe_acheteuse->tva_intra) { return 0; } // Sinon la TVA propos�e par d�faut=0. Fin de r�gle. // Rem: Cela signifie qu'au moins un des 2 est hors Communaut� europ�enne et que le pays diff�re return 0; } /** \brief Fonction qui renvoie si tva doit etre tva percue r�cup�rable \remarks Si vendeur non assujeti a TVA, TVA par d�faut=0. Fin de r�gle. Si le (pays vendeur = pays acheteur) alors TVA par d�faut=TVA du produit vendu. Fin de r�gle. Si (vendeur et acheteur dans Communaut� europ�enne) et (bien vendu = moyen de transports neuf comme auto, bateau, avion) alors TVA par d�faut=0 (La TVA doit �tre pay� par acheteur au centre d'impots de son pays et non au vendeur). Fin de r�gle. Si (vendeur et acheteur dans Communaut� europ�enne) et (acheteur = particulier ou entreprise sans num TVA intra) alors TVA par d�faut=TVA du produit vendu. Fin de r�gle Si (vendeur et acheteur dans Communaut� europ�enne) et (acheteur = entreprise avec num TVA) intra alors TVA par d�faut=0. Fin de r�gle Sinon TVA propos�e par d�faut=0. Fin de r�gle. \param societe_vendeuse Objet soci�t� vendeuse \param societe_acheteuse Objet soci�t� acheteuse \param taux_produit Taux par defaut du produit vendu \return float 0 or 1 */ function get_default_npr($societe_vendeuse, $societe_acheteuse, $taux_produit) { return 0; } /** \brief Renvoie oui ou non dans la langue choisie \param yesno Variable pour test si oui ou non \param case 1=Yes/No, 0=yes/no \param color 0=texte only, 1=Text is format with a color font style */ function yn($yesno, $case=1, $color=0) { global $langs; $result='unknown'; if ($yesno == 1 || strtolower($yesno) == 'yes' || strtolower($yesno) == 'true') // A mettre avant test sur no a cause du == 0 { $result=($case?$langs->trans("Yes"):$langs->trans("yes")); $class='ok'; } elseif ($yesno == 0 || strtolower($yesno) == 'no' || strtolower($yesno) == 'false') { $result=($case?$langs->trans("No"):$langs->trans("no")); $class='error'; } if ($color) return ''.$result.''; return $result; } /** * \brief Return a path to class a directory according to an id * \remarks Examples: 1->"0/0/1/", 15->"0/1/5/" * \param $num Id to develop * \param $level Level of development (1, 2 or 3 level) */ function get_exdir($num,$level=3) { $num = eregi_replace('[^0-9]','',$num); $num = substr("000".$num, -$level); if ($level == 1) return substr($num,0,1).'/'; if ($level == 2) return substr($num,1,1).'/'.substr($num,0,1).'/'; if ($level == 3) return substr($num,2,1).'/'.substr($num,1,1).'/'.substr($num,0,1).'/'; return ''; } /** * \brief Creation of a directory (recursive) * \param $dir Directory to create * \return int < 0 if KO, >= 0 if OK */ function create_exdir($dir) { global $conf; dolibarr_syslog("functions.lib::create_exdir: dir=".$dir,LOG_INFO); if (@is_dir($dir)) return 0; $nberr=0; $nbcreated=0; $ccdir = ''; $cdir = explode("/",$dir); for ($i = 0 ; $i < sizeof($cdir) ; $i++) { if ($i > 0) $ccdir .= '/'.$cdir[$i]; else $ccdir = $cdir[$i]; if (eregi("^.:$",$ccdir,$regs)) continue; // Si chemin Windows incomplet, on poursuit par rep suivant // Attention, le is_dir() peut echouer bien que le rep existe. // (ex selon config de open_basedir) if ($ccdir) { if (! @is_dir($ccdir)) { dolibarr_syslog("functions.lib::create_exdir: Directory '".$ccdir."' does not exists or is outside open_basedir PHP setting.",LOG_DEBUG); umask(0); $dirmaskdec=octdec('0755'); if (! empty($conf->global->MAIN_UMASK)) $dirmaskdec=octdec($conf->global->MAIN_UMASK); $dirmaskdec |= octdec('0110'); if (! @mkdir($ccdir, $dirmaskdec)) { // Si le is_dir a renvoye une fausse info, alors on passe ici. dolibarr_syslog("functions.lib::create_exdir: Fails to create directory '".$ccdir."' or directory already exists.",LOG_WARNING); $nberr++; } else { dolibarr_syslog("functions.lib::create_exdir: Directory '".$ccdir."' created",LOG_DEBUG); $nberr=0; // On remet a zero car si on arrive ici, cela veut dire que les �checs pr�c�dents peuvent etre ignor�s $nbcreated++; } } else { $nberr=0; // On remet a zero car si on arrive ici, cela veut dire que les �checs pr�c�dents peuvent etre ignor�s } } } return ($nberr ? -$nberr : $nbcreated); } /** * \brief Retourne le picto champ obligatoire * \return string Chaine avec picto obligatoire */ function picto_required() { return '*'; } /** * \brief Clean an url string * \param url Url * \param http 1: keep http, 0: remove also http * \return string CleanUrl */ function clean_url($url,$http=1) { // Fixed by Matelli (see http://matelli.fr/showcases/patchs-dolibarr/fix-cleaning-url.html) // To include the minus sign in a char class, we must not escape it but put it at the end of the class // Also, there's no need of escape a dot sign in a class if (eregi('^(https?:[\\\/]+)?([0-9A-Z.-]+\.[A-Z]{2,4})(:[0-9]+)?',$url,$regs)) { $proto=$regs[1]; $domain=$regs[2]; $port=$regs[3]; //print $url." -> ".$proto." - ".$domain." - ".$port; //$url = dol_string_nospecial(trim($url)); $url = trim($url); // Si http: defini on supprime le http (Si https on ne supprime pas) $newproto=$proto; if ($http==0) { if (eregi('^http:[\\\/]+',$url)) { $url = eregi_replace('^http:[\\\/]+','',$url); $newproto = ''; } } // On passe le nom de domaine en minuscule $url = eregi_replace('^'.$proto.$domain, $newproto.strtolower($domain), $url); return $url; } } /** * \brief Clean a string from all HTML tags and entities * \param StringHtml String to clean * \param removelinefeed Replace also all lines feeds by a space * \return string String cleaned */ function dol_string_nohtmltag($StringHtml,$removelinefeed=1) { $pattern = "<[^>]+>"; $temp = dol_entity_decode($StringHtml); $temp = ereg_replace($pattern,"",$temp); // Supprime aussi les retours if ($removelinefeed) $temp=str_replace("\n"," ",$temp); // et les espaces doubles while(strpos($temp," ")) { $temp = str_replace(" "," ",$temp); } $CleanString = $temp; return $CleanString; } /** * \brief Replace CRLF in string with a HTML BR tag. * \param string2encode String to encode * \param nl2brmode 0=Adding br before \n, 1=Replacing \n by br * \return string String encoded */ function dol_nl2br($stringtoencode,$nl2brmode=0) { if (! $nl2brmode) return nl2br($stringtoencode); else { $ret=ereg_replace("\r","",$stringtoencode); $ret=ereg_replace("\n","
",$ret); return $ret; } } /** * \brief This function is called to encode a string into a HTML string * \param stringtoencode String to encode * \param nl2brmode 0=Adding br before \n, 1=Replacing \n by br (for use with FPDF writeHTMLCell function for example) * \remarks For PDF usage, you can show text by 2 ways: * - writeHTMLCell -> param must be encoded into HTML. * - MultiCell -> param must not be encoded into HTML. * Because writeHTMLCell convert also \n into
, if function * is used to build PDF, nl2brmode must be 1. */ function dol_htmlentitiesbr($stringtoencode,$nl2brmode=0,$pagecodefrom='UTF-8') { if (dol_textishtml($stringtoencode)) { // Replace "
" by "
". It's same and avoid pb with FPDF. $stringtoencode=eregi_replace('",$ret); $ret=eregi_replace('|'; if ($ordchar < 32 && $ordchar != 13 && $ordchar != 10) { $ok=0; break; } if ($ordchar > 126 && $ordchar < 160) { $ok=0; break; } } return $ok; } /** * \brief Return nb of lines of a text * \param s String to check * \param maxchar Not yet used * \return int 0 if bad iso, 1 if good iso */ function dol_nboflines($s,$maxchar=0) { $arraystring=split("\n",$s); $nb=sizeof($arraystring); return $nb; } /** * \brief Fonction retournant le nombre de lignes dans un texte formate * \param texte Texte * \param maxlinesize Largeur de ligne en caracteres(ou 0 si pas de limite - defaut) * \return nblines Nombre de lignes */ function num_lines($texte,$maxlinesize=0) { $repTable = array("\t" => " ", "\n" => "
", "\r" => " ", "\0" => " ", "\x0B" => " "); $texte = strtr($texte, $repTable); $pattern = '/(<[^>]+>)/Uu'; $a = preg_split($pattern, $texte, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); $nblines = ((count($a)+1)/2); // count possible auto line breaks if($maxlinesize) { foreach ($a as $line) { if (strlen($line)>$maxlinesize) { //$line_dec = html_entity_decode(strip_tags($line)); $line_dec = html_entity_decode($line); if(strlen($line_dec)>$maxlinesize) { $line_dec=wordwrap($line_dec,$maxlinesize,'\n',true); $nblines+=substr_count($line_dec,'\n'); } } } } return $nblines; } /** * \brief Fonction simple identique a microtime de PHP 5 mais compatible PHP 4 * \return float Time en millisecondes avec decimal pour microsecondes */ function dol_microtime_float() { list($usec, $sec) = explode(" ", microtime()); return ((float)$usec + (float)$sec); } /* * \brief Return if a text is a html content * \param msg Content to check * \param option 0=Full detection, 1=Fast check * \return boolean true/false */ function dol_textishtml($msg,$option=0) { if ($option == 1) { if (eregi('',$msg)) return true; elseif (eregi('',$msg)) return true; elseif (eregi('&[A-Z0-9]{1,6};',$msg)) return true; return false; } } /** * \brief Effectue les substitutions des mots cl�s par les donn�es en fonction du tableau * \param chaine Chaine dans laquelle faire les substitutions * \param substitutionarray Tableau cl� substitution => valeur a mettre * \return string Chaine avec les substitutions effectu�es */ function make_substitutions($chaine,$substitutionarray) { foreach ($substitutionarray as $key => $value) { $chaine=ereg_replace($key,$value,$chaine); } return $chaine; } /** * \brief Format output for start and end date * \param date_start Start date * \param date_end End date * \param format Output format * \remarks Updated by Matelli : added format paramter * \remarks See http://matelli.fr/showcases/patchs-dolibarr/update-date-range-format.html for details */ function print_date_range($date_start,$date_end,$format = '',$outputlangs='') { global $langs; if (! is_object($outputlangs)) $outputlangs=$langs; if ($date_start && $date_end) { print ' ('.$langs->trans('DateFromTo',dolibarr_print_date($date_start, $format, false, $outputlangs),dolibarr_print_date($date_end, $format, false, $outputlangs)).')'; } if ($date_start && ! $date_end) { print ' ('.$langs->trans('DateFrom',dolibarr_print_date($date_start, $format, false, $outputlangs)).')'; } if (! $date_start && $date_end) { print ' ('.$langs->trans('DateUntil',dolibarr_print_date($date_end, $format, false, $outputlangs)).')'; } } /** * \brief Retourne un tableau des mois ou le mois selectionne * \param selected Mois a selectionner ou -1 * \return string or array Month string or array if selected < 0 */ function monthArrayOrSelected($selected=0) { global $langs; $langs->load("main"); $month = array (1 => $langs->trans("January"), 2 => $langs->trans("February"), 3 => $langs->trans("March"), 4 => $langs->trans("April"), 5 => $langs->trans("May"), 6 => $langs->trans("June"), 7 => $langs->trans("July"), 8 => $langs->trans("August"), 9 => $langs->trans("September"), 10 => $langs->trans("October"), 11 => $langs->trans("November"), 12 => $langs->trans("December") ); if ($selected >=0) { $return=''; foreach ($month as $key => $val) { if ($selected == $key) { $return = $val; } } return $return; } else { return $month; } } /** * \brief Returns formated reduction * \param reduction Reduction percentage * \return string Formated reduction */ function dolibarr_print_reduction($reduction=0) { global $langs; $langs->load("main"); $string = ''; if ($reduction == 100) { $string = $langs->trans("Offered"); } else { $string = $reduction.'%'; } return $string; } /** * \brief Returns formated reduction * \param reduction Reduction percentage * \return int Return number of error messages shown */ function dol_htmloutput_errors($mesgstring='',$mesgarray='') { global $langs; $ret = 0; $langs->load("errors"); if (is_array($mesgarray) && sizeof($mesgarray)) { print '
'; foreach($mesgarray as $message) { $ret++; print $langs->trans($message)."
\n"; } print '
'; } if ($mesgstring) { $ret++; print '
'; print $mesgstring; print '
'; } return $ret; } /** * \brief This function output memory used by PHP and exit everything. Used for debugging purpose. */ function stopwithmem() { print memory_get_usage(); llxFooter(); exit; } /** * \brief Advanced sort array by second index function, which produces * ascending (default) or descending output and uses optionally * natural case insensitive sorting (which can be optionally case * sensitive as well). */ function dol_sort_array($array, $index, $order='asc', $natsort, $case_sensitive) { // Clean parameters $order=strtolower($order); if (is_array($array) && count($array)>0) { foreach(array_keys($array) as $key) $temp[$key]=$array[$key][$index]; if (!$natsort) ($order=='asc') ? asort($temp) : arsort($temp); else { ($case_sensitive) ? natsort($temp) : natcasesort($temp); if($order!='asc') $temp=array_reverse($temp,TRUE); } foreach(array_keys($temp) as $key) (is_numeric($key))? $sorted[]=$array[$key] : $sorted[$key]=$array[$key]; return $sorted; } return $array; } /** * \brief Check if a string is in UTF8 * \param $Str String to check * \return boolean True if string is UTF8 or ISO compatible with UTF8, False if not (ISO with special char or Binary) */ function utf8_check($Str) { for ($i=0; $i