PageRenderTime 92ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/htdocs/core/lib/functions.lib.php

https://bitbucket.org/speedealing/speedealing
PHP | 4174 lines | 4010 code | 26 blank | 138 comment | 55 complexity | 3e9cd8b513b776388c29c401933f3b89 MD5 | raw file
Possible License(s): LGPL-3.0, LGPL-2.1, GPL-3.0, MIT
  1. <?php
  2. /* Copyright (C) 2000-2007 Rodolphe Quiedeville <rodolphe@quiedeville.org>
  3. * Copyright (C) 2003 Jean-Louis Bergamo <jlb@j1b.org>
  4. * Copyright (C) 2004-2012 Laurent Destailleur <eldy@users.sourceforge.net>
  5. * Copyright (C) 2004 Sebastien Di Cintio <sdicintio@ressource-toi.org>
  6. * Copyright (C) 2004 Benoit Mortier <benoit.mortier@opensides.be>
  7. * Copyright (C) 2004 Christophe Combelles <ccomb@free.fr>
  8. * Copyright (C) 2005-2013 Regis Houssin <regis.houssin@capnetworks.com>
  9. * Copyright (C) 2008 Raphael Bertrand <raphael.bertrand@resultic.fr>
  10. * Copyright (C) 2010-2011 Juanjo Menent <jmenent@2byte.es>
  11. *
  12. * This program is free software; you can redistribute it and/or modify
  13. * it under the terms of the GNU General Public License as published by
  14. * the Free Software Foundation; either version 3 of the License, or
  15. * (at your option) any later version.
  16. *
  17. * This program is distributed in the hope that it will be useful,
  18. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20. * GNU General Public License for more details.
  21. *
  22. * You should have received a copy of the GNU General Public License
  23. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  24. * or see http://www.gnu.org/
  25. */
  26. /**
  27. * \file htdocs/core/lib/functions.lib.php
  28. * \brief A set of functions for Dolibarr
  29. * This file contains all frequently used functions.
  30. */
  31. if (!function_exists('json_encode')) {
  32. include_once DOL_DOCUMENT_ROOT . '/core/lib/json.lib.php';
  33. }
  34. /**
  35. * Function to return value of a static property when class
  36. * name is dynamically defined (not hard coded).
  37. * This is because $myclass::$myvar works from PHP 5.3.0+ only
  38. *
  39. * @param string $class Class name
  40. * @param string $member Name of property
  41. * @return string Return value of static property.
  42. */
  43. function getStaticMember($class, $member) {
  44. if (is_object($class))
  45. $class = get_class($class);
  46. $classObj = new ReflectionClass($class);
  47. $result = null;
  48. foreach ($classObj->getStaticProperties() as $prop => $value) {
  49. if ($prop == $member) {
  50. $result = $value;
  51. break;
  52. }
  53. }
  54. return $result;
  55. }
  56. /**
  57. * Return a DoliDB instance (database handler).
  58. *
  59. * @param string $type Type of database (mysql, pgsql...)
  60. * @param string $host Address of database server
  61. * @param string $user Nom de l'utilisateur autorise
  62. * @param string $pass Mot de passe
  63. * @param string $name Nom de la database
  64. * @param int $port Port of database server
  65. * @return DoliDB A DoliDB instance
  66. */
  67. function getDoliDBInstance($type, $host, $user, $pass, $name, $port) {
  68. require_once DOL_DOCUMENT_ROOT . "/core/db/" . $type . '.class.php';
  69. $class = 'DoliDB' . ucfirst($type);
  70. $dolidb = new $class($type, $host, $user, $pass, $name, $port);
  71. return $dolidb;
  72. }
  73. /**
  74. * Get entity to use
  75. *
  76. * @param string $element Current element
  77. * @param int $shared 1=Return shared entities
  78. * @return mixed Entity id(s) to use
  79. */
  80. function getEntity($element = false, $shared = false) {
  81. global $conf, $mc;
  82. if (is_object($mc)) {
  83. return $mc->getEntity($element, $shared);
  84. } else {
  85. $out = '';
  86. $addzero = array('user', 'usergroup');
  87. if (in_array($element, $addzero))
  88. $out.= '0,';
  89. $out.= $conf->entity;
  90. return $out;
  91. }
  92. }
  93. /**
  94. * Return information about user browser
  95. *
  96. * @return array Array of information ('browsername'=>,'browseros'=>,'phone'=>,'browserfirefox'=>)
  97. */
  98. function getBrowserInfo() {
  99. $name = 'unknown';
  100. $version = '';
  101. $os = 'unknown';
  102. $phone = '';
  103. // If phone/smartphone, we set phone os name.
  104. if (preg_match('/android/i', $_SERVER["HTTP_USER_AGENT"])) {
  105. $os = $phone = 'android';
  106. } elseif (preg_match('/blackberry/i', $_SERVER["HTTP_USER_AGENT"])) {
  107. $os = $phone = 'blackberry';
  108. } elseif (preg_match('/iphone/i', $_SERVER["HTTP_USER_AGENT"])) {
  109. $os = 'ios';
  110. $phone = 'iphone';
  111. } elseif (preg_match('/ipod/i', $_SERVER["HTTP_USER_AGENT"])) {
  112. $os = 'ios';
  113. $phone = 'iphone';
  114. } elseif (preg_match('/palm/i', $_SERVER["HTTP_USER_AGENT"])) {
  115. $os = $phone = 'palm';
  116. } elseif (preg_match('/symbian/i', $_SERVER["HTTP_USER_AGENT"])) {
  117. $os = 'symbian';
  118. $phone = 'unknown';
  119. } elseif (preg_match('/webos/i', $_SERVER["HTTP_USER_AGENT"])) {
  120. $os = 'webos';
  121. $phone = 'unknown';
  122. } elseif (preg_match('/maemo/i', $_SERVER["HTTP_USER_AGENT"])) {
  123. $os = 'maemo';
  124. $phone = 'unknown';
  125. }
  126. // MS products at end
  127. elseif (preg_match('/iemobile/i', $_SERVER["HTTP_USER_AGENT"])) {
  128. $os = 'windows';
  129. $phone = 'unkown';
  130. } elseif (preg_match('/windows ce/i', $_SERVER["HTTP_USER_AGENT"])) {
  131. $os = 'windows';
  132. $phone = 'unkown';
  133. }
  134. // Name
  135. if (preg_match('/firefox(\/|\s)([\d\.]*)/i', $_SERVER["HTTP_USER_AGENT"], $reg)) {
  136. $name = 'firefox';
  137. $version = $reg[2];
  138. } elseif (preg_match('/chrome(\/|\s)([\d\.]+)/i', $_SERVER["HTTP_USER_AGENT"], $reg)) {
  139. $name = 'chrome';
  140. $version = $reg[2];
  141. } // we can have 'chrome (Mozilla...) chrome x.y' in one string
  142. elseif (preg_match('/chrome/i', $_SERVER["HTTP_USER_AGENT"], $reg)) {
  143. $name = 'chrome';
  144. } elseif (preg_match('/iceweasel/i', $_SERVER["HTTP_USER_AGENT"])) {
  145. $name = 'iceweasel';
  146. $version = $reg[2];
  147. } elseif (preg_match('/epiphany/i', $_SERVER["HTTP_USER_AGENT"])) {
  148. $name = 'epiphany';
  149. $version = $reg[2];
  150. } elseif ((empty($phone) || preg_match('/iphone/i', $_SERVER["HTTP_USER_AGENT"])) && preg_match('/safari(\/|\s)([\d\.]*)/i', $_SERVER["HTTP_USER_AGENT"], $reg)) {
  151. $name = 'safari';
  152. $version = $reg[2];
  153. } // Safari is often present in string for mobile but its not.
  154. elseif (preg_match('/opera(\/|\s)([\d\.]*)/i', $_SERVER["HTTP_USER_AGENT"], $reg)) {
  155. $name = 'opera';
  156. $version = $reg[2];
  157. } elseif (preg_match('/msie(\/|\s)([\d\.]*)/i', $_SERVER["HTTP_USER_AGENT"], $reg)) {
  158. $name = 'ie';
  159. $version = $reg[2];
  160. } // MS products at end
  161. // Other
  162. $firefox = 0;
  163. if (in_array($name, array('firefox', 'iceweasel')))
  164. $firefox = 1;
  165. return array('browsername' => $name, 'browserversion' => $version, 'browseros' => $os, 'phone' => $phone, 'browserfirefox' => $firefox);
  166. }
  167. /**
  168. * Function called at end of web php process
  169. *
  170. * @return void
  171. */
  172. function dol_shutdown() {
  173. global $conf, $user, $langs, $db;
  174. $disconnectdone = false;
  175. $depth = 0;
  176. if (is_object($db) && !empty($db->connected)) {
  177. $depth = $db->transaction_opened;
  178. $disconnectdone = $db->close();
  179. }
  180. dol_syslog("--- End access to " . $_SERVER["PHP_SELF"] . ($disconnectdone ? ' (Warn: db disconnection forced, transaction depth was ' . $depth . ')' : ''), ($disconnectdone ? LOG_WARNING : LOG_DEBUG));
  181. }
  182. /**
  183. * Return value of a param into GET or POST supervariable
  184. *
  185. * @param string $paramname Name of parameter to found
  186. * @param string $check Type of check (''=no check, 'int'=check it's numeric, 'alpha'=check it's alpha only, 'array'=check it's array)
  187. * @param int $method Type of method (0 = get then post, 1 = only get, 2 = only post, 3 = post then get)
  188. * @return string Value found or '' if check fails
  189. */
  190. function GETPOST($paramname, $check = '', $method = 0) {
  191. if (empty($method))
  192. $out = isset($_GET[$paramname]) ? $_GET[$paramname] : (isset($_POST[$paramname]) ? $_POST[$paramname] : '');
  193. elseif ($method == 1)
  194. $out = isset($_GET[$paramname]) ? $_GET[$paramname] : '';
  195. elseif ($method == 2)
  196. $out = isset($_POST[$paramname]) ? $_POST[$paramname] : '';
  197. elseif ($method == 3)
  198. $out = isset($_POST[$paramname]) ? $_POST[$paramname] : (isset($_GET[$paramname]) ? $_GET[$paramname] : '');
  199. else
  200. return 'BadParameter';
  201. if (!empty($check)) {
  202. // Check if numeric
  203. if ($check == 'int' && !preg_match('/^[-\.,0-9]+$/i', $out)) {
  204. $out = trim($out);
  205. $out = '';
  206. }
  207. // Check if alpha
  208. elseif ($check == 'alpha') {
  209. $out = trim($out);
  210. // '"' is dangerous because param in url can close the href= or src= and add javascript functions.
  211. // '../' is dangerous because it allows dir transversals
  212. if (preg_match('/"/', $out))
  213. $out = '';
  214. else if (preg_match('/\.\.\//', $out))
  215. $out = '';
  216. }
  217. elseif ($check == 'array') {
  218. if (!is_array($out) || empty($out))
  219. $out = array();
  220. }
  221. }
  222. return $out;
  223. }
  224. /**
  225. * Return a prefix to use for this Dolibarr instance for session or cookie names.
  226. * This prefix is unique for instance and avoid conflict between multi-instances,
  227. * even when having two instances with one root dir or two instances in virtual servers
  228. *
  229. * @return string A calculated prefix
  230. */
  231. function dol_getprefix() {
  232. return dol_hash($_SERVER["SERVER_NAME"] . $_SERVER["HTTP_HOST"] . $_SERVER["DOCUMENT_ROOT"] . DOL_DOCUMENT_ROOT . DOL_URL_ROOT);
  233. }
  234. /**
  235. * Make an include_once using default root and alternate root if it fails.
  236. * WARNING: In most cases, you should not use this function:
  237. * To link to a core file, use include(DOL_DOCUMENT_ROOT.'/pathtofile')
  238. * To link to a module file from a module file, use include './mymodulefile';
  239. * To link to a module file from a core file, then this function can be used
  240. *
  241. * @param string $relpath Relative path to file (Ie: mydir/myfile, ../myfile, ...)
  242. * @param string $classname Class name
  243. * @return int false if include fails.
  244. */
  245. function dol_include_once($relpath, $classname = '') {
  246. global $conf, $langs, $user, $mysoc; // Other global var must be retreived with $GLOBALS['var']
  247. if (!empty($classname)) {
  248. if (!class_exists($classname))
  249. return @include dol_buildpath($relpath);
  250. }
  251. else
  252. return @include_once dol_buildpath($relpath);
  253. }
  254. /**
  255. * Return path of url or filesystem. Return default_root or alternate root if file_exist fails
  256. *
  257. * @param string $path Relative path to file (if mode=0, ie: mydir/myfile, ../myfile, ...) or relative url (if mode=1).
  258. * @param int $type 0=Used for a Filesystem path, 1=Used for an URL path (output relative), 2=Used for an URL path (output full path)
  259. * @return string Full filsystem path (if mode=0), Full url path (if mode=1)
  260. */
  261. function dol_buildpath($path, $type = 0) {
  262. if (empty($type)) { // For a filesystem path
  263. $res = DOL_DOCUMENT_ROOT . $path; // Standard value
  264. if (defined('DOL_DOCUMENT_ROOT_ALT') && DOL_DOCUMENT_ROOT_ALT) { // We check only if alternate feature is used
  265. if (!file_exists(DOL_DOCUMENT_ROOT . $path))
  266. $res = DOL_DOCUMENT_ROOT_ALT . $path;
  267. }
  268. }
  269. else { // For an url path
  270. // We try to get local path of file on filesystem from url
  271. // Note that trying to know if a file on disk exist by forging path on disk from url
  272. // works only for some web server and some setup. This is bugged when
  273. // using proxy, rewriting, virtual path, etc...
  274. if ($type == 1) {
  275. $res = DOL_URL_ROOT . $path; // Standard value
  276. if (defined('DOL_URL_ROOT_ALT') && DOL_URL_ROOT_ALT) { // We check only if alternate feature is used
  277. preg_match('/^([^\?]+(\.css\.php|\.css|\.js\.php|\.js|\.png|\.jpg|\.php)?)/i', $path, $regs); // Take part before '?'
  278. if (!empty($regs[1])) {
  279. if (!file_exists(DOL_DOCUMENT_ROOT . $regs[1]))
  280. $res = DOL_URL_ROOT_ALT . $path;
  281. }
  282. }
  283. }
  284. else if ($type == 2) {
  285. $res = DOL_MAIN_URL_ROOT . $path; // Standard value
  286. if (defined('DOL_URL_ROOT_ALT') && DOL_URL_ROOT_ALT) { // We check only if alternate feature is used
  287. preg_match('/^([^\?]+(\.css\.php|\.css|\.js\.php|\.js|\.png|\.jpg|\.php)?)/i', $path, $regs); // Take part before '?'
  288. if (!empty($regs[1])) {
  289. if (!file_exists(DOL_DOCUMENT_ROOT . $regs[1]))
  290. $res = DOL_MAIN_URL_ROOT_ALT . $path;
  291. }
  292. }
  293. }
  294. }
  295. return $res;
  296. }
  297. /**
  298. * Create a clone of instance of object (new instance with same properties)
  299. * This function works for both PHP4 and PHP5
  300. *
  301. * @param object $object Object to clone
  302. * @return object Object clone
  303. */
  304. function dol_clone($object) {
  305. dol_syslog("Functions.lib::dol_clone Clone object");
  306. // We create dynamically a clone function, making a =
  307. if (version_compare(phpversion(), '5.0') < 0 && !function_exists('clone')) {
  308. eval('function clone($object){return($object);}');
  309. }
  310. $myclone = clone($object);
  311. return $myclone;
  312. }
  313. /**
  314. * Optimize a size for some browsers (phone, smarphone, ...)
  315. *
  316. * @param int $size Size we want
  317. * @param string $type Type of optimizing:
  318. * '' = function used to define a size for truncation
  319. * 'width' = function is used to define a width
  320. * @return int New size after optimizing
  321. */
  322. function dol_size($size, $type = '') {
  323. global $conf;
  324. if (empty($conf->browser->phone))
  325. return $size;
  326. if ($type == 'width' && $size > 250)
  327. return 250;
  328. else
  329. return 10;
  330. }
  331. /**
  332. * Clean a string to use it as a file name
  333. *
  334. * @param string $str String to clean
  335. * @param string $newstr String to replace bad chars with
  336. * @param string $unaccent 1=Remove also accent (default), 0 do not remove them
  337. * @return string String cleaned (a-zA-Z_)
  338. *
  339. * @see dol_string_nospecial, dol_string_unaccent
  340. */
  341. function dol_sanitizeFileName($str, $newstr = '_', $unaccent = 1) {
  342. $filesystem_forbidden_chars = array('<', '>', ':', '/', '\\', '?', '*', '|', '"');
  343. return dol_string_nospecial($unaccent ? dol_string_unaccent($str) : $str, $newstr, $filesystem_forbidden_chars);
  344. }
  345. /**
  346. * Clean a string from all accent characters to be used as ref, login or by dol_sanitizeFileName
  347. *
  348. * @param string $str String to clean
  349. * @return string Cleaned string
  350. *
  351. * @see dol_sanitizeFilename, dol_string_nospecial
  352. */
  353. function dol_string_unaccent($str) {
  354. if (utf8_check($str)) {
  355. $string = rawurlencode($str);
  356. $replacements = array(
  357. '%C3%80' => 'A', '%C3%81' => 'A',
  358. '%C3%88' => 'E', '%C3%89' => 'E',
  359. '%C3%8C' => 'I', '%C3%8D' => 'I',
  360. '%C3%92' => 'O', '%C3%93' => 'O',
  361. '%C3%99' => 'U', '%C3%9A' => 'U',
  362. '%C3%A0' => 'a', '%C3%A1' => 'a', '%C3%A2' => 'a',
  363. '%C3%A8' => 'e', '%C3%A9' => 'e', '%C3%AA' => 'e', '%C3%AB' => 'e',
  364. '%C3%AC' => 'i', '%C3%AD' => 'i', '%C3%AE' => 'i',
  365. '%C3%B2' => 'o', '%C3%B3' => 'o',
  366. '%C3%B9' => 'u', '%C3%BA' => 'u'
  367. );
  368. $string = strtr($string, $replacements);
  369. return rawurldecode($string);
  370. } else {
  371. $string = strtr(
  372. $str, "\xC0\xC1\xC2\xC3\xC5\xC7
  373. \xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF\xD0\xD1
  374. \xD2\xD3\xD4\xD5\xD8\xD9\xDA\xDB\xDD
  375. \xE0\xE1\xE2\xE3\xE5\xE7\xE8\xE9\xEA\xEB
  376. \xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4\xF5\xF8
  377. \xF9\xFA\xFB\xFD\xFF", "AAAAAC
  378. EEEEIIIIDN
  379. OOOOOUUUY
  380. aaaaaceeee
  381. iiiidnooooo
  382. uuuyy"
  383. );
  384. $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"));
  385. return $string;
  386. }
  387. }
  388. /**
  389. * Clean a string from all punctuation characters to use it as a ref or login
  390. *
  391. * @param string $str String to clean
  392. * @param string $newstr String to replace forbidden chars with
  393. * @param array $badchars List of forbidden characters
  394. * @return string Cleaned string
  395. *
  396. * @see dol_sanitizeFilename, dol_string_unaccent
  397. */
  398. function dol_string_nospecial($str, $newstr = '_', $badchars = '') {
  399. $forbidden_chars_to_replace = array(" ", "'", "/", "\\", ":", "*", "?", "\"", "<", ">", "|", "[", "]", ",", ";", "=");
  400. $forbidden_chars_to_remove = array();
  401. if (is_array($badchars))
  402. $forbidden_chars_to_replace = $badchars;
  403. //$forbidden_chars_to_remove=array("(",")");
  404. return str_replace($forbidden_chars_to_replace, $newstr, str_replace($forbidden_chars_to_remove, "", $str));
  405. }
  406. /**
  407. * Returns text escaped for inclusion into javascript code
  408. *
  409. * @param string $stringtoescape String to escape
  410. * @return string Escaped string
  411. */
  412. function dol_escape_js($stringtoescape) {
  413. // escape quotes and backslashes, newlines, etc.
  414. $substitjs = array("&#039;" => "\\'", '\\' => '\\\\', "'" => "\\'", '"' => "\\'", "\r" => '\\r', "\n" => '\\n', '</' => '<\/');
  415. return strtr($stringtoescape, $substitjs);
  416. }
  417. /**
  418. * Returns text escaped for inclusion in HTML alt or title tags
  419. *
  420. * @param string $stringtoescape String to escape
  421. * @param int $keepb Do not clean b tags
  422. * @return string Escaped string
  423. */
  424. function dol_escape_htmltag($stringtoescape, $keepb = 0) {
  425. // escape quotes and backslashes, newlines, etc.
  426. $tmp = dol_html_entity_decode($stringtoescape, ENT_COMPAT, 'UTF-8');
  427. if ($keepb)
  428. $tmp = strtr($tmp, array("\r" => '\\r', "\n" => '\\n'));
  429. else
  430. $tmp = strtr($tmp, array("\r" => '\\r', "\n" => '\\n', "<b>" => '', '</b>' => ''));
  431. return dol_htmlentities($tmp, ENT_COMPAT, 'UTF-8');
  432. }
  433. /**
  434. * Write log message into outputs. Possible outputs can be:
  435. * A file if SYSLOG_FILE_ON defined: file name is then defined by SYSLOG_FILE
  436. * Syslog if SYSLOG_SYSLOG_ON defined: facility is then defined by SYSLOG_FACILITY
  437. * Warning, syslog functions are bugged on Windows, generating memory protection faults. To solve
  438. * this, use logging to files instead of syslog (see setup of module).
  439. * Note: If SYSLOG_FILE_NO_ERROR defined, we never output any error message when writing to log fails.
  440. * Note: You can get log message into html sources by adding parameter &logtohtml=1 (constant MAIN_LOGTOHTML must be set)
  441. * This function works only if syslog module is enabled.
  442. * This must not use any call to other function calling dol_syslog (avoid infinite loop).
  443. *
  444. * @param string $message Line to log. Ne doit pas etre traduit si level = LOG_ERR
  445. * @param int $level Log level
  446. * On Windows LOG_ERR=4, LOG_WARNING=5, LOG_NOTICE=LOG_INFO=6, LOG_DEBUG=6 si define_syslog_variables ou PHP 5.3+, 7 si dolibarr
  447. * On Linux LOG_ERR=3, LOG_WARNING=4, LOG_INFO=6, LOG_DEBUG=7
  448. * @return void
  449. * @deprecated
  450. */
  451. function dol_syslog($message, $level = LOG_INFO) {
  452. // nothing
  453. }
  454. /**
  455. * Show tab header of a card
  456. *
  457. * @param array $links Array of tabs
  458. * @param string $active Active tab name (document', 'info', 'ldap', ....)
  459. * @param string $title Title
  460. * @param int $notab 0=Add tab header, 1=no tab header
  461. * @param string $picto Add a picto on tab title
  462. * @return void
  463. */
  464. function dol_fiche_head($links = array(), $active = '0', $title = '', $notab = 0, $picto = '') {
  465. print dol_get_fiche_head($links, $active, $title, $notab, $picto);
  466. }
  467. /**
  468. * Show tab header of a card
  469. *
  470. * @param array $links Array of tabs
  471. * @param int $active Active tab name
  472. * @param string $title Title
  473. * @param int $notab 0=Add tab header, 1=no tab header
  474. * @param string $picto Add a picto on tab title
  475. * @return void
  476. */
  477. function dol_get_fiche_head($links = array(), $active = '0', $title = '', $notab = 0, $picto = '') {
  478. $out = "\n" . '<div>' . "\n";
  479. // Define max of key (max may be higher than sizeof because of hole due to module disabling some tabs).
  480. $maxkey = -1;
  481. if (is_array($links) && !empty($links)) {
  482. $keys = array_keys($links);
  483. if (count($keys))
  484. $maxkey = max($keys);
  485. }
  486. // Show tabs
  487. for ($i = 0; $i <= $maxkey; $i++) {
  488. if (isset($links[$i][2]) && $links[$i][2] == 'image') {
  489. if (!empty($links[$i][0])) {
  490. $out.='<a class="tabimage" href="' . $links[$i][0] . '">' . $links[$i][1] . '</a>' . "\n";
  491. } else {
  492. $out.='<span class="tabspan">' . $links[$i][1] . '</span>' . "\n";
  493. }
  494. } else if (!empty($links[$i][1])) {
  495. //print "x $i $active ".$links[$i][2]." z";
  496. if ((is_numeric($active) && $i == $active) || (!is_numeric($active) && $active == $links[$i][2])) {
  497. $out.='<a id="active" class="tab" href="' . $links[$i][0] . '">' . $links[$i][1] . '</a>' . "\n";
  498. } else {
  499. $out.='<a id="' . $links[$i][2] . '" class="tab" href="' . $links[$i][0] . '">' . $links[$i][1] . '</a>' . "\n";
  500. }
  501. }
  502. }
  503. $out.="</div>\n";
  504. if (!$notab)
  505. $out.="\n" . '<div class="tabBar">' . "\n";
  506. return $out;
  507. }
  508. /**
  509. * Show tab footer of a card
  510. *
  511. * @param int $notab 0=Add tab footer, 1=no tab footer
  512. * @return void
  513. */
  514. function dol_fiche_end($notab = 0) {
  515. print dol_get_fiche_end($notab);
  516. }
  517. /**
  518. * Return tab footer of a card
  519. *
  520. * @param int $notab 0=Add tab footer, 1=no tab footer
  521. * @return void
  522. */
  523. function dol_get_fiche_end($notab = 0) {
  524. if (!$notab)
  525. return "\n</div>\n";
  526. else
  527. return '';
  528. }
  529. /**
  530. * Return a formated address (part address/zip/town/state) according to country rules
  531. *
  532. * @param Object $object A company or contact object
  533. * @return string Formated string
  534. */
  535. function dol_format_address($object) {
  536. $ret = '';
  537. $countriesusingstate = array('US', 'IN', 'GB');
  538. // Address
  539. $ret .= $object->address;
  540. // Zip/Town/State
  541. if (in_array($object->country_code, array('US'))) { // US: title firstname name \n address lines \n town, state, zip \n country
  542. $ret .= ($ret ? "\n" : '' ) . $object->town;
  543. if ($object->state && in_array($object->country_code, $countriesusingstate)) {
  544. $ret.=", " . $object->departement;
  545. }
  546. if ($object->zip)
  547. $ret .= ', ' . $object->zip;
  548. }
  549. else if (in_array($object->country_code, array('GB'))) { // UK: title firstname name \n address lines \n town state \n zip \n country
  550. $ret .= ($ret ? "\n" : '' ) . $object->town;
  551. if ($object->state && in_array($object->country_code, $countriesusingstate)) {
  552. $ret.=", " . $object->departement;
  553. }
  554. if ($object->zip)
  555. $ret .= ($ret ? "\n" : '' ) . $object->zip;
  556. }
  557. else { // Other: title firstname name \n address lines \n zip town \n country
  558. $ret .= ($ret ? "\n" : '' ) . $object->zip;
  559. $ret .= ' ' . $object->town;
  560. if ($object->state && in_array($object->country_code, $countriesusingstate)) {
  561. $ret.=", " . $object->state;
  562. }
  563. }
  564. return $ret;
  565. }
  566. /**
  567. * Output date in a string format according to outputlangs (or langs if not defined).
  568. * Return charset is always UTF-8, except if encodetoouput is defined. In this case charset is output charset
  569. *
  570. * @param timestamp $time GM Timestamps date
  571. * @param string $format Output date format
  572. * "%d %b %Y",
  573. * "%d/%m/%Y %H:%M",
  574. * "%d/%m/%Y %H:%M:%S",
  575. * "day", "daytext", "dayhour", "dayhourldap", "dayhourtext", "dayrfc", "dayhourrfc"
  576. * @param string $tzoutput true=output or 'gmt' => string is for Greenwich location
  577. * false or 'tzserver' => output string is for local PHP server TZ usage
  578. * 'tzuser' => output string is for local browser TZ usage
  579. * @param Tranlsate $outputlangs Object lang that contains language for text translation.
  580. * @param boolean $encodetooutput false=no convert into output pagecode
  581. * @return string Formated date or '' if time is null
  582. *
  583. * @see dol_mktime, dol_stringtotime, dol_getdate
  584. */
  585. function dol_print_date($time, $format = '', $tzoutput = 'tzserver', $outputlangs = '', $encodetooutput = false) {
  586. global $conf, $langs;
  587. require_once DOL_DOCUMENT_ROOT . '/includes/adodbtime/adodb-time.inc.php';
  588. $time = strtotime($time);
  589. $to_gmt = false;
  590. $offsettz = $offsetdst = 0;
  591. if ($tzoutput) {
  592. $to_gmt = true; // For backward compatibility
  593. if (is_string($tzoutput)) {
  594. if ($tzoutput == 'tzserver') {
  595. $to_gmt = false;
  596. $offsettz = $offsetdst = 0;
  597. } elseif ($tzoutput == 'tzuser') {
  598. $to_gmt = true;
  599. $offsettz = (empty($_SESSION['dol_tz']) ? 0 : $_SESSION['dol_tz']) * 60 * 60;
  600. $offsetdst = (empty($_SESSION['dol_dst']) ? 0 : $_SESSION['dol_dst']) * 60 * 60;
  601. } elseif ($tzoutput == 'tzcompany') {
  602. $to_gmt = false;
  603. $offsettz = $offsetdst = 0; // TODO Define this and use it later
  604. }
  605. }
  606. }
  607. if (!is_object($outputlangs))
  608. $outputlangs = $langs;
  609. // Si format non defini, on prend $conf->format_date_text_short sinon %Y-%m-%d %H:%M:%S
  610. if (!$format)
  611. $format = (isset($conf->format_date_text_short) ? $conf->format_date_text_short : '%Y-%m-%d %H:%M:%S');
  612. // Change predefined format into computer format. If found translation in lang file we use it, otherwise we use default.
  613. if ($format == 'day')
  614. $format = ($outputlangs->trans("FormatDateShort") != "FormatDateShort" ? $outputlangs->trans("FormatDateShort") : $conf->format_date_short);
  615. if ($format == 'hour')
  616. $format = ($outputlangs->trans("FormatHourShort") != "FormatHourShort" ? $outputlangs->trans("FormatHourShort") : $conf->format_hour_short);
  617. if ($format == 'hourduration')
  618. $format = ($outputlangs->trans("FormatHourShortDuration") != "FormatHourShortDuration" ? $outputlangs->trans("FormatHourShortDuration") : $conf->format_hour_short_duration);
  619. if ($format == 'daytext')
  620. $format = ($outputlangs->trans("FormatDateText") != "FormatDateText" ? $outputlangs->trans("FormatDateText") : $conf->format_date_text);
  621. if ($format == 'daytextshort')
  622. $format = ($outputlangs->trans("FormatDateTextShort") != "FormatDateTextShort" ? $outputlangs->trans("FormatDateTextShort") : $conf->format_date_text_short);
  623. if ($format == 'dayhour')
  624. $format = ($outputlangs->trans("FormatDateHourShort") != "FormatDateHourShort" ? $outputlangs->trans("FormatDateHourShort") : $conf->format_date_hour_short);
  625. if ($format == 'dayhourtext')
  626. $format = ($outputlangs->trans("FormatDateHourText") != "FormatDateHourText" ? $outputlangs->trans("FormatDateHourText") : $conf->format_date_hour_text);
  627. if ($format == 'dayhourtextshort')
  628. $format = ($outputlangs->trans("FormatDateHourTextShort") != "FormatDateHourTextShort" ? $outputlangs->trans("FormatDateHourTextShort") : $conf->format_date_hour_text_short);
  629. // Format not sensitive to language
  630. if ($format == 'dayhourlog')
  631. $format = '%Y%m%d%H%M%S';
  632. if ($format == 'dayhourldap')
  633. $format = '%Y%m%d%H%M%SZ';
  634. if ($format == 'dayhourxcard')
  635. $format = '%Y%m%dT%H%M%SZ';
  636. if ($format == 'dayxcard')
  637. $format = '%Y%m%d';
  638. if ($format == 'dayrfc')
  639. $format = '%Y-%m-%d'; // DATE_RFC3339
  640. if ($format == 'dayhourrfc')
  641. $format = '%Y-%m-%dT%H:%M:%SZ'; // DATETIME RFC3339
  642. // If date undefined or "", we return ""
  643. if (dol_strlen($time) == 0)
  644. return ''; // $time=0 allowed (it means 01/01/1970 00:00:00)
  645. //print 'x'.$time;
  646. if (preg_match('/%b/i', $format)) { // There is some text to translate
  647. // We inhibate translation to text made by strftime functions. We will use trans instead later.
  648. $format = str_replace('%b', '__b__', $format);
  649. $format = str_replace('%B', '__B__', $format);
  650. }
  651. if (preg_match('/%a/i', $format)) { // There is some text to translate
  652. // We inhibate translation to text made by strftime functions. We will use trans instead later.
  653. $format = str_replace('%a', '__a__', $format);
  654. $format = str_replace('%A', '__A__', $format);
  655. }
  656. // Analyze date (deprecated) Ex: 1970-01-01, 1970-01-01 01:00:00, 19700101010000
  657. if (preg_match('/^([0-9]+)\-([0-9]+)\-([0-9]+) ?([0-9]+)?:?([0-9]+)?:?([0-9]+)?/i', $time, $reg) || preg_match('/^([0-9][0-9][0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])$/i', $time, $reg)) {
  658. // This part of code should not be used.
  659. dol_syslog("Functions.lib::dol_print_date function call with deprecated value of time in page " . $_SERVER["PHP_SELF"], LOG_WARNING);
  660. // Date has format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM:SS' or 'YYYYMMDDHHMMSS'
  661. $syear = (!empty($reg[1]) ? $reg[1] : '');
  662. $smonth = (!empty($reg[2]) ? $reg[2] : '');
  663. $sday = (!empty($reg[3]) ? $reg[3] : '');
  664. $shour = (!empty($reg[4]) ? $reg[4] : '');
  665. $smin = (!empty($reg[5]) ? $reg[5] : '');
  666. $ssec = (!empty($reg[6]) ? $reg[6] : '');
  667. $time = dol_mktime($shour, $smin, $ssec, $smonth, $sday, $syear, true);
  668. $ret = adodb_strftime($format, $time + $offsettz + $offsetdst, $to_gmt);
  669. } else {
  670. // Date is a timestamps
  671. if ($time < 100000000000) { // Protection against bad date values
  672. $ret = adodb_strftime($format, $time + $offsettz + $offsetdst, $to_gmt);
  673. }
  674. else
  675. $ret = 'Bad value ' . $time . ' for date';
  676. }
  677. if (preg_match('/__b__/i', $format)) {
  678. // Here ret is string in PHP setup language (strftime was used). Now we convert to $outputlangs.
  679. $month = adodb_strftime('%m', $time + $offsettz + $offsetdst);
  680. if ($encodetooutput) {
  681. $monthtext = $outputlangs->transnoentities('Month' . $month);
  682. $monthtextshort = $outputlangs->transnoentities('MonthShort' . $month);
  683. } else {
  684. $monthtext = $outputlangs->transnoentitiesnoconv('Month' . $month);
  685. $monthtextshort = $outputlangs->transnoentitiesnoconv('MonthShort' . $month);
  686. }
  687. //print 'monthtext='.$monthtext.' monthtextshort='.$monthtextshort;
  688. $ret = str_replace('__b__', $monthtextshort, $ret);
  689. $ret = str_replace('__B__', $monthtext, $ret);
  690. //print 'x'.$outputlangs->charset_output.'-'.$ret.'x';
  691. //return $ret;
  692. }
  693. if (preg_match('/__a__/i', $format)) {
  694. $w = adodb_strftime('%w', $time + $offsettz + $offsetdst);
  695. $dayweek = $outputlangs->transnoentitiesnoconv('Day' . $w);
  696. $ret = str_replace('__A__', $dayweek, $ret);
  697. $ret = str_replace('__a__', dol_substr($dayweek, 0, 3), $ret);
  698. }
  699. return $ret;
  700. }
  701. /**
  702. * Return an array with locale date info.
  703. * PHP getdate is restricted to the years 1901-2038 on Unix and 1970-2038 on Windows
  704. * WARNING: This function always use PHP server timezone to return locale informations.
  705. * Usage must be avoid.
  706. *
  707. * @param timestamp $timestamp Timestamp
  708. * @param boolean $fast Fast mode
  709. * @return array Array of informations
  710. * If no fast mode:
  711. * 'seconds' => $secs,
  712. * 'minutes' => $min,
  713. * 'hours' => $hour,
  714. * 'mday' => $day,
  715. * 'wday' => $dow,
  716. * 'mon' => $month,
  717. * 'year' => $year,
  718. * 'yday' => floor($secsInYear/$_day_power),
  719. * 'weekday' => gmdate('l',$_day_power*(3+$dow)),
  720. * 'month' => gmdate('F',mktime(0,0,0,$month,2,1971)),
  721. * If fast mode:
  722. * 'seconds' => $secs,
  723. * 'minutes' => $min,
  724. * 'hours' => $hour,
  725. * 'mday' => $day,
  726. * 'mon' => $month,
  727. * 'year' => $year,
  728. * 'yday' => floor($secsInYear/$_day_power),
  729. * 'leap' => $leaf,
  730. * 'ndays' => $ndays
  731. * @see dol_print_date, dol_stringtotime, dol_mktime
  732. */
  733. function dol_getdate($timestamp, $fast = false) {
  734. $usealternatemethod = false;
  735. if ($timestamp <= 0)
  736. $usealternatemethod = true; // <= 1970
  737. if ($timestamp >= 2145913200)
  738. $usealternatemethod = true; // >= 2038
  739. if ($usealternatemethod) {
  740. $arrayinfo = adodb_getdate($timestamp, $fast);
  741. } else {
  742. $arrayinfo = getdate($timestamp);
  743. }
  744. return $arrayinfo;
  745. }
  746. /**
  747. * Return a timestamp date built from detailed informations (by default a local PHP server timestamp)
  748. * Replace function mktime not available under Windows if year < 1970
  749. * PHP mktime is restricted to the years 1901-2038 on Unix and 1970-2038 on Windows
  750. *
  751. * @param int $hour Hour (can be -1 for undefined)
  752. * @param int $minute Minute (can be -1 for undefined)
  753. * @param int $second Second (can be -1 for undefined)
  754. * @param int $month Month (1 to 12)
  755. * @param int $day Day (1 to 31)
  756. * @param int $year Year
  757. * @param int $gm 1=Input informations are GMT values, otherwise local to server TZ
  758. * @param int $check 0=No check on parameters (Can use day 32, etc...)
  759. * @return timestamp Date as a timestamp, '' if error
  760. * @see dol_print_date, dol_stringtotime, dol_getdate
  761. */
  762. function dol_mktime($hour, $minute, $second, $month, $day, $year, $gm = false, $check = 1) {
  763. global $conf;
  764. //print "- ".$hour.",".$minute.",".$second.",".$month.",".$day.",".$year.",".$_SERVER["WINDIR"]." -";
  765. // Clean parameters
  766. if ($hour == -1 || empty($hour))
  767. $hour = 0;
  768. if ($minute == -1 || empty($minute))
  769. $minute = 0;
  770. if ($second == -1 || empty($second))
  771. $second = 0;
  772. // Check parameters
  773. if ($check) {
  774. if (!$month || !$day)
  775. return '';
  776. if ($day > 31)
  777. return '';
  778. if ($month > 12)
  779. return '';
  780. if ($hour < 0 || $hour > 24)
  781. return '';
  782. if ($minute < 0 || $minute > 60)
  783. return '';
  784. if ($second < 0 || $second > 60)
  785. return '';
  786. }
  787. if (method_exists('DateTime', 'getTimestamp') && empty($conf->global->MAIN_OLD_DATE)) {
  788. if (empty($gm))
  789. $localtz = new DateTimeZone(date_default_timezone_get());
  790. else
  791. $localtz = new DateTimeZone('UTC');
  792. $dt = new DateTime(null, $localtz);
  793. $dt->setDate($year, $month, $day);
  794. $dt->setTime((int) $hour, (int) $minute, (int) $second);
  795. $date = $dt->getTimestamp();
  796. }
  797. else {
  798. $usealternatemethod = false;
  799. if ($year <= 1970)
  800. $usealternatemethod = true; // <= 1970
  801. if ($year >= 2038)
  802. $usealternatemethod = true; // >= 2038
  803. if ($usealternatemethod || $gm) { // Si time gm, seule adodb peut convertir
  804. $date = adodb_mktime($hour, $minute, $second, $month, $day, $year, 0, $gm);
  805. } else {
  806. $date = mktime($hour, $minute, $second, $month, $day, $year);
  807. }
  808. }
  809. return date("c", $date);
  810. }
  811. /**
  812. * Return date for now. We should always use this function without parameters (that means GMT time)
  813. *
  814. * @param string $mode 'gmt' => we return GMT timestamp,
  815. * 'tzserver' => we add the PHP server timezone
  816. * 'tzref' => we add the company timezone
  817. * 'tzuser' => we add the user timezone
  818. * @return timestamp $date Timestamp
  819. */
  820. function dol_now($mode = 'gmt') {
  821. // Note that gmmktime and mktime return same value (GMT) whithout parameters
  822. //if ($mode == 'gmt') $ret=gmmktime(); // Strict Standards: gmmktime(): You should be using the time() function instead
  823. if ($mode == 'gmt')
  824. $ret = time(); // Time for now at greenwich.
  825. else if ($mode == 'tzserver') { // Time for now with PHP server timezone added
  826. require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php';
  827. $tzsecond = getServerTimeZoneInt('now'); // Contains tz+dayling saving time
  828. $ret = time() + ($tzsecond * 3600);
  829. }
  830. /* else if ($mode == 'tzref') // Time for now with parent company timezone is added
  831. {
  832. require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
  833. $tzsecond=getParentCompanyTimeZoneInt(); // Contains tz+dayling saving time
  834. $ret=dol_now('gmt')+($tzsecond*3600);
  835. } */ else if ($mode == 'tzuser') { // Time for now with user timezone is added
  836. //print 'eeee'.time().'-'.mktime().'-'.gmmktime();
  837. $offsettz = (empty($_SESSION['dol_tz']) ? 0 : $_SESSION['dol_tz']) * 60 * 60;
  838. $offsetdst = (empty($_SESSION['dol_dst']) ? 0 : $_SESSION['dol_dst']) * 60 * 60;
  839. $ret = time() + ($offsettz + $offsetdst);
  840. }
  841. return date("c", $ret); // ISO date format
  842. }
  843. /**
  844. * Return string with formated size
  845. *
  846. * @param int $size Size to print
  847. * @param int $shortvalue Tell if we want long value to use another unit (Ex: 1.5Kb instead of 1500b)
  848. * @param int $shortunit Use short value of size unit
  849. * @return string Link
  850. */
  851. function dol_print_size($size, $shortvalue = 0, $shortunit = 0) {
  852. global $langs;
  853. $level = 1024;
  854. // Set value text
  855. if (empty($shortvalue) || $size < ($level * 10)) {
  856. $ret = $size;
  857. $textunitshort = $langs->trans("b");
  858. $textunitlong = $langs->trans("Bytes");
  859. } else {
  860. $ret = round($size / $level, 0);
  861. $textunitshort = $langs->trans("Kb");
  862. $textunitlong = $langs->trans("KiloBytes");
  863. }
  864. // Use long or short text unit
  865. if (empty($shortunit)) {
  866. $ret.=' ' . $textunitlong;
  867. } else {
  868. $ret.=' ' . $textunitshort;
  869. }
  870. return $ret;
  871. }
  872. /**
  873. * Show Url link
  874. *
  875. * @param string $url Url to show
  876. * @param string $target Target for link
  877. * @param int $max Max number of characters to show
  878. * @return string HTML Link
  879. */
  880. function dol_print_url($url, $target = '_blank', $max = 32) {
  881. if (empty($url))
  882. return '';
  883. $link = '<a href="';
  884. if (!preg_match('/^http/i', $url))
  885. $link.='http://';
  886. $link.=$url;
  887. if ($target)
  888. $link.='" target="' . $target . '">';
  889. if (!preg_match('/^http/i', $url))
  890. $link.='http://';
  891. $link.=dol_trunc($url, $max);
  892. $link.='</a>';
  893. return $link;
  894. }
  895. /**
  896. * Show EMail link
  897. *
  898. * @param string $email EMail to show (only email, without 'Name of recipient' before)
  899. * @param int $cid Id of contact if known
  900. * @param int $socid Id of third party if known
  901. * @param int $addlink 0=no link to create action
  902. * @param int $max Max number of characters to show
  903. * @param int $showinvalid Show warning if syntax email is wrong
  904. * @return string HTML Link
  905. */
  906. function dol_print_email($email, $cid = 0, $socid = 0, $addlink = 0, $max = 64, $showinvalid = 1) {
  907. global $conf, $user, $langs;
  908. $newemail = $email;
  909. if (empty($email))
  910. return '&nbsp;';
  911. if (!empty($addlink)) {
  912. $newemail = '<a href="';
  913. if (!preg_match('/^mailto:/i', $email))
  914. $newemail.='mailto:';
  915. $newemail.=$email;
  916. $newemail.='">';
  917. $newemail.=dol_trunc($email, $max);
  918. $newemail.='</a>';
  919. if ($showinvalid && !isValidEmail($email)) {
  920. $langs->load("errors");
  921. $newemail.=img_warning($langs->trans("ErrorBadEMail", $email));
  922. }
  923. if (($cid || $socid) && !empty($conf->agenda->enabled) && $user->rights->agenda->myactions->create) {
  924. $type = 'AC_EMAIL';
  925. $link = '';
  926. if (!empty($conf->global->AGENDA_ADDACTIONFOREMAIL))
  927. $link = '<a href="' . DOL_URL_ROOT . '/comm/action/fiche.php?action=create&amp;backtopage=1&amp;actioncode=' . $type . '&amp;contactid=' . $cid . '&amp;socid=' . $socid . '">' . img_object($langs->trans("AddAction"), "calendar") . '</a>';
  928. $newemail = '<table class="nobordernopadding"><tr><td>' . $newemail . ' </td><td>&nbsp;' . $link . '</td></tr></table>';
  929. }
  930. }
  931. else {
  932. if ($showinvalid && !isValidEmail($email)) {
  933. $langs->load("errors");
  934. $newemail.=img_warning($langs->trans("ErrorBadEMail", $email));
  935. }
  936. }
  937. return $newemail;
  938. }
  939. /**
  940. * Format phone numbers according to country
  941. *
  942. * @param string $phone Phone number to format
  943. * @param string $country Country code to use for formatting
  944. * @param int $cid Id of contact if known
  945. * @param int $socid Id of third party if known
  946. * @param int $addlink 0=no link to create action
  947. * @param string $separ separation between numbers for a better visibility example : xx.xx.xx.xx.xx
  948. * @return string Formated phone number
  949. */
  950. function dol_print_phone($phone, $country = "FR", $cid = 0, $socid = 0, $addlink = 0, $separ = "&nbsp;") {
  951. global $conf, $user, $langs;
  952. // Clean phone parameter
  953. $phone = preg_replace("/[\s.-]/", "", trim($phone));
  954. if (empty($phone)) {
  955. return '';
  956. }
  957. $newphone = $phone;
  958. if (strtoupper($country) == "FR") {
  959. // France
  960. if (dol_strlen($phone) == 10) {
  961. $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);
  962. } elseif (dol_strlen($newphone) == 7) {
  963. $newphone = substr($newphone, 0, 3) . $separ . substr($newphone, 3, 2) . $separ . substr($newphone, 5, 2);
  964. } elseif (dol_strlen($newphone) == 9) {
  965. $newphone = substr($newphone, 0, 2) . $separ . substr($newphone, 2, 3) . $separ . substr($newphone, 5, 2) . $separ . substr($newphone, 7, 2);
  966. } elseif (dol_strlen($newphone) == 11) {
  967. $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);
  968. } elseif (dol_strlen($newphone) == 12) {
  969. $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);
  970. }
  971. }
  972. if (!empty($addlink)) {
  973. if (!empty($conf->clicktodial->enabled) && $addlink == 'AC_TEL') {
  974. if (empty($user->clicktodial_loaded))
  975. $user->fetch_clicktodial();
  976. if (empty($conf->global->CLICKTODIAL_URL))
  977. $urlmask = 'ErrorClickToDialModuleNotConfigured';
  978. else
  979. $urlmask = $conf->global->CLICKTODIAL_URL;
  980. $clicktodial_poste = (!empty($user->clicktodial_poste) ? urlencode($user->clicktodial_poste) : '');
  981. $clicktodial_login = (!empty($user->clicktodial_login) ? urlencode($user->clicktodial_login) : '');
  982. $clicktodial_password = (!empty($user->clicktodial_password) ? urlencode($user->clicktodial_password) : '');
  983. // This line is for backward compatibility
  984. $url = sprintf($urlmask, urlencode($phone), $clicktodial_poste, $clicktodial_login, $clicktodial_password);
  985. // Thoose lines are for substitution
  986. $substitarray = array('__PHONEFROM__' => $clicktodial_poste,
  987. '__PHONETO__' => urlencode($phone),
  988. '__LOGIN__' => $clicktodial_login,
  989. '__PASS__' => $clicktodial_password);
  990. $url = make_substitutions($url, $substitarray);
  991. $newphonesav = $newphone;
  992. $newphone = '<a href="' . $url . '"';
  993. if (!empty($conf->global->CLICKTODIAL_FORCENEWTARGET))
  994. $newphone.=' target="_blank"';
  995. $newphone.='>' . $newphonesav . '</a>';
  996. }
  997. //if (($cid || $socid) && ! empty($conf->agenda->enabled) && $user->rights->agenda->myactions->create)
  998. if (!empty($conf->agenda->enabled) && $user->rights->agenda->myactions->create) {
  999. $type = 'AC_TEL';
  1000. $link = '';
  1001. if ($addlink == 'AC_FAX')
  1002. $type = 'AC_FAX';
  1003. if (!empty($conf->global->AGENDA_ADDACTIONFORPHONE))
  1004. $link = '<a href="' . DOL_URL_ROOT . '/comm/action/fiche.php?action=create&amp;backtopage=1&amp;actioncode=' . $type . ($cid ? '&amp;contactid=' . $cid : '') . ($socid ? '&amp;socid=' . $socid : '') . '">' . img_object($langs->trans("AddAction"), "calendar") . '</a>';
  1005. $newphone = '<table class="nobordernopadding"><tr><td>' . $newphone . ' </td><td>&nbsp;' . $link . '</td></tr></table>';
  1006. }
  1007. }
  1008. return $newphone;
  1009. }
  1010. /**
  1011. * Return an IP formated to be shown on screen
  1012. *
  1013. * @param string $ip IP
  1014. * @param int $mode 0=return IP + country/flag, 1=return only country/flag, 2=return only IP
  1015. * @return string Formated IP, with country if GeoIP module is enabled
  1016. */
  1017. function dol_print_ip($ip, $mode = 0) {
  1018. global $conf, $langs;
  1019. $ret = '';
  1020. if (empty($mode))
  1021. $ret.=$ip;
  1022. if (!empty($conf->geoipmaxmind->enabled) && $mode != 2) {
  1023. $datafile = $conf->global->GEOIPMAXMIND_COUNTRY_DATAFILE;
  1024. //$ip='24.24.24.24';
  1025. //$datafile='E:\Mes Sites\Web\Admin1\awstats\maxmind\GeoIP.dat'; Note that this must be downloaded datafile (not same than datafile provided with ubuntu packages)
  1026. include_once DOL_DOCUMENT_ROOT . '/core/class/dolgeoip.class.php';
  1027. $geoip = new DolGeoIP('country', $datafile);
  1028. //print 'ip='.$ip.' databaseType='.$geoip->gi->databaseType." GEOIP_CITY_EDITION_REV1=".GEOIP_CITY_EDITION_REV1."\n";
  1029. //print "geoip_country_id_by_addr=".geoip_country_id_by_addr($geoip->gi,$ip)."\n";
  1030. $countrycode = $geoip->getCountryCodeFromIP($ip);
  1031. if ($countrycode) { // If success, countrycode is us, fr, ...
  1032. if (file_exists(DOL_DOCUMENT_ROOT . '/theme/common/flags/' . $countrycode . '.png')) {
  1033. $ret.=' ' . img_picto($countrycode . ' ' . $langs->trans("AccordingToGeoIPDatabase"), DOL_URL_ROOT . '/theme/common/flags/' . $countrycode . '.png', '', 1);
  1034. }
  1035. else
  1036. $ret.=' (' . $countrycode . ')';
  1037. }
  1038. }
  1039. return $ret;
  1040. }
  1041. /**
  1042. * Return country code for current user.
  1043. * If software is used inside a local network, detection may fails (we need a public ip)
  1044. *
  1045. * @return string Country code (fr, es, it, us, ...)
  1046. */
  1047. function dol_user_country() {
  1048. global $conf, $langs, $user;
  1049. //$ret=$user->xxx;
  1050. $ret = '';
  1051. if (!empty($conf->geoipmaxmind->enabled)) {
  1052. $ip = $_SERVER["REMOTE_ADDR"];
  1053. $datafile = $conf->global->GEOIPMAXMIND_COUNTRY_DATAFILE;
  1054. //$ip='24.24.24.24';
  1055. //$datafile='E:\Mes Sites\Web\Admin1\awstats\maxmind\GeoIP.dat';
  1056. include_once DOL_DOCUMENT_ROOT . '/core/class/dolgeoip.class.php';
  1057. $geoip = new DolGeoIP('country', $datafile);
  1058. $countrycode = $geoip->getCountryCodeFromIP($ip);
  1059. $ret = $countrycode;
  1060. }
  1061. return $ret;
  1062. }
  1063. /**
  1064. * Format address string
  1065. *
  1066. * @param string $address Address
  1067. * @param int $htmlid Html ID (for example 'gmap')
  1068. * @param int $mode thirdparty|contact|member|other
  1069. * @param int $id Id of object
  1070. * @param bool $gps See MAP
  1071. * @return void
  1072. */
  1073. function dol_print_address($address, $htmlid, $mode, $id, $gps = false) {
  1074. global $conf, $user, $langs;
  1075. $rtr = "";
  1076. if ($address) {
  1077. $rtr.= nl2br($address);
  1078. $showgmap = $showomap = 0;
  1079. if ($mode == 'thirdparty' && !empty($conf->google->enabled) && !empty($conf->global->GOOGLE_ENABLE_GMAPS))
  1080. $showgmap = 1;
  1081. if ($mode == 'contact' && !empty($conf->google->enabled) && !empty($conf->global->GOOGLE_ENABLE_GMAPS_CONTACTS))
  1082. $showgmap = 1;
  1083. if ($mode == 'member' && !empty($conf->google->enabled) && !empty($conf->global->GOOGLE_ENABLE_GMAPS_MEMBERS))
  1084. $showgmap = 1;
  1085. if ($mode == 'thirdparty' && !empty($conf->openstreetmap->enabled) && !empty($conf->global->OPENSTREETMAP_ENABLE_MAPS))
  1086. $showomap = 1;
  1087. if ($mode == 'contact' && !empty($conf->openstreetmap->enabled) && !empty($conf->global->OPENSTREETMAP_ENABLE_MAPS_CONTACTS))
  1088. $showomap = 1;
  1089. if ($mode == 'member' && !empty($conf->openstreetmap->enabled) && !empty($conf->global->OPENSTREETMAP_ENABLE_MAPS_MEMBERS))
  1090. $showomap = 1;
  1091. if ($conf->map->enabled && $gps) {
  1092. $url = dol_buildpath('/map/map.php?id=' . $id, 1);
  1093. $rtr.= ' <a href="' . $url . '" target="_gmaps"><img id="' . $htmlid . '" border="0" src="' . DOL_URL_ROOT . '/theme/common/gmap.png"></a>';
  1094. }
  1095. // TODO Add a hook here
  1096. if ($showgmap) {
  1097. $url = dol_buildpath('/google/gmaps.php?mode=' . $mode . '&id=' . $id, 1);
  1098. $rtr.= ' <a href="' . $url . '" target="_gmaps"><img id="' . $htmlid . '" border="0" src="' . DOL_URL_ROOT . '/theme/common/gmap.png"></a>';
  1099. }
  1100. if ($showomap) {
  1101. $url = dol_buildpath('/openstreetmap/maps.php?mode=' . $mode . '&id=' . $id, 1);
  1102. $rtr.= ' <a href="' . $url . '" target="_gmaps"><img id="' . $htmlid . '_openstreetmap" border="0" src="' . DOL_URL_ROOT . '/theme/common/gmap.png"></a>';
  1103. }
  1104. }
  1105. return $rtr;
  1106. }
  1107. /**
  1108. * Return true if email syntax is ok
  1109. *
  1110. * @param string $address email (Ex: "toto@titi.com", "John Do <johndo@titi.com>")
  1111. * @return boolean true if email syntax is OK, false if KO or empty string
  1112. */
  1113. function isValidEmail($address) {
  1114. if (preg_match("/.*<(.+)>/i", $address, $regs)) {
  1115. $address = $regs[1];
  1116. }
  1117. // 2 letters domains extensions are for countries
  1118. // 3 letters domains extensions: biz|com|edu|gov|int|mil|net|org|pro|...
  1119. if (preg_match("/^[^@\s\t]+@([a-zA-Z0-9\-]+\.)+([a-zA-Z0-9\-]{2,3}|asso|aero|coop|info|name)\$/i", $address)) {
  1120. return true;
  1121. } else {
  1122. return false;
  1123. }
  1124. }
  1125. /**
  1126. * Return true if phone number syntax is ok
  1127. *
  1128. * @param string $phone phone (Ex: "0601010101")
  1129. * @return boolean true if phone syntax is OK, false if KO or empty string
  1130. */
  1131. function isValidPhone($phone) {
  1132. return true;
  1133. }
  1134. /**
  1135. * Make a strlen call. Works even if mbstring module not enabled
  1136. *
  1137. * @param string $string String to calculate length
  1138. * @param string $stringencoding Encoding of string
  1139. * @return int Length of string
  1140. */
  1141. function dol_strlen($string, $stringencoding = 'UTF-8') {
  1142. if (function_exists('mb_strlen'))
  1143. return mb_strlen($string, $stringencoding);
  1144. else
  1145. return strlen($string);
  1146. }
  1147. /**
  1148. * Make a substring. Works even in mbstring module is not enabled.
  1149. *
  1150. * @param string $string String to scan
  1151. * @param string $start Start position
  1152. * @param int $length Length
  1153. * @param string $stringencoding Page code used for input string encoding
  1154. * @return string substring
  1155. */
  1156. function dol_substr($string, $start, $length, $stringencoding = '') {
  1157. global $langs;
  1158. if (empty($stringencoding))
  1159. $stringencoding = $langs->charset_output;
  1160. $ret = '';
  1161. if (function_exists('mb_substr')) {
  1162. $ret = mb_substr($string, $start, $length, $stringencoding);
  1163. } else {
  1164. $ret = substr($string, $start, $length);
  1165. }
  1166. return $ret;
  1167. }
  1168. /**
  1169. * Show a javascript graph.
  1170. * Do not use this function anymore. Use DolGraph class instead.
  1171. *
  1172. * @param string $htmlid Html id name
  1173. * @param int $width Width in pixel
  1174. * @param int $height Height in pixel
  1175. * @param array $data Data array
  1176. * @param int $showlegend 1 to show legend, 0 otherwise
  1177. * @param string $type Type of graph ('pie', 'barline')
  1178. * @param int $showpercent Show percent (with type='pie' only)
  1179. * @param string $url Param to add an url to click values
  1180. * @return void
  1181. * @deprecated
  1182. */
  1183. function dol_print_graph($htmlid, $width, $height, $data, $showlegend = 0, $type = 'pie', $showpercent = 0, $url = '') {
  1184. global $conf, $langs;
  1185. global $theme_datacolor; // To have var kept when function is called several times
  1186. if (empty($conf->use_javascript_ajax))
  1187. return;
  1188. $jsgraphlib = 'flot';
  1189. $datacolor = array();
  1190. // Load colors of theme into $datacolor array
  1191. $color_file = DOL_DOCUMENT_ROOT . "/theme/" . $conf->theme . "/graph-color.php";
  1192. if (is_readable($color_file)) {
  1193. include_once $color_file;
  1194. if (isset($theme_datacolor)) {
  1195. $datacolor = array();
  1196. foreach ($theme_datacolor as $val) {
  1197. $datacolor[] = "#" . sprintf("%02x", $val[0]) . sprintf("%02x", $val[1]) . sprintf("%02x", $val[2]);
  1198. }
  1199. }
  1200. }
  1201. print '<div id="' . $htmlid . '" style="width:' . $width . 'px;height:' . $height . 'px;"></div>';
  1202. // We use Flot js lib
  1203. if ($jsgraphlib == 'flot') {
  1204. if ($type == 'pie') {
  1205. // data is array('series'=>array(serie1,serie2,...),
  1206. // 'seriestype'=>array('bar','line',...),
  1207. // 'seriescolor'=>array(0=>'#999999',1=>'#999999',...)
  1208. // 'xlabel'=>array(0=>labelx1,1=>labelx2,...));
  1209. // serieX is array('label'=>'label', data=>val)
  1210. print '
  1211. <script type="text/javascript">
  1212. $(function () {
  1213. var data = ' . json_encode($data['series']) . ';
  1214. function plotWithOptions() {
  1215. $.plot($("#' . $htmlid . '"), data,
  1216. {
  1217. series: {
  1218. pie: {
  1219. show: true,
  1220. radius: 3/4,
  1221. label: {
  1222. show: true,
  1223. radius: 3/4,
  1224. formatter: function(label, series) {
  1225. var percent=Math.round(series.percent);
  1226. var number=series.data[0][1];
  1227. return \'';
  1228. print '<div style="font-size:8pt;text-align:center;padding:2px;color:white;">';
  1229. if ($url)
  1230. print '<a style="color: #FFFFFF;" border="0" href="' . $url . '=">';
  1231. print '\'+' . ($showlegend ? 'number' : 'label+\'<br/>\'+number');
  1232. if (!empty($showpercent))
  1233. print '+\'<br/>\'+percent+\'%\'';
  1234. print '+\'';
  1235. if ($url)
  1236. print '</a>';
  1237. print '</div>\';
  1238. },
  1239. background: {
  1240. opacity: 0.5,
  1241. color: \'#000000\'
  1242. }
  1243. }
  1244. }
  1245. },
  1246. zoom: {
  1247. interactive: true
  1248. },
  1249. pan: {
  1250. interactive: true
  1251. },';
  1252. if (count($datacolor)) {
  1253. print 'colors: ' . (!empty($data['seriescolor']) ? json_encode($data['seriescolor']) : json_encode($datacolor)) . ',';
  1254. }
  1255. print 'legend: {show: ' . ($showlegend ? 'true' : 'false') . ', position: \'ne\' }
  1256. });
  1257. }
  1258. plotWithOptions();
  1259. });
  1260. </script>';
  1261. } else if ($type == 'barline') {
  1262. // data is array('series'=>array(serie1,serie2,...),
  1263. // 'seriestype'=>array('bar','line',...),
  1264. // 'seriescolor'=>array(0=>'#999999',1=>'#999999',...)
  1265. // 'xlabel'=>array(0=>labelx1,1=>labelx2,...));
  1266. // serieX is array('label'=>'label', data=>array(0=>y1,1=>y2,...)) with same nb of value than into xlabel
  1267. print '
  1268. <script type="text/javascript">
  1269. $(function () {
  1270. var data = [';
  1271. $i = 0;
  1272. $outputserie = 0;
  1273. foreach ($data['series'] as $serie) {
  1274. if ($data['seriestype'][$i] == 'line') {
  1275. $i++;
  1276. continue;
  1277. };
  1278. if ($outputserie > 0)
  1279. print ',';
  1280. print '{ bars: { stack: 0, show: true, barWidth: 0.9, align: \'center\' }, label: \'' . dol_escape_js($serie['label']) . '\', data: ' . json_encode($serie['data']) . '}' . "\n";
  1281. $outputserie++;
  1282. $i++;
  1283. }
  1284. if ($outputserie)
  1285. print ', ';
  1286. //print '];
  1287. //var datalines = [';
  1288. $i = 0;
  1289. $outputserie = 0;
  1290. foreach ($data['series'] as $serie) {
  1291. if (empty($data['seriestype'][$i]) || $data['seriestype'][$i] == 'bar') {
  1292. $i++;
  1293. continue;
  1294. };
  1295. if ($outputserie > 0)
  1296. print ',';
  1297. print '{ lines: { show: true }, label: \'' . dol_escape_js($serie['label']) . '\', data: ' . json_encode($serie['data']) . '}' . "\n";
  1298. $outputserie++;
  1299. $i++;
  1300. }
  1301. print '];
  1302. var dataticks = ' . json_encode($data['xlabel']) . '
  1303. function plotWithOptions() {
  1304. $.plot(jQuery("#' . $htmlid . '"), data,
  1305. {
  1306. series: {
  1307. stack: 0
  1308. },
  1309. zoom: {
  1310. interactive: true
  1311. },
  1312. pan: {
  1313. interactive: true
  1314. },';
  1315. if (count($datacolor)) {
  1316. print 'colors: ' . json_encode($datacolor) . ',';
  1317. }
  1318. print 'legend: {show: ' . ($showlegend ? 'true' : 'false') . '},
  1319. xaxis: {ticks: dataticks}
  1320. });
  1321. }
  1322. plotWithOptions();
  1323. });
  1324. </script>';
  1325. }
  1326. else
  1327. print 'BadValueForPArameterType';
  1328. }
  1329. }
  1330. /**
  1331. * Truncate a string to a particular length adding '...' if string larger than length.
  1332. * If length = max length+1, we do no truncate to avoid having just 1 char replaced with '...'.
  1333. * MAIN_DISABLE_TRUNC=1 can disable all truncings
  1334. *
  1335. * @param string $string String to truncate
  1336. * @param int $size Max string size visible. 0 for no limit. finale string size can be 1 more (if size was max+1) or 3 more (if we added ...)
  1337. * @param string $trunc Where to trunc: right, left, middle (size must be a 2 power), wrap
  1338. * @param string $stringencoding Tell what is source string encoding
  1339. * @param int $nodot Truncation do not add ... after truncation. So it's an exact truncation.
  1340. * @return string Truncated string
  1341. */
  1342. function dol_trunc($string, $size = 40, $trunc = 'right', $stringencoding = 'UTF-8', $nodot = 0) {
  1343. global $conf;
  1344. if ($size == 0 || !empty($conf->global->MAIN_DISABLE_TRUNC))
  1345. return $string;
  1346. // We go always here
  1347. if ($trunc == 'right') {
  1348. $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
  1349. if (dol_strlen($newstring, $stringencoding) > ($size + ($nodot ? 0 : 1)))
  1350. return dol_substr($newstring, 0, $size, $stringencoding) . ($nodot ? '' : '...');
  1351. else
  1352. return $string;
  1353. }
  1354. elseif ($trunc == 'middle') {
  1355. $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
  1356. if (dol_strlen($newstring, $stringencoding) > 2 && dol_strlen($newstring, $stringencoding) > ($size + 1)) {
  1357. $size1 = round($size / 2);
  1358. $size2 = round($size / 2);
  1359. return dol_substr($newstring, 0, $size1, $stringencoding) . '...' . dol_substr($newstring, dol_strlen($newstring, $stringencoding) - $size2, $size2, $stringencoding);
  1360. }
  1361. else
  1362. return $string;
  1363. }
  1364. elseif ($trunc == 'left') {
  1365. $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
  1366. if (dol_strlen($newstring, $stringencoding) > ($size + 1))
  1367. return '...' . dol_substr($newstring, dol_strlen($newstring, $stringencoding) - $size, $size, $stringencoding);
  1368. else
  1369. return $string;
  1370. }
  1371. elseif ($trunc == 'wrap') {
  1372. $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
  1373. if (dol_strlen($newstring, $stringencoding) > ($size + 1))
  1374. return dol_substr($newstring, 0, $size, $stringencoding) . "\n" . dol_trunc(dol_substr($newstring, $size, dol_strlen($newstring, $stringencoding) - $size, $stringencoding), $size, $trunc);
  1375. else
  1376. return $string;
  1377. }
  1378. else
  1379. return 'BadParam3CallingDolTrunc';
  1380. }
  1381. /**
  1382. * Show picto whatever it's its name (generic function)
  1383. *
  1384. * @param string $alt Text on alt and title of image
  1385. * @param string $picto Name of image file to show ('filenew', ...)
  1386. * If no extension provided, we use '.png'. Image must be stored into theme/xxx/img directory.
  1387. * Example: picto.png if picto.png is stored into htdocs/theme/mytheme/img
  1388. * Example: picto.png@mymodule if picto.png is stored into htdocs/mymodule/img
  1389. * Example: /mydir/mysubdir/picto.png if picto.png is stored into htdocs/mydir/mysubdir (pictoisfullpath must be set to 1)
  1390. * @param string $options Add more attribute on img tag (For example 'style="float: right"')
  1391. * @param int $pictoisfullpath If 1, image path is a full path
  1392. * @return string Return img tag
  1393. * @see #img_object, #img_picto_common
  1394. */
  1395. function img_picto($alt, $picto, $options = '', $pictoisfullpath = false) {
  1396. global $conf;
  1397. // Define fullpathpicto to use into src
  1398. if ($pictoisfullpath) {
  1399. // Clean parameters
  1400. if (!preg_match('/(\.png|\.gif)$/i', $picto))
  1401. $picto .= '.png';
  1402. $fullpathpicto = $picto;
  1403. }
  1404. else {
  1405. // By default, we search into theme directory
  1406. $url = DOL_URL_ROOT;
  1407. $path = 'theme/' . $conf->theme;
  1408. if (!empty($conf->global->MAIN_FORCETHEMEDIR))
  1409. $path = preg_replace('/^\//', '', $conf->global->MAIN_FORCETHEMEDIR) . '/' . $path;
  1410. // If we ask an image into module/img (not into a theme path)
  1411. if (preg_match('/^([^@]+)@([^@]+)$/i', $picto, $regs)) {
  1412. $picto = $regs[1];
  1413. $path = $regs[2];
  1414. }
  1415. // Clean parameters
  1416. if (!preg_match('/(\.png|\.gif)$/i', $picto))
  1417. $picto .= '.png';
  1418. // If img file not into standard path, we use alternate path
  1419. if (defined('DOL_URL_ROOT_ALT') && DOL_URL_ROOT_ALT && !file_exists(DOL_DOCUMENT_ROOT . '/' . $path . '/img/' . $picto))
  1420. $url = DOL_URL_ROOT_ALT;
  1421. $fullpathpicto = $url . '/' . $path . '/img/' . $picto;
  1422. }
  1423. return '<img src="' . $fullpathpicto . '" border="0" alt="' . dol_escape_htmltag($alt) . '" title="' . dol_escape_htmltag($alt) . '"' . (!empty($options) ? ' ' . $options : '') . '>';
  1424. }
  1425. /**
  1426. * Show a picto called object_picto (generic function)
  1427. *
  1428. * @param string $alt Text of alt on image
  1429. * @param string $picto Name of image to show object_picto (example: user, group, action, bill, contract, propal, product, ...)
  1430. * For external modules use imagename@mymodule to search into directory "img" of module.
  1431. * @param string $options Add more attribute on img tag (ie: class="datecallink")
  1432. * @param int $pictoisfullpath If 1, image path is a full path
  1433. * @return string Return img tag
  1434. * @see #img_picto, #img_picto_common
  1435. */
  1436. function img_object($alt, $picto, $options = '', $pictoisfullpath = false) {
  1437. return img_picto($alt, 'object_' . $picto, $options, $pictoisfullpath);
  1438. }
  1439. /**
  1440. * Show picto (generic function)
  1441. *
  1442. * @param string $alt Text on alt and title of image
  1443. * @param string $picto Name of image file to show (If no extension provided, we use '.png'). Image must be stored into htdocs/theme/common directory.
  1444. * @param string $options Add more attribute on img tag
  1445. * @param int $pictoisfullpath If 1, image path is a full path
  1446. * @return string Return img tag
  1447. * @see #img_object, #img_picto
  1448. */
  1449. function img_picto_common($alt, $picto, $options = '', $pictoisfullpath = 0) {
  1450. global $conf;
  1451. if (!preg_match('/(\.png|\.gif)$/i', $picto))
  1452. $picto .= '.png';
  1453. if ($pictoisfullpath)
  1454. $path = $picto;
  1455. else {
  1456. $path = DOL_URL_ROOT . '/theme/common/' . $picto;
  1457. if (!empty($conf->global->MAIN_MODULE_CAN_OVERWRITE_COMMONICONS)) {
  1458. $themepath = DOL_DOCUMENT_ROOT . '/theme/' . $conf->theme . '/img/' . $picto;
  1459. if (file_exists($themepath))
  1460. $path = $themepath;
  1461. }
  1462. }
  1463. return img_picto($alt, $path, $options, 1);
  1464. }
  1465. /**
  1466. * Show logo action
  1467. *
  1468. * @param string $alt Text for image alt and title ('default', ...)
  1469. * @param int $numaction Action to show
  1470. * @return string Return an img tag
  1471. */
  1472. function img_action($alt, $numaction) {
  1473. global $conf, $langs;
  1474. if ($alt == 'default') {
  1475. if ($numaction == -1)
  1476. $alt = $langs->transnoentitiesnoconv('ChangeDoNotContact');
  1477. if ($numaction == 0)
  1478. $alt = $langs->transnoentitiesnoconv('ChangeNeverContacted');
  1479. if ($numaction == 1)
  1480. $alt = $langs->transnoentitiesnoconv('ChangeToContact');
  1481. if ($numaction == 2)
  1482. $alt = $langs->transnoentitiesnoconv('ChangeContactInProcess');
  1483. if ($numaction == 3)
  1484. $alt = $langs->transnoentitiesnoconv('ChangeContactDone');
  1485. }
  1486. return img_picto($alt, 'stcomm' . $numaction . '.png');
  1487. }
  1488. /**
  1489. * Show pdf logo
  1490. *
  1491. * @param string $alt Texte sur le alt de l'image
  1492. * @param int $size Taille de l'icone : 3 = 16x16px , 2 = 14x14px
  1493. * @return string Retourne tag img
  1494. */
  1495. function img_pdf($alt = 'default', $size = 3) {
  1496. global $conf, $langs;
  1497. if ($alt == 'default')
  1498. $alt = $langs->trans('Show');
  1499. return img_picto($alt, 'pdf' . $size . '.png');
  1500. }
  1501. /**
  1502. * Show logo +
  1503. *
  1504. * @param string $alt Texte sur le alt de l'image
  1505. * @return string Return tag img
  1506. */
  1507. function img_edit_add($alt = 'default') {
  1508. global $conf, $langs;
  1509. if ($alt == 'default')
  1510. $alt = $langs->trans('Add');
  1511. return img_picto($alt, 'edit_add.png');
  1512. }
  1513. /**
  1514. * Show logo -
  1515. *
  1516. * @param string $alt Texte sur le alt de l'image
  1517. * @return string Retourne tag img
  1518. */
  1519. function img_edit_remove($alt = 'default') {
  1520. global $conf, $langs;
  1521. if ($alt == 'default')
  1522. $alt = $langs->trans('Remove');
  1523. return img_picto($alt, 'edit_remove.png');
  1524. }
  1525. /**
  1526. * Show logo editer/modifier fiche
  1527. *
  1528. * @param string $alt Texte sur le alt de l'image
  1529. * @param float $float Si il faut y mettre le style "float: right"
  1530. * @param string $other Add more attributes on img
  1531. * @return string Retourne tag img
  1532. */
  1533. function img_edit($alt = 'default', $float = 0, $other = '') {
  1534. global $conf, $langs;
  1535. if ($alt == 'default')
  1536. $alt = $langs->trans('Modify');
  1537. return img_picto($alt, 'edit.png', ($float ? 'style="float: right"' : $other));
  1538. }
  1539. /**
  1540. * Show logo view card
  1541. *
  1542. * @param string $alt Texte sur le alt de l'image
  1543. * @param float $float Si il faut y mettre le style "float: right"
  1544. * @param string $other Add more attributes on img
  1545. * @return string Retourne tag img
  1546. */
  1547. function img_view($alt = 'default', $float = 0, $other = '') {
  1548. global $conf, $langs;
  1549. if ($alt == 'default')
  1550. $alt = $langs->trans('View');
  1551. $options = ($float ? 'style="float: right" ' : '') . $other;
  1552. return img_picto($alt, 'view.png', $options);
  1553. }
  1554. /**
  1555. * Show delete logo
  1556. *
  1557. * @param string $alt Text on alt image
  1558. * @param string $other Add more attributes on img
  1559. * @return string Retourne tag img
  1560. */
  1561. function img_delete($alt = 'default', $other = '') {
  1562. global $conf, $langs;
  1563. if ($alt == 'default')
  1564. $alt = $langs->trans('Delete');
  1565. return img_picto($alt, 'delete.png', $other);
  1566. }
  1567. /**
  1568. * Show help logo with cursor "?"
  1569. *
  1570. * @param string $usehelpcursor Use help cursor
  1571. * @param string $usealttitle Text to use as alt title
  1572. * @return string Retourne tag img
  1573. */
  1574. function img_help($usehelpcursor = 1, $usealttitle = 1) {
  1575. global $conf, $langs;
  1576. if ($usealttitle) {
  1577. if (is_string($usealttitle))
  1578. $usealttitle = dol_escape_htmltag($usealttitle);
  1579. else
  1580. $usealttitle = $langs->trans('Info');
  1581. }
  1582. return img_picto($usealttitle, 'info.png', ($usehelpcursor ? 'style="cursor: help"' : ''));
  1583. }
  1584. /**
  1585. * Show info logo
  1586. *
  1587. * @param string $alt Text to show on alt image
  1588. * @return string Return img tag
  1589. */
  1590. function img_info($alt = 'default') {
  1591. global $conf, $langs;
  1592. if ($alt == 'default')
  1593. $alt = $langs->trans('Informations');
  1594. return img_picto($alt, 'info.png');
  1595. }
  1596. /**
  1597. * Show warning logo
  1598. *
  1599. * @param string $alt Text to show on alt image
  1600. * @param int $float If we must add style "float: right"
  1601. * @return string Return img tag
  1602. */
  1603. function img_warning($alt = 'default', $float = 0) {
  1604. global $conf, $langs;
  1605. if ($alt == 'default')
  1606. $alt = $langs->trans('Warning');
  1607. return img_picto($alt, 'warning.png', ($float ? 'style="float: right"' : ''));
  1608. }
  1609. /**
  1610. * Show error logo
  1611. *
  1612. * @param string $alt Text to show on alt image
  1613. * @return string Return img tag
  1614. */
  1615. function img_error($alt = 'default') {
  1616. global $conf, $langs;
  1617. if ($alt == 'default')
  1618. $alt = $langs->trans('Error');
  1619. return img_picto($alt, 'error.png');
  1620. }
  1621. /**
  1622. * Show next logo
  1623. *
  1624. * @param string $alt Text to show on alt image
  1625. * @return string Return img tag
  1626. */
  1627. function img_next($alt = 'default') {
  1628. global $conf, $langs;
  1629. if ($alt == 'default')
  1630. $alt = $langs->trans('Next');
  1631. return img_picto($alt, 'next.png');
  1632. }
  1633. /**
  1634. * Show previous logo
  1635. *
  1636. * @param string $alt Text to show on alt image
  1637. * @return string Return img tag
  1638. */
  1639. function img_previous($alt = 'default') {
  1640. global $conf, $langs;
  1641. if ($alt == 'default')
  1642. $alt = $langs->trans('Previous');
  1643. return img_picto($alt, 'previous.png');
  1644. }
  1645. /**
  1646. * Show down arrow logo
  1647. *
  1648. * @param string $alt Text to show on alt image
  1649. * @param int $selected Selected
  1650. * @return string Return img tag
  1651. */
  1652. function img_down($alt = 'default', $selected = 0) {
  1653. global $conf, $langs;
  1654. if ($alt == 'default')
  1655. $alt = $langs->trans('Down');
  1656. return img_picto($alt, ($selected ? '1downarrow_selected.png' : '1downarrow.png'), 'class="imgdown"');
  1657. }
  1658. /**
  1659. * Show top arrow logo
  1660. *
  1661. * @param string $alt Text to show on alt image
  1662. * @param int $selected Selected
  1663. * @return string Return img tag
  1664. */
  1665. function img_up($alt = 'default', $selected = 0) {
  1666. global $conf, $langs;
  1667. if ($alt == 'default')
  1668. $alt = $langs->trans('Up');
  1669. return img_picto($alt, ($selected ? '1uparrow_selected.png' : '1uparrow.png'), 'class="imgup"');
  1670. }
  1671. /**
  1672. * Show left arrow logo
  1673. *
  1674. * @param string $alt Text to show on alt image
  1675. * @param int $selected Selected
  1676. * @return string Return img tag
  1677. */
  1678. function img_left($alt = 'default', $selected = 0) {
  1679. global $conf, $langs;
  1680. if ($alt == 'default')
  1681. $alt = $langs->trans('Left');
  1682. return img_picto($alt, ($selected ? '1leftarrow_selected.png' : '1leftarrow.png'));
  1683. }
  1684. /**
  1685. * Show right arrow logo
  1686. *
  1687. * @param string $alt Text to show on alt image
  1688. * @param int $selected Selected
  1689. * @return string Return img tag
  1690. */
  1691. function img_right($alt = 'default', $selected = 0) {
  1692. global $conf, $langs;
  1693. if ($alt == 'default')
  1694. $alt = $langs->trans('Right');
  1695. return img_picto($alt, ($selected ? '1rightarrow_selected.png' : '1rightarrow.png'));
  1696. }
  1697. /**
  1698. * Show tick logo if allowed
  1699. *
  1700. * @param string $allow Allow
  1701. * @param string $alt Text to show on alt image
  1702. * @return string Return img tag
  1703. */
  1704. function img_allow($allow, $alt = 'default') {
  1705. global $conf, $langs;
  1706. if ($alt == 'default')
  1707. $alt = $langs->trans('Active');
  1708. if ($allow == 1)
  1709. return img_picto($alt, 'tick.png');
  1710. return '-';
  1711. }
  1712. /**
  1713. * Show MIME img of a file
  1714. *
  1715. * @param string $file Filename
  1716. * @param string $alt Alternate text to show on img mous hover
  1717. * @return string Return img tag
  1718. */
  1719. function img_mime($file, $alt = '') {
  1720. require_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php';
  1721. $mimetype = dol_mimetype($file, '', 1);
  1722. $mimeimg = dol_mimetype($file, '', 2);
  1723. if (empty($alt))
  1724. $alt = 'Mime type: ' . $mimetype;
  1725. return img_picto_common($alt, 'mime/' . $mimeimg);
  1726. }
  1727. /**
  1728. * Show phone logo.
  1729. * Use img_picto instead.
  1730. *
  1731. * @param string $alt Text to show on alt image
  1732. * @param int $option Option
  1733. * @return string Return img tag
  1734. * @deprecated
  1735. */
  1736. function img_phone($alt = 'default', $option = 0) {
  1737. global $conf, $langs;
  1738. if ($alt == 'default')
  1739. $alt = $langs->trans('Call');
  1740. if ($option == 1)
  1741. $img = 'call';
  1742. else
  1743. $img = 'call_out';
  1744. return img_picto($alt, $img);
  1745. }
  1746. /**
  1747. * Show information for admin users
  1748. *
  1749. * @param string $text Text info
  1750. * @param string $infoonimgalt Info is shown only on alt of star picto, otherwise it is show on output after the star picto
  1751. * @return string String with info text
  1752. */
  1753. function info_admin($text, $infoonimgalt = 0) {
  1754. global $conf, $langs;
  1755. if ($infoonimgalt) {
  1756. return img_picto($text, 'star');
  1757. }
  1758. return '<div class="info">' . img_picto($langs->trans('InfoAdmin'), 'star') . ' ' . $text . '</div>';
  1759. }
  1760. /**
  1761. * Affiche message erreur system avec toutes les informations pour faciliter le diagnostic et la remontee des bugs.
  1762. * On doit appeler cette fonction quand une erreur technique bloquante est rencontree.
  1763. * Toutefois, il faut essayer de ne l'appeler qu'au sein de pages php, les classes devant
  1764. * renvoyer leur erreur par l'intermediaire de leur propriete "error".
  1765. *
  1766. * @param DoliDB $db Database handler
  1767. * @param string $error String or array of errors strings to show
  1768. * @return void
  1769. * @see dol_htmloutput_errors
  1770. */
  1771. function dol_print_error($db = '', $error = '') {
  1772. global $conf, $langs, $argv;
  1773. global $dolibarr_main_prod;
  1774. $out = '';
  1775. $syslog = '';
  1776. // Si erreur intervenue avant chargement langue
  1777. if (!$langs) {
  1778. require_once DOL_DOCUMENT_ROOT . '/core/class/translate.class.php';
  1779. $langs = new Translate();
  1780. $langs->load("main");
  1781. }
  1782. $langs->load("main");
  1783. $langs->load("errors");
  1784. if ($_SERVER['DOCUMENT_ROOT']) { // Mode web
  1785. //$out.=$langs->trans("SpeedealingHasDetectedError") . ".<br>\n";
  1786. if (!empty($conf->global->MAIN_FEATURES_LEVEL))
  1787. $out.="You use an experimental level of features, so please do NOT report any bugs, anywhere, until going back to MAIN_FEATURES_LEVEL = 0.<br>\n";
  1788. $out.=$langs->trans("InformationToHelpDiagnose") . ":<br>\n";
  1789. $out.="<b>" . $langs->trans("Date") . ":</b> " . dol_print_date(time(), 'dayhourlog') . "<br>\n";
  1790. ;
  1791. $out.="<b>" . $langs->trans("Speedealing") . ":</b> " . DOL_VERSION . "<br>\n";
  1792. ;
  1793. if (isset($conf->global->MAIN_FEATURES_LEVEL))
  1794. $out.="<b>" . $langs->trans("LevelOfFeature") . ":</b> " . $conf->global->MAIN_FEATURES_LEVEL . "<br>\n";;
  1795. if (function_exists("phpversion")) {
  1796. $out.="<b>" . $langs->trans("PHP") . ":</b> " . phpversion() . "<br>\n";
  1797. //phpinfo(); // This is to show location of php.ini file
  1798. }
  1799. $out.="<b>" . $langs->trans("Server") . ":</b> " . $_SERVER["SERVER_SOFTWARE"] . "<br>\n";
  1800. ;
  1801. $out.="<br>\n";
  1802. $out.="<b>" . $langs->trans("RequestedUrl") . ":</b> " . $_SERVER["REQUEST_URI"] . "<br>\n";
  1803. ;
  1804. $out.="<b>" . $langs->trans("Referer") . ":</b> " . (isset($_SERVER["HTTP_REFERER"]) ? $_SERVER["HTTP_REFERER"] : '') . "<br>\n";
  1805. ;
  1806. $out.="<br>\n";
  1807. $syslog.="url=" . $_SERVER["REQUEST_URI"];
  1808. $syslog.=", query_string=" . $_SERVER["QUERY_STRING"];
  1809. } else { // Mode CLI
  1810. $out.='> ' . $langs->transnoentities("ErrorInternalErrorDetected") . ":\n" . $argv[0] . "\n";
  1811. $syslog.="pid=" . getmypid();
  1812. }
  1813. if (is_object($db)) {
  1814. if ($_SERVER['DOCUMENT_ROOT']) { // Mode web
  1815. $out.="<b>" . $langs->trans("DatabaseTypeManager") . ":</b> " . $db->type . "<br>\n";
  1816. $out.="<b>" . $langs->trans("RequestLastAccessInError") . ":</b> " . ($db->lastqueryerror() ? $db->lastqueryerror() : $langs->trans("ErrorNoRequestInError")) . "<br>\n";
  1817. $out.="<b>" . $langs->trans("ReturnCodeLastAccessInError") . ":</b> " . ($db->lasterrno() ? $db->lasterrno() : $langs->trans("ErrorNoRequestInError")) . "<br>\n";
  1818. $out.="<b>" . $langs->trans("InformationLastAccessInError") . ":</b> " . ($db->lasterror() ? $db->lasterror() : $langs->trans("ErrorNoRequestInError")) . "<br>\n";
  1819. $out.="<br>\n";
  1820. } else { // Mode CLI
  1821. $out.='> ' . $langs->transnoentities("DatabaseTypeManager") . ":\n" . $db->type . "\n";
  1822. $out.='> ' . $langs->transnoentities("RequestLastAccessInError") . ":\n" . ($db->lastqueryerror() ? $db->lastqueryerror() : $langs->trans("ErrorNoRequestInError")) . "\n";
  1823. $out.='> ' . $langs->transnoentities("ReturnCodeLastAccessInError") . ":\n" . ($db->lasterrno() ? $db->lasterrno() : $langs->trans("ErrorNoRequestInError")) . "\n";
  1824. $out.='> ' . $langs->transnoentities("InformationLastAccessInError") . ":\n" . ($db->lasterror() ? $db->lasterror() : $langs->trans("ErrorNoRequestInError")) . "\n";
  1825. }
  1826. $syslog.=", sql=" . $db->lastquery();
  1827. $syslog.=", db_error=" . $db->lasterror();
  1828. }
  1829. if ($error) {
  1830. $langs->load("errors");
  1831. if (is_array($error))
  1832. $errors = $error;
  1833. else
  1834. $errors = array($error);
  1835. foreach ($errors as $msg) {
  1836. $msg = $langs->trans($msg);
  1837. if ($_SERVER['DOCUMENT_ROOT']) { // Mode web
  1838. $out.="<b>" . $langs->trans("Message") . ":</b> " . $msg . "<br>\n";
  1839. } else { // Mode CLI
  1840. $out.='> ' . $langs->transnoentities("Message") . ":\n" . $msg . "\n";
  1841. }
  1842. $syslog.=", msg=" . $msg;
  1843. }
  1844. }
  1845. if (empty($dolibarr_main_prod) && $_SERVER['DOCUMENT_ROOT'] && function_exists('xdebug_print_function_stack') && function_exists('xdebug_call_file')) {
  1846. xdebug_print_function_stack();
  1847. $out.='<b>XDebug informations:</b>' . "<br>\n";
  1848. $out.='File: ' . xdebug_call_file() . "<br>\n";
  1849. $out.='Line: ' . xdebug_call_line() . "<br>\n";
  1850. $out.='Function: ' . xdebug_call_function() . "<br>\n";
  1851. $out.="<br>\n";
  1852. }
  1853. if (empty($dolibarr_main_prod))
  1854. print $out;
  1855. else
  1856. define("MAIN_CORE_ERROR", 1);
  1857. error_log($out);
  1858. }
  1859. /**
  1860. * Show email to contact if technical error
  1861. *
  1862. * @return void
  1863. */
  1864. function dol_print_error_email() {
  1865. global $langs, $conf;
  1866. $langs->load("errors");
  1867. $now = dol_now();
  1868. print '<br><div class="error">' . $langs->trans("ErrorContactEMail", $conf->global->MAIN_INFO_SOCIETE_MAIL, 'ERRORNEWPAYMENT' . dol_print_date($now, '%Y%m%d')) . '</div>';
  1869. }
  1870. /**
  1871. * Show title line of an array
  1872. *
  1873. * @param string $name Label of field
  1874. * @param string $file Url used when we click on sort picto
  1875. * @param string $field Field to use for new sorting
  1876. * @param string $begin ("" by defaut)
  1877. * @param string $moreparam Add more parameters on sort url links ("" by default)
  1878. * @param string $td Options of attribute td ("" by defaut)
  1879. * @param string $sortfield Current field used to sort
  1880. * @param string $sortorder Current sort order
  1881. * @return void
  1882. */
  1883. function print_liste_field_titre($name, $file = "", $field = "", $begin = "", $moreparam = "", $td = "", $sortfield = "", $sortorder = "") {
  1884. print getTitleFieldOfList($name, 0, $file, $field, $begin, $moreparam, $td, $sortfield, $sortorder);
  1885. }
  1886. /**
  1887. * Get title line of an array
  1888. *
  1889. * @param string $name Label of field
  1890. * @param int $thead For thead format
  1891. * @param string $file Url used when we click on sort picto
  1892. * @param string $field Field to use for new sorting. Empty if this field is not sortable.
  1893. * @param string $begin ("" by defaut)
  1894. * @param string $moreparam Add more parameters on sort url links ("" by default)
  1895. * @param string $moreattrib Add more attributes on th ("" by defaut)
  1896. * @param string $sortfield Current field used to sort
  1897. * @param string $sortorder Current sort order
  1898. * @return void
  1899. */
  1900. function getTitleFieldOfList($name, $thead = 0, $file = "", $field = "", $begin = "", $moreparam = "", $moreattrib = "", $sortfield = "", $sortorder = "") {
  1901. global $conf;
  1902. //print "$name, $file, $field, $begin, $options, $moreattrib, $sortfield, $sortorder<br>\n";
  1903. $out = '';
  1904. // If field is used as sort criteria we use a specific class
  1905. // Example if (sortfield,field)=("nom","xxx.nom") or (sortfield,field)=("nom","nom")
  1906. if ($field && ($sortfield == $field || $sortfield == preg_replace("/^[^\.]+\./", "", $field))) {
  1907. $out.= '<th class="liste_titre_sel" ' . $moreattrib . '>';
  1908. } else {
  1909. $out.= '<th class="liste_titre" ' . $moreattrib . '>';
  1910. }
  1911. $out.=$name;
  1912. if (empty($thead) && $field) { // If this is a sort field
  1913. $options = preg_replace('/sortfield=([a-zA-Z0-9,\s\.]+)/i', '', $moreparam);
  1914. $options = preg_replace('/sortorder=([a-zA-Z0-9,\s\.]+)/i', '', $options);
  1915. $options = preg_replace('/&+/i', '&', $options);
  1916. if (!preg_match('/^&/', $options))
  1917. $options = '&' . $options;
  1918. //print "&nbsp;";
  1919. $out.= '<img width="2" src="' . DOL_URL_ROOT . '/theme/common/transparent.png" alt="">';
  1920. if (!$sortorder) {
  1921. $out.= '<a href="' . $file . '?sortfield=' . $field . '&sortorder=asc&begin=' . $begin . $options . '">' . img_down("A-Z", 0) . '</a>';
  1922. $out.= '<a href="' . $file . '?sortfield=' . $field . '&sortorder=desc&begin=' . $begin . $options . '">' . img_up("Z-A", 0) . '</a>';
  1923. } else {
  1924. if ($field != $sortfield) {
  1925. $out.= '<a href="' . $file . '?sortfield=' . $field . '&sortorder=asc&begin=' . $begin . $options . '">' . img_down("A-Z", 0) . '</a>';
  1926. $out.= '<a href="' . $file . '?sortfield=' . $field . '&sortorder=desc&begin=' . $begin . $options . '">' . img_up("Z-A", 0) . '</a>';
  1927. } else {
  1928. $sortorder = strtoupper($sortorder);
  1929. if ($sortorder == 'DESC') {
  1930. $out.= '<a href="' . $file . '?sortfield=' . $field . '&sortorder=asc&begin=' . $begin . $options . '">' . img_down("A-Z", 0) . '</a>';
  1931. $out.= '<a href="' . $file . '?sortfield=' . $field . '&sortorder=desc&begin=' . $begin . $options . '">' . img_up("Z-A", 1) . '</a>';
  1932. }
  1933. if ($sortorder == 'ASC') {
  1934. $out.= '<a href="' . $file . '?sortfield=' . $field . '&sortorder=asc&begin=' . $begin . $options . '">' . img_down("A-Z", 1) . '</a>';
  1935. $out.= '<a href="' . $file . '?sortfield=' . $field . '&sortorder=desc&begin=' . $begin . $options . '">' . img_up("Z-A", 0) . '</a>';
  1936. }
  1937. }
  1938. }
  1939. }
  1940. $out.='</th>';
  1941. return $out;
  1942. }
  1943. /**
  1944. * Show a title (deprecated. use print_fiche_titre instrad)
  1945. *
  1946. * @param string $title Title to show
  1947. * @return string Title to show
  1948. */
  1949. function print_titre($title) {
  1950. print '<div class="titre">' . $title . '</div>';
  1951. }
  1952. /**
  1953. * Start a box
  1954. *
  1955. * @param string $title Title of the box
  1956. * @param array $head list of top menu on box
  1957. * @param boolean $box_action Enable or Disable buttons reduse and delete box
  1958. * @return string Title to show
  1959. */
  1960. function start_box($title, $cssClass = 'icon-object-default', $menu = array(), $box_action = true) {
  1961. if (!empty($title)) {
  1962. $rtr = "";
  1963. $rtr.= '<fieldset class="fieldset">';
  1964. $rtr.= '<legend class="no-margin-bottom anthracite large left-icon ' . $cssClass . '">' . $title;
  1965. $rtr.= '</legend>';
  1966. //$rtr.= '<h3 class="green left-icon-big relative ' . $cssClass . '">' . $title;
  1967. if (count($menu) > 0 && $box_action) {
  1968. $rtr.= '<div class="relative margin-bottom">';
  1969. if (count($menu) == 1)
  1970. if (isset($menu[0]->href))
  1971. $rtr.= '<a href="' . $menu[0]->href . '" class="absolute-right compact button with-tooltip ' . $menu[0]->icon . '" id="' . $menu[0]->id . '" onclick="' . $menu[0]->onclick . '" title="' . $menu[0]->title . '"></a>';
  1972. else
  1973. $rtr.= '<button class="absolute-right compact button with-tooltip ' . $menu[0]->icon . '" id="' . $menu[0]->id . '" onclick="' . $menu[0]->onclick . '" title="' . $menu[0]->title . '"></button>';
  1974. else {
  1975. $rtr.= '<div class="button-group absolute-right compact children-tooltip">';
  1976. foreach ($menu as $aRow)
  1977. if (isset($aRow->href))
  1978. $rtr.= '<a href="' . $aRow->href . '" class="button ' . $aRow->icon . '" id="' . $aRow->id . '" onclick="' . $aRow->onclick . '" title="' . $aRow->title . '"></a>';
  1979. else
  1980. $rtr.= '<button class="button ' . $aRow->icon . '" id="' . $aRow->id . '" onclick="' . $aRow->onclick . '" title="' . $aRow->title . '"></button>';
  1981. /* <a href="#" class="button icon-pencil">Edit</a>
  1982. <a href="#" class="button icon-gear with-tooltip" title="Other actions"></a>
  1983. <a href="#" class="button icon-trash with-tooltip confirm" title="Delete"></a> */
  1984. $rtr.='</div>';
  1985. }
  1986. $rtr.= '</div>';
  1987. }
  1988. }
  1989. return $rtr;
  1990. }
  1991. /**
  1992. * End of a box
  1993. *
  1994. * @return string Title to show
  1995. */
  1996. function end_box() {
  1997. return '</fieldset>';
  1998. }
  1999. function column_start($nbcolumn = "tweleve", $cssClass = "") {
  2000. switch ($nbcolumn) {
  2001. case "two" :
  2002. $rtr = '<div class="' . $cssClass . ' two-columns four-columns-mobile-landscape six-columns-mobile-portrait">';
  2003. break;
  2004. case "four" :
  2005. $rtr = '<div class="' . $cssClass . ' four-columns six-columns-tablet twelve-columns-mobile">';
  2006. break;
  2007. case "six" :
  2008. $rtr = '<div class="' . $cssClass . ' six-columns twelve-columns-mobile">';
  2009. break;
  2010. default :
  2011. $rtr = '<div class="twelve-columns">';
  2012. }
  2013. return $rtr;
  2014. }
  2015. function column_end() {
  2016. return "</div>";
  2017. }
  2018. /**
  2019. * Show a title with picto
  2020. *
  2021. * @param string $titre Title to show
  2022. * @param string $mesg Added message to show on right
  2023. * @param string $picto Icon to use before title (should be a 32x32 transparent png file)
  2024. * @param int $pictoisfullpath 1=Icon name is a full absolute url of image
  2025. * @param int $id To force an id on html objects
  2026. * @return void
  2027. */
  2028. function print_fiche_titre($title, $showDate = false) {
  2029. global $langs;
  2030. if ($showDate)
  2031. $now = dol_now();
  2032. ?>
  2033. <hgroup id="main-title" class="thin">
  2034. <h1><?php echo $title; ?></h1>
  2035. <?php if ($showDate): ?>
  2036. <h2><?php echo strtolower($langs->trans(date('F', strtotime($now)))); ?> <strong><?php echo date('d', strtotime($now)); ?></strong></h2>
  2037. <?php endif ?>
  2038. </hgroup>
  2039. <?php
  2040. }
  2041. /**
  2042. * Load a title with picto
  2043. *
  2044. * @param string $titre Title to show
  2045. * @param string $mesg Added message to show on right
  2046. * @param string $picto Icon to use before title (should be a 32x32 transparent png file)
  2047. * @param int $pictoisfullpath 1=Icon name is a full absolute url of image
  2048. * @param int $id To force an id on html objects
  2049. * @return void
  2050. */
  2051. function load_fiche_titre($titre, $mesg = '', $picto = 'title.png', $pictoisfullpath = 0, $id = '') {
  2052. global $conf;
  2053. $return = '';
  2054. if ($picto == 'setup')
  2055. $picto = 'title.png';
  2056. if (!empty($conf->browser->ie) && $picto == 'title.png')
  2057. $picto = 'title.gif';
  2058. $return.= "\n";
  2059. $return.= '<table ' . ($id ? 'id="' . $id . '" ' : '') . 'summary="" width="100%" border="0" class="notopnoleftnoright" style="margin-bottom: 2px;"><tr>';
  2060. if ($picto)
  2061. $return.= '<td class="nobordernopadding hideonsmartphone" width="40" align="left" valign="middle">' . img_picto('', $picto, 'id="pictotitle"', $pictoisfullpath) . '</td>';
  2062. $return.= '<td class="nobordernopadding" valign="middle">';
  2063. $return.= '<div class="titre">' . $titre . '</div>';
  2064. $return.= '</td>';
  2065. if (dol_strlen($mesg)) {
  2066. $return.= '<td class="nobordernopadding" align="right" valign="middle"><b>' . $mesg . '</b></td>';
  2067. }
  2068. $return.= '</tr></table>' . "\n";
  2069. return $return;
  2070. }
  2071. /**
  2072. * Print a title with navigation controls for pagination
  2073. *
  2074. * @param string $titre Title to show (required)
  2075. * @param string $page Numero of page (required)
  2076. * @param string $file Url of page (required)
  2077. * @param string $options parametres complementaires lien ('' par defaut)
  2078. * @param string $sortfield champ de tri ('' par defaut)
  2079. * @param string $sortorder ordre de tri ('' par defaut)
  2080. * @param string $center chaine du centre ('' par defaut)
  2081. * @param int $num number of records found by select with limit+1
  2082. * @param int $totalnboflines Total number of records/lines for all pages (if known)
  2083. * @param string $picto Icon to use before title (should be a 32x32 transparent png file)
  2084. * @param int $pictoisfullpath 1=Icon name is a full absolute url of image
  2085. * @return void
  2086. */
  2087. function print_barre_liste($titre, $page, $file, $options = '', $sortfield = '', $sortorder = '', $center = '', $num = -1, $totalnboflines = 0, $picto = 'title.png', $pictoisfullpath = 0) {
  2088. global $conf, $langs;
  2089. if ($picto == 'setup')
  2090. $picto = 'title.png';
  2091. if (!empty($conf->browser->ie) && $picto == 'title.png')
  2092. $picto = 'title.gif';
  2093. if ($num > $conf->liste_limit or $num == -1) {
  2094. $nextpage = 1;
  2095. } else {
  2096. $nextpage = 0;
  2097. }
  2098. print "\n";
  2099. print "<!-- Begin title '" . $titre . "' -->\n";
  2100. print '<table width="100%" border="0" class="notopnoleftnoright" style="margin-bottom: 2px;"><tr>';
  2101. $pagelist = '';
  2102. // Left
  2103. if ($page > 0 || $num > $conf->liste_limit) {
  2104. if ($totalnboflines) {
  2105. if ($picto && $titre)
  2106. print '<td class="nobordernopadding" width="40" align="left" valign="middle">' . img_picto('', $picto, '', $pictoisfullpath) . '</td>';
  2107. print '<td class="nobordernopadding">';
  2108. print '<div class="titre">' . $titre . '</div>';
  2109. print '</td>';
  2110. $maxnbofpage = 10;
  2111. $nbpages = ceil($totalnboflines / $conf->liste_limit);
  2112. $cpt = ($page - $maxnbofpage);
  2113. if ($cpt < 0) {
  2114. $cpt = 0;
  2115. }
  2116. $pagelist.=$langs->trans('Page');
  2117. if ($cpt >= 1) {
  2118. $pagelist.=' <a href="' . $file . '?page=0' . $options . '&amp;sortfield=' . $sortfield . '&amp;sortorder=' . $sortorder . '">1</a>';
  2119. if ($cpt >= 2)
  2120. $pagelist.=' ...';
  2121. }
  2122. do {
  2123. if ($cpt == $page) {
  2124. $pagelist.= ' <u>' . ($page + 1) . '</u>';
  2125. } else {
  2126. $pagelist.= ' <a href="' . $file . '?page=' . $cpt . $options . '&amp;sortfield=' . $sortfield . '&amp;sortorder=' . $sortorder . '">' . ($cpt + 1) . '</a>';
  2127. }
  2128. $cpt++;
  2129. } while ($cpt < $nbpages && $cpt <= $page + $maxnbofpage);
  2130. if ($cpt < $nbpages) {
  2131. if ($cpt < $nbpages - 1)
  2132. $pagelist.= ' ...';
  2133. $pagelist.= ' <a href="' . $file . '?page=' . ($nbpages - 1) . $options . '&amp;sortfield=' . $sortfield . '&amp;sortorder=' . $sortorder . '">' . $nbpages . '</a>';
  2134. }
  2135. }
  2136. else {
  2137. if (empty($conf->browser->phone) && $picto && $titre)
  2138. print '<td class="nobordernopadding" width="40" align="left" valign="middle">' . img_picto('', $picto, '', $pictoisfullpath) . '</td>';
  2139. print '<td class="nobordernopadding">';
  2140. print '<div class="titre">' . $titre . '</div>';
  2141. $pagelist.= $langs->trans('Page') . ' ' . ($page + 1);
  2142. print '</td>';
  2143. }
  2144. }
  2145. else {
  2146. if (empty($conf->browser->phone) && $picto && $titre)
  2147. print '<td class="nobordernopadding" width="40" align="left" valign="middle">' . img_picto('', $picto, '', $pictoisfullpath) . '</td>';
  2148. print '<td class="nobordernopadding"><div class="titre">' . $titre . '</div></td>';
  2149. }
  2150. // Center
  2151. if ($center) {
  2152. print '<td class="nobordernopadding" align="left" valign="middle">' . $center . '</td>';
  2153. }
  2154. // Right
  2155. print '<td class="nobordernopadding" align="right" valign="middle">';
  2156. if ($sortfield)
  2157. $options .= "&amp;sortfield=" . $sortfield;
  2158. if ($sortorder)
  2159. $options .= "&amp;sortorder=" . $sortorder;
  2160. // Affichage des fleches de navigation
  2161. print_fleche_navigation($page, $file, $options, $nextpage, $pagelist);
  2162. print '</td>';
  2163. print '</tr></table>' . "\n";
  2164. print "<!-- End title -->\n\n";
  2165. }
  2166. /**
  2167. * Fonction servant a afficher les fleches de navigation dans les pages de listes
  2168. *
  2169. * @param int $page Numero of page
  2170. * @param string $file Lien
  2171. * @param string $options Autres parametres d'url a propager dans les liens ("" par defaut)
  2172. * @param int $nextpage Faut-il une page suivante
  2173. * @param string $betweenarrows HTML Content to show between arrows
  2174. * @return void
  2175. */
  2176. function print_fleche_navigation($page, $file, $options = '', $nextpage = 0, $betweenarrows = '') {
  2177. global $conf, $langs;
  2178. if ($page > 0) {
  2179. print '<a href="' . $file . '?page=' . ($page - 1) . $options . '">' . img_previous($langs->trans("Previous")) . '</a>';
  2180. }
  2181. if ($betweenarrows)
  2182. print ($page > 0 ? ' ' : '') . $betweenarrows . ($nextpage > 0 ? ' ' : '');
  2183. if ($nextpage > 0) {
  2184. print '<a href="' . $file . '?page=' . ($page + 1) . $options . '">' . img_next($langs->trans("Next")) . '</a>';
  2185. }
  2186. }
  2187. /**
  2188. * Return a string with VAT rate label formated for view output
  2189. * Used into pdf and HTML pages
  2190. *
  2191. * @param float $rate Rate value to format (19.6 19,6 19.6% 19,6%,...)
  2192. * @param boolean $addpercent Add a percent % sign in output
  2193. * @param int $info_bits Miscellanous information on vat (0=Default, 1=French NPR vat)
  2194. * @param int $usestarfornpr 1=Use '*' for NPR vat rate intead of MAIN_LABEL_MENTION_NPR
  2195. * @return string String with formated amounts (19,6 or 19,6% or 8.5% NPR or 8.5% *)
  2196. */
  2197. function vatrate($rate, $addpercent = false, $info_bits = 0, $usestarfornpr = 0) {
  2198. // Test for compatibility
  2199. if (preg_match('/%/', $rate)) {
  2200. $rate = str_replace('%', '', $rate);
  2201. $addpercent = true;
  2202. }
  2203. if (preg_match('/\*/', $rate) || preg_match('/' . constant('MAIN_LABEL_MENTION_NPR') . '/i', $rate)) {
  2204. $rate = str_replace('*', '', $rate);
  2205. $info_bits |= 1;
  2206. }
  2207. $ret = price($rate, 0, '', 0, 0) . ($addpercent ? '%' : '');
  2208. if ($info_bits & 1)
  2209. $ret.=' ' . ($usestarfornpr ? '*' : constant('MAIN_LABEL_MENTION_NPR'));
  2210. return $ret;
  2211. }
  2212. /**
  2213. * Fonction qui formate un montant pour visualisation
  2214. * Fonction utilisee dans les pdf et les pages html
  2215. *
  2216. * @param float $amount Montant a formater
  2217. * @param string $form Type de formatage, html ou pas (par defaut)
  2218. * @param Translate $outlangs Objet langs pour formatage text
  2219. * @param int $trunc 1=Tronque affichage si trop de decimales,0=Force le non troncage
  2220. * @param int $rounding Minimum number of decimal. If not defined we use min($conf->global->MAIN_MAX_DECIMALS_UNIT,$conf->global->MAIN_MAX_DECIMALS_TOTAL)
  2221. * @param int $forcerounding Force the number of decimal
  2222. * @return string Chaine avec montant formate
  2223. *
  2224. * @see price2num Revert function of price
  2225. */
  2226. function price($amount, $form = 0, $outlangs = '', $trunc = 1, $rounding = -1, $forcerounding = -1) {
  2227. global $langs, $conf;
  2228. // Clean parameters
  2229. if (empty($amount))
  2230. $amount = 0; // To have a numeric value if amount not defined or = ''
  2231. if ($rounding < 0)
  2232. $rounding = min($conf->global->MAIN_MAX_DECIMALS_UNIT, $conf->global->MAIN_MAX_DECIMALS_TOT);
  2233. $nbdecimal = $rounding;
  2234. // Output separators by default (french)
  2235. $dec = ',';
  2236. $thousand = ' ';
  2237. // If $outlangs not forced, we use use language
  2238. if (!is_object($outlangs))
  2239. $outlangs = $langs;
  2240. if ($outlangs->trans("SeparatorDecimal") != "SeparatorDecimal")
  2241. $dec = $outlangs->trans("SeparatorDecimal");
  2242. if ($outlangs->trans("SeparatorThousand") != "SeparatorThousand")
  2243. $thousand = $outlangs->trans("SeparatorThousand");
  2244. if ($thousand == 'None')
  2245. $thousand = '';
  2246. //print "amount=".$amount." html=".$form." trunc=".$trunc." nbdecimal=".$nbdecimal." dec='".$dec."' thousand='".$thousand."'<br>";
  2247. //print "amount=".$amount."-";
  2248. $amount = str_replace(',', '.', $amount); // should be useless
  2249. //print $amount."-";
  2250. $datas = explode('.', $amount);
  2251. $decpart = isset($datas[1]) ? $datas[1] : '';
  2252. $decpart = preg_replace('/0+$/i', '', $decpart); // Supprime les 0 de fin de partie decimale
  2253. //print "decpart=".$decpart."<br>";
  2254. $end = '';
  2255. // We increase nbdecimal if there is more decimal than asked (to not loose information)
  2256. if (dol_strlen($decpart) > $nbdecimal)
  2257. $nbdecimal = dol_strlen($decpart);
  2258. // Si on depasse max
  2259. if ($trunc && $nbdecimal > $conf->global->MAIN_MAX_DECIMALS_SHOWN) {
  2260. $nbdecimal = $conf->global->MAIN_MAX_DECIMALS_SHOWN;
  2261. if (preg_match('/\.\.\./i', $conf->global->MAIN_MAX_DECIMALS_SHOWN)) {
  2262. // Si un affichage est tronque, on montre des ...
  2263. $end = '...';
  2264. }
  2265. }
  2266. // If force rounding
  2267. if ($forcerounding >= 0)
  2268. $nbdecimal = $forcerounding;
  2269. // Format number
  2270. if ($form) {
  2271. $output = preg_replace('/\s/', '&nbsp;', number_format($amount, $nbdecimal, $dec, $thousand));
  2272. } else {
  2273. $output = number_format($amount, $nbdecimal, $dec, $thousand);
  2274. }
  2275. $output.=$end;
  2276. return $output;
  2277. }
  2278. /**
  2279. * Function that return a number with universal decimal format (decimal separator is '.') from
  2280. * an amount typed by a user.
  2281. * Function to use on each input amount before any numeric test or database insert
  2282. *
  2283. * @param float $amount Amount to convert/clean
  2284. * @param string $rounding ''=No rounding
  2285. * 'MU'=Round to Max unit price (MAIN_MAX_DECIMALS_UNIT)
  2286. * 'MT'=Round to Max for totals with Tax (MAIN_MAX_DECIMALS_TOT)
  2287. * 'MS'=Round to Max Shown (MAIN_MAX_DECIMALS_SHOWN)
  2288. * @param int $alreadysqlnb Put 1 if you know that content is already universal format number
  2289. * @return string Amount with universal numeric format (Example: '99.99999')
  2290. *
  2291. * @see price Opposite function of price2num
  2292. */
  2293. function price2num($amount, $rounding = '', $alreadysqlnb = 0) {
  2294. global $langs, $conf;
  2295. // Round PHP function does not allow number like '1,234.56' nor '1.234,56' nor '1 234,56'
  2296. // Numbers must be '1234.56'
  2297. // Decimal delimiter for PHP and database SQL requests must be '.'
  2298. $dec = ',';
  2299. $thousand = ' ';
  2300. if ($langs->trans("SeparatorDecimal") != "SeparatorDecimal")
  2301. $dec = $langs->trans("SeparatorDecimal");
  2302. if ($langs->trans("SeparatorThousand") != "SeparatorThousand")
  2303. $thousand = $langs->trans("SeparatorThousand");
  2304. if ($thousand == 'None')
  2305. $thousand = '';
  2306. //print "amount=".$amount." html=".$form." trunc=".$trunc." nbdecimal=".$nbdecimal." dec='".$dec."' thousand='".$thousand."'<br>";
  2307. // Convert value to universal number format (no thousand separator, '.' as decimal separator)
  2308. if ($alreadysqlnb != 1) { // If not a PHP number or unknown, we change format
  2309. //print 'PP'.$amount.' - '.$dec.' - '.$thousand.'<br>';
  2310. // Convert amount to format with dolibarr dec and thousand (this is because PHP convert a number
  2311. // to format defined by LC_NUMERIC after a calculation and we want source format to be like defined by Dolibarr setup.
  2312. if (is_numeric($amount)) {
  2313. // We put in temps value of decimal ("0.00001"). Works with 0 and 2.0E-5 and 9999.10
  2314. $temps = sprintf("%0.10F", $amount - intval($amount)); // temps=0.0000000000 or 0.0000200000 or 9999.1000000000
  2315. $temps = preg_replace('/([\.1-9])0+$/', '\\1', $temps); // temps=0. or 0.00002 or 9999.1
  2316. $nbofdec = max(0, dol_strlen($temps) - 2); // -2 to remove "0."
  2317. $amount = number_format($amount, $nbofdec, $dec, $thousand);
  2318. }
  2319. //print "QQ".$amount.'<br>';
  2320. // Now make replace (the main goal of function)
  2321. if ($thousand != ',' && $thousand != '.')
  2322. $amount = str_replace(',', '.', $amount); // To accept 2 notations for french users
  2323. $amount = str_replace(' ', '', $amount); // To avoid spaces
  2324. $amount = str_replace($thousand, '', $amount); // Replace of thousand before replace of dec to avoid pb if thousand is .
  2325. $amount = str_replace($dec, '.', $amount);
  2326. }
  2327. // Now, make a rounding if required
  2328. if ($rounding) {
  2329. $nbofdectoround = '';
  2330. if ($rounding == 'MU')
  2331. $nbofdectoround = $conf->global->MAIN_MAX_DECIMALS_UNIT;
  2332. elseif ($rounding == 'MT')
  2333. $nbofdectoround = $conf->global->MAIN_MAX_DECIMALS_TOT;
  2334. elseif ($rounding == 'MS')
  2335. $nbofdectoround = $conf->global->MAIN_MAX_DECIMALS_SHOWN;
  2336. elseif (is_numeric($rounding))
  2337. $nbofdectoround = $rounding; // For admin info page
  2338. //print "RR".$amount.' - '.$nbofdectoround.'<br>';
  2339. if (dol_strlen($nbofdectoround))
  2340. $amount = round($amount, $nbofdectoround); // $nbofdectoround can be 0.
  2341. else
  2342. return 'ErrorBadParameterProvidedToFunction';
  2343. //print 'SS'.$amount.' - '.$nbofdec.' - '.$dec.' - '.$thousand.' - '.$nbofdectoround.'<br>';
  2344. // Convert amount to format with dolibarr dec and thousand (this is because PHP convert a number
  2345. // to format defined by LC_NUMERIC after a calculation and we want source format to be defined by Dolibarr setup.
  2346. if (is_numeric($amount)) {
  2347. // We put in temps value of decimal ("0.00001"). Works with 0 and 2.0E-5 and 9999.10
  2348. $temps = sprintf("%0.10F", $amount - intval($amount)); // temps=0.0000000000 or 0.0000200000 or 9999.1000000000
  2349. $temps = preg_replace('/([\.1-9])0+$/', '\\1', $temps); // temps=0. or 0.00002 or 9999.1
  2350. $nbofdec = max(0, dol_strlen($temps) - 2); // -2 to remove "0."
  2351. $amount = number_format($amount, min($nbofdec, $nbofdectoround), $dec, $thousand); // Convert amount to format with dolibarr dec and thousand
  2352. }
  2353. //print "TT".$amount.'<br>';
  2354. // Always make replace because each math function (like round) replace
  2355. // with local values and we want a number that has a SQL string format x.y
  2356. if ($thousand != ',' && $thousand != '.')
  2357. $amount = str_replace(',', '.', $amount); // To accept 2 notations for french users
  2358. $amount = str_replace(' ', '', $amount); // To avoid spaces
  2359. $amount = str_replace($thousand, '', $amount); // Replace of thousand before replace of dec to avoid pb if thousand is .
  2360. $amount = str_replace($dec, '.', $amount);
  2361. }
  2362. return floatval($amount);
  2363. }
  2364. /**
  2365. * Return localtaxe rate for a particular vat
  2366. *
  2367. * @param float $tva Vat taxe
  2368. * @param int $local Local tax to search and return (1 or 2 return only tax rate 1 or tax rate 2)
  2369. * @param Societe $thirdparty_buyer Object of buying third party
  2370. * @param Societe $thirdparty_seller Object of selling third party
  2371. * @return int 0 if not found, localtax if found
  2372. */
  2373. function get_localtax($tva, $local, $thirdparty_buyer = "", $thirdparty_seller = "") {
  2374. global $db, $conf, $mysoc;
  2375. if (empty($thirdparty_seller) || !is_object($thirdparty_seller))
  2376. $thirdparty_seller = $mysoc;
  2377. dol_syslog("get_localtax tva=" . $tva . " local=" . $local . " thirdparty_buyer=" . (is_object($thirdparty_buyer) ? $thirdparty_buyer->id : '') . " thirdparty_seller=" . $thirdparty_seller->id);
  2378. // Some test to guess with no need to make database access
  2379. if ($local == 1 && !$thirdparty_seller->localtax1_assuj)
  2380. return 0;
  2381. if ($local == 2 && !$thirdparty_seller->localtax2_assuj)
  2382. return 0;
  2383. //if ($local == 0 && ! $thirdparty_seller->localtax1_assuj && ! $thirdparty_seller->localtax2_assuj) return array('localtax1'=>0,'localtax2'=>0);
  2384. $code_country = $thirdparty_seller->country_code;
  2385. if (is_object($thirdparty_buyer)) {
  2386. if ($code_country != $thirdparty_buyer->country_code)
  2387. return 0;
  2388. if ($local == 1 && !$thirdparty_buyer->localtax1_assuj)
  2389. return 0; // TODO Not sure this is good
  2390. elseif ($local == 2 && !$thirdparty_buyer->localtax2_assuj)
  2391. return 0; // TODO Not sure this is good
  2392. }
  2393. // Search local taxes
  2394. $sql = "SELECT t.localtax1, t.localtax2";
  2395. $sql .= " FROM " . MAIN_DB_PREFIX . "c_tva as t, " . MAIN_DB_PREFIX . "c_pays as p";
  2396. $sql .= " WHERE t.fk_pays = p.rowid AND p.code = '" . $code_country . "'";
  2397. $sql .= " AND t.taux = " . $tva . " AND t.active = 1";
  2398. dol_syslog("get_localtax sql=" . $sql);
  2399. $resql = $db->query($sql);
  2400. if ($resql) {
  2401. $obj = $db->fetch_object($resql);
  2402. if ($local == 1)
  2403. return $obj->localtax1;
  2404. elseif ($local == 2)
  2405. return $obj->localtax2;
  2406. //else return array($obj->localtax1,$obj->localtax2);
  2407. }
  2408. return 0;
  2409. }
  2410. /**
  2411. * Return vat rate of a product in a particular selling country or default country
  2412. * vat if product is unknown
  2413. *
  2414. * @param int $idprod Id of product or 0 if not a predefined product
  2415. * @param Societe $thirdparty_seller Thirdparty with a ->country_code defined (FR, US, IT, ...)
  2416. * @param int $idprodfournprice Id product_fournisseur_price (for supplier order/invoice)
  2417. * @return int <0 if KO, Vat rate if OK
  2418. * TODO May be this should be better as a method of product class
  2419. */
  2420. function get_product_vat_for_country($idprod, $thirdparty_seller, $idprodfournprice = 0) {
  2421. global $db, $mysoc;
  2422. if (!class_exists('Product')) {
  2423. require DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
  2424. }
  2425. $ret = 0;
  2426. $found = 0;
  2427. if ($idprod > 0) {
  2428. // Load product
  2429. $product = new Product($db);
  2430. $result = $product->fetch($idprod);
  2431. if ($mysoc->country_code == $thirdparty_seller->country_code) { // If selling country is ours
  2432. if ($idprodfournprice > 0) { // We want vat for product for a supplier order or invoice
  2433. $product->get_buyprice($idprodfournprice, 0, 0, 0);
  2434. $ret = $product->vatrate_supplier;
  2435. } else {
  2436. $ret = $product->tva_tx; // Default vat of product we defined
  2437. }
  2438. $found = 1;
  2439. } else {
  2440. // TODO Read default product vat according to countrycode and product
  2441. }
  2442. }
  2443. if (!$found) {
  2444. // If vat of product for the country not found or not defined, we return higher vat of country.
  2445. $sql = "SELECT taux as vat_rate";
  2446. $sql.= " FROM " . MAIN_DB_PREFIX . "c_tva as t, " . MAIN_DB_PREFIX . "c_pays as p";
  2447. $sql.= " WHERE t.active=1 AND t.fk_pays = p.rowid AND p.code='" . $thirdparty_seller->country_code . "'";
  2448. $sql.= " ORDER BY t.taux DESC, t.recuperableonly ASC";
  2449. $sql.= $db->plimit(1);
  2450. $resql = $db->query($sql);
  2451. if ($resql) {
  2452. $obj = $db->fetch_object($resql);
  2453. if ($obj) {
  2454. $ret = $obj->vat_rate;
  2455. }
  2456. }
  2457. else
  2458. dol_print_error($db);
  2459. }
  2460. dol_syslog("get_product_vat_for_country: ret=" . $ret);
  2461. return $ret;
  2462. }
  2463. /**
  2464. * Return localtax rate of a product in a particular selling country
  2465. *
  2466. * @param int $idprod Id of product
  2467. * @param int $local 1 for localtax1, 2 for localtax 2
  2468. * @param string $countrycode Country code (FR, US, IT, ...)
  2469. * @return int <0 if KO, Vat rate if OK
  2470. * TODO May be this should be better as a method of product class
  2471. */
  2472. function get_product_localtax_for_country($idprod, $local, $countrycode) {
  2473. global $db;
  2474. $product = new Product($db);
  2475. $product->fetch($idprod);
  2476. if ($local == 1)
  2477. return $product->localtax1_tx;
  2478. elseif ($local == 2)
  2479. return $product->localtax2_tx;
  2480. return -1;
  2481. }
  2482. /**
  2483. * Function that return vat rate of a product line (according to seller, buyer and product vat rate)
  2484. * Si vendeur non assujeti a TVA, TVA par defaut=0. Fin de regle.
  2485. * Si le (pays vendeur = pays acheteur) alors TVA par defaut=TVA du produit vendu. Fin de regle.
  2486. * Si (vendeur et acheteur dans Communaute europeenne) et (bien vendu = moyen de transports neuf comme auto, bateau, avion) alors TVA par defaut=0 (La TVA doit etre paye par acheteur au centre d'impots de son pays et non au vendeur). Fin de regle.
  2487. * Si (vendeur et acheteur dans Communaute europeenne) et (acheteur = particulier ou entreprise sans num TVA intra) alors TVA par defaut=TVA du produit vendu. Fin de regle
  2488. * Si (vendeur et acheteur dans Communaute europeenne) et (acheteur = entreprise avec num TVA) intra alors TVA par defaut=0. Fin de regle
  2489. * Sinon TVA proposee par defaut=0. Fin de regle.
  2490. *
  2491. * @param Societe $thirdparty_seller Objet societe vendeuse
  2492. * @param Societe $thirdparty_buyer Objet societe acheteuse
  2493. * @param int $idprod Id product
  2494. * @param int $idprodfournprice Id product_fournisseur_price (for supplier order/invoice)
  2495. * @return float Taux de tva a appliquer, -1 si ne peut etre determine
  2496. */
  2497. function get_default_tva($thirdparty_seller, $thirdparty_buyer, $idprod = 0, $idprodfournprice = 0) {
  2498. global $conf;
  2499. if (!is_object($thirdparty_seller))
  2500. return -1;
  2501. if (!is_object($thirdparty_buyer))
  2502. return -1;
  2503. dol_syslog("get_default_tva: seller use vat=" . $thirdparty_seller->tva_assuj . ", seller country=" . $thirdparty_seller->country_id . ", seller in cee=" . $thirdparty_seller->isInEEC() . ", buyer country=" . $thirdparty_buyer->country_id . ", 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 : ''));
  2504. // Si vendeur non assujeti a TVA (tva_assuj vaut 0/1 ou franchise/reel)
  2505. if (is_numeric($thirdparty_seller->tva_assuj) && !$thirdparty_seller->tva_assuj) {
  2506. //print 'VATRULE 1';
  2507. return 0;
  2508. }
  2509. if (!is_numeric($thirdparty_seller->tva_assuj) && $thirdparty_seller->tva_assuj == 'franchise') {
  2510. //print 'VATRULE 2';
  2511. return 0;
  2512. }
  2513. //if (is_object($thirdparty_buyer) && ($thirdparty_seller->country_id == $thirdparty_buyer->country_id) && ($thirdparty_buyer->tva_assuj == 1 || $thirdparty_buyer->tva_assuj == 'reel'))
  2514. // Le test ci-dessus ne devrait pas etre necessaire. Me signaler l'exemple du cas juridique concerne si le test suivant n'est pas suffisant.
  2515. // Si le (pays vendeur = pays acheteur) alors la TVA par defaut=TVA du produit vendu. Fin de regle.
  2516. if (($thirdparty_seller->country_id == $thirdparty_buyer->country_id) || (in_array($thirdparty_seller->country_id, array('FR,MC')) && in_array($thirdparty_buyer->country_id, array('FR', 'MC')))) { // Warning ->country_id not always defined
  2517. //print 'VATRULE 3';
  2518. return get_product_vat_for_country($idprod, $thirdparty_seller, $idprodfournprice);
  2519. }
  2520. // Si (vendeur et acheteur dans Communaute europeenne) et (bien vendu = moyen de transports neuf comme auto, bateau, avion) alors TVA par defaut=0 (La TVA doit etre paye par l'acheteur au centre d'impots de son pays et non au vendeur). Fin de regle.
  2521. // Non gere
  2522. // Si (vendeur et acheteur dans Communaute europeenne) et (acheteur = entreprise) alors TVA par defaut=0. Fin de regle
  2523. // Si (vendeur et acheteur dans Communaute europeenne) et (acheteur = particulier) alors TVA par defaut=TVA du produit vendu. Fin de regle
  2524. if (($thirdparty_seller->isInEEC() && $thirdparty_buyer->isInEEC())) {
  2525. $isacompany = $thirdparty_buyer->isACompany();
  2526. if ($isacompany) {
  2527. //print 'VATRULE 4';
  2528. return 0;
  2529. } else {
  2530. //print 'VATRULE 5';
  2531. return get_product_vat_for_country($idprod, $thirdparty_seller, $idprodfournprice);
  2532. }
  2533. }
  2534. // If services are eServices according to EU Council Directive 2002/38/EC (ec.europa.eu/taxation_customs/taxation/v.../article_1610_en.htm)
  2535. // we use the buyer VAT.
  2536. if (!empty($conf->global->SERVICE_ARE_ECOMMERCE_200238EC)) {
  2537. //print "eee".$thirdparty_buyer->isACompany();exit;
  2538. if (!$thirdparty_seller->isInEEC() && $thirdparty_buyer->isInEEC() && !$thirdparty_buyer->isACompany()) {
  2539. //print 'VATRULE 6';
  2540. return get_product_vat_for_country($idprod, $thirdparty_buyer, $idprodfournprice);
  2541. }
  2542. }
  2543. // Sinon la TVA proposee par defaut=0. Fin de regle.
  2544. // Rem: Cela signifie qu'au moins un des 2 est hors Communaute europeenne et que le pays differe
  2545. //print 'VATRULE 7';
  2546. return 0;
  2547. }
  2548. /**
  2549. * Fonction qui renvoie si tva doit etre tva percue recuperable
  2550. *
  2551. * @param Societe $thirdparty_seller Objet societe vendeuse
  2552. * @param Societe $thirdparty_buyer Objet societe acheteuse
  2553. * @param int $idprod Id product
  2554. * @return float 0 or 1
  2555. */
  2556. function get_default_npr($thirdparty_seller, $thirdparty_buyer, $idprod) {
  2557. return 0;
  2558. }
  2559. /**
  2560. * Function that return localtax of a product line (according to seller, buyer and product vat rate)
  2561. *
  2562. * @param Societe $thirdparty_seller Objet societe vendeuse
  2563. * @param Societe $thirdparty_buyer Objet societe acheteuse
  2564. * @param int $local Localtax to process (1 or 2)
  2565. * @param int $idprod Id product
  2566. * @return float Taux de localtax appliquer, -1 si ne peut etre determine
  2567. */
  2568. function get_default_localtax($thirdparty_seller, $thirdparty_buyer, $local, $idprod = 0) {
  2569. if (!is_object($thirdparty_seller))
  2570. return -1;
  2571. if (!is_object($thirdparty_buyer))
  2572. return -1;
  2573. if ($thirdparty_seller->country_id == 'ES' || $thirdparty_seller->country_code == 'ES') {
  2574. if ($local == 1) { //RE
  2575. // Si achatteur non assujeti a RE, localtax1 par default=0
  2576. if (is_numeric($thirdparty_buyer->localtax1_assuj) && !$thirdparty_buyer->localtax1_assuj)
  2577. return 0;
  2578. if (!is_numeric($thirdparty_buyer->localtax1_assuj) && $thirdparty_buyer->localtax1_assuj == 'localtax1off')
  2579. return 0;
  2580. }
  2581. elseif ($local == 2) { //IRPF
  2582. // Si vendeur non assujeti a IRPF, localtax2 par default=0
  2583. if (is_numeric($thirdparty_seller->localtax2_assuj) && !$thirdparty_seller->localtax2_assuj)
  2584. return 0;
  2585. if (!is_numeric($thirdparty_seller->localtax2_assuj) && $thirdparty_seller->localtax2_assuj == 'localtax2off')
  2586. return 0;
  2587. }
  2588. else
  2589. return -1;
  2590. if ($idprod)
  2591. return get_product_localtax_for_country($idprod, $local, $thirdparty_seller->country_code);
  2592. else
  2593. return -1;
  2594. }
  2595. return 0;
  2596. }
  2597. /**
  2598. * Return yes or no in current language
  2599. *
  2600. * @param string $yesno Value to test (1, 'yes', 'true' or 0, 'no', 'false')
  2601. * @param string $case 1=Yes/No, 0=yes/no
  2602. * @param int $color 0=texte only, 1=Text is formated with a color font style ('ok' or 'error'), 2=Text is formated with 'ok' color.
  2603. * @return string HTML string
  2604. */
  2605. function yn($yesno, $case = 1, $color = 0) {
  2606. global $langs;
  2607. $result = 'unknown';
  2608. if ($yesno == 1 || strtolower($yesno) == 'yes' || strtolower($yesno) == 'true') { // A mettre avant test sur no a cause du == 0
  2609. $result = ($case ? $langs->trans("Yes") : $langs->trans("yes"));
  2610. $classname = 'ok';
  2611. } elseif ($yesno == 0 || strtolower($yesno) == 'no' || strtolower($yesno) == 'false') {
  2612. $result = ($case ? $langs->trans("No") : $langs->trans("no"));
  2613. if ($color == 2)
  2614. $classname = 'ok';
  2615. else
  2616. $classname = 'error';
  2617. }
  2618. if ($color)
  2619. return '<font class="' . $classname . '">' . $result . '</font>';
  2620. return $result;
  2621. }
  2622. /**
  2623. * Return a path to have a directory according to an id
  2624. * Examples: '001' with level 3->"0/0/1/", '015' with level 3->"0/1/5/"
  2625. * Examples: 'ABC-1' with level 3 ->"0/0/1/", '015' with level 1->"5/"
  2626. *
  2627. * @param string $num Id to develop
  2628. * @param int $level Level of development (1, 2 or 3 level)
  2629. * @param int $alpha Use alpha ref
  2630. * @param int $withoutslash 0=With slash at end, 1=without slash at end
  2631. * @return string Dir to use
  2632. */
  2633. function get_exdir($num, $level = 3, $alpha = 0, $withoutslash = 0) {
  2634. $path = '';
  2635. if (empty($alpha))
  2636. $num = preg_replace('/([^0-9])/i', '', $num);
  2637. else
  2638. $num = preg_replace('/^.*\-/i', '', $num);
  2639. $num = substr("000" . $num, -$level);
  2640. if ($level == 1)
  2641. $path = substr($num, 0, 1);
  2642. if ($level == 2)
  2643. $path = substr($num, 1, 1) . '/' . substr($num, 0, 1);
  2644. if ($level == 3)
  2645. $path = substr($num, 2, 1) . '/' . substr($num, 1, 1) . '/' . substr($num, 0, 1);
  2646. if (empty($withoutslash))
  2647. $path.='/';
  2648. return $path;
  2649. }
  2650. /**
  2651. * Creation of a directory (this can create recursive subdir)
  2652. *
  2653. * @param string $dir Directory to create (Separator must be '/'. Example: '/mydir/mysubdir')
  2654. * @param string $dataroot Data root directory (To avoid having the data root in the loop. Using this will also lost the warning on first dir PHP has no permission when open_basedir is used)
  2655. * @return int < 0 if KO, 0 = already exists, > 0 if OK
  2656. */
  2657. function dol_mkdir($dir, $dataroot = '') {
  2658. global $conf;
  2659. dol_syslog("functions.lib::dol_mkdir: dir=" . $dir, LOG_INFO);
  2660. $dir_osencoded = dol_osencode($dir);
  2661. if (@is_dir($dir_osencoded))
  2662. return 0;
  2663. $nberr = 0;
  2664. $nbcreated = 0;
  2665. $ccdir = '';
  2666. if (!empty($dataroot)) {
  2667. // Remove data root from loop
  2668. $dir = str_replace($dataroot . '/', '', $dir);
  2669. $ccdir = $dataroot . '/';
  2670. }
  2671. $cdir = explode("/", $dir);
  2672. $num = count($cdir);
  2673. for ($i = 0; $i < $num; $i++) {
  2674. if ($i > 0)
  2675. $ccdir .= '/' . $cdir[$i];
  2676. else
  2677. $ccdir .= $cdir[$i];
  2678. if (preg_match("/^.:$/", $ccdir, $regs))
  2679. continue; // Si chemin Windows incomplet, on poursuit par rep suivant
  2680. // Attention, le is_dir() peut echouer bien que le rep existe.
  2681. // (ex selon config de open_basedir)
  2682. if ($ccdir) {
  2683. $ccdir_osencoded = dol_osencode($ccdir);
  2684. if (!@is_dir($ccdir_osencoded)) {
  2685. dol_syslog("functions.lib::dol_mkdir: Directory '" . $ccdir . "' does not exists or is outside open_basedir PHP setting.", LOG_DEBUG);
  2686. umask(0);
  2687. $dirmaskdec = octdec('0755');
  2688. if (!empty($conf->global->MAIN_UMASK))
  2689. $dirmaskdec = octdec($conf->global->MAIN_UMASK);
  2690. $dirmaskdec |= octdec('0111'); // Set x bit required for directories
  2691. if (!@mkdir($ccdir_osencoded, $dirmaskdec)) {
  2692. // Si le is_dir a renvoye une fausse info, alors on passe ici.
  2693. dol_syslog("functions.lib::dol_mkdir: Fails to create directory '" . $ccdir . "' or directory already exists.", LOG_WARNING);
  2694. $nberr++;
  2695. } else {
  2696. dol_syslog("functions.lib::dol_mkdir: Directory '" . $ccdir . "' created", LOG_DEBUG);
  2697. $nberr = 0; // On remet a zero car si on arrive ici, cela veut dire que les echecs precedents peuvent etre ignore
  2698. $nbcreated++;
  2699. }
  2700. } else {
  2701. $nberr = 0; // On remet a zero car si on arrive ici, cela veut dire que les echecs precedents peuvent etre ignores
  2702. }
  2703. }
  2704. }
  2705. return ($nberr ? -$nberr : $nbcreated);
  2706. }
  2707. /**
  2708. * Return picto saying a field is required
  2709. *
  2710. * @return string Chaine avec picto obligatoire
  2711. */
  2712. function picto_required() {
  2713. return '<span class="fieldrequired">*</span>';
  2714. }
  2715. /**
  2716. * Clean a string from all HTML tags and entities
  2717. *
  2718. * @param string $StringHtml String to clean
  2719. * @param string $removelinefeed Replace also all lines feeds by a space
  2720. * @param string $pagecodeto Encoding of input string
  2721. * @return string String cleaned
  2722. */
  2723. function dol_string_nohtmltag($StringHtml, $removelinefeed = 1, $pagecodeto = 'UTF-8') {
  2724. $pattern = "/<[^>]+>/";
  2725. $temp = dol_html_entity_decode($StringHtml, ENT_COMPAT, $pagecodeto);
  2726. $temp = preg_replace($pattern, "", $temp);
  2727. // Supprime aussi les retours
  2728. if ($removelinefeed)
  2729. $temp = str_replace(array("\r\n", "\r", "\n"), " ", $temp);
  2730. // et les espaces doubles
  2731. while (strpos($temp, " ")) {
  2732. $temp = str_replace(" ", " ", $temp);
  2733. }
  2734. $CleanString = trim($temp);
  2735. return $CleanString;
  2736. }
  2737. /**
  2738. * Replace CRLF in string with a HTML BR tag
  2739. *
  2740. * @param string $stringtoencode String to encode
  2741. * @param string $nl2brmode 0=Adding br before \n, 1=Replacing \n by br
  2742. * @param string $forxml false=Use <br>, true=Use <br />
  2743. * @return string String encoded
  2744. */
  2745. function dol_nl2br($stringtoencode, $nl2brmode = 0, $forxml = false) {
  2746. if (!$nl2brmode) {
  2747. // We use @ to avoid warning on PHP4 that does not support entity encoding from UTF8;
  2748. if (version_compare(PHP_VERSION, '5.3.0') < 0)
  2749. return @nl2br($stringtoencode);
  2750. else
  2751. return @nl2br($stringtoencode, $forxml);
  2752. }
  2753. else {
  2754. $ret = preg_replace('/(\r\n|\r|\n)/i', ($forxml ? '<br />' : '<br>'), $stringtoencode);
  2755. return $ret;
  2756. }
  2757. }
  2758. /**
  2759. * This function is called to encode a string into a HTML string but differs from htmlentities because
  2760. * all entities but &,<,> are converted. This permits to encode special chars to entities with no double
  2761. * encoding for already encoded HTML strings.
  2762. * This function also remove last CR/BR.
  2763. * For PDF usage, you can show text by 2 ways:
  2764. * - writeHTMLCell -> param must be encoded into HTML.
  2765. * - MultiCell -> param must not be encoded into HTML.
  2766. * Because writeHTMLCell convert also \n into <br>, if function
  2767. * is used to build PDF, nl2brmode must be 1
  2768. *
  2769. * @param string $stringtoencode String to encode
  2770. * @param int $nl2brmode 0=Adding br before \n, 1=Replacing \n by br (for use with FPDF writeHTMLCell function for example)
  2771. * @param string $pagecodefrom Pagecode stringtoencode is encoded
  2772. * @return string String encoded
  2773. */
  2774. function dol_htmlentitiesbr($stringtoencode, $nl2brmode = 0, $pagecodefrom = 'UTF-8') {
  2775. if (dol_textishtml($stringtoencode)) {
  2776. $newstring = $stringtoencode;
  2777. $newstring = preg_replace('/<br(\s[\sa-zA-Z_="]*)?\/?>/i', '<br>', $newstring); // Replace "<br type="_moz" />" by "<br>". It's same and avoid pb with FPDF.
  2778. $newstring = preg_replace('/<br>$/i', '', $newstring); // Remove last <br>
  2779. $newstring = strtr($newstring, array('&' => '__and__', '<' => '__lt__', '>' => '__gt__', '"' => '__dquot__'));
  2780. $newstring = dol_htmlentities($newstring, ENT_COMPAT, $pagecodefrom); // Make entity encoding
  2781. $newstring = strtr($newstring, array('__and__' => '&', '__lt__' => '<', '__gt__' => '>', '__dquot__' => '"'));
  2782. //$newstring=strtr($newstring,array('__li__'=>"<li>\n")); // Restore <li>\n
  2783. } else {
  2784. $newstring = dol_nl2br(dol_htmlentities($stringtoencode, ENT_COMPAT, $pagecodefrom), $nl2brmode);
  2785. }
  2786. // Other substitutions that htmlentities does not do
  2787. //$newstring=str_replace(chr(128),'&euro;',$newstring); // 128 = 0x80. Not in html entity table. // Seems useles with TCPDF. Make bug with UTF8 languages
  2788. return $newstring;
  2789. }
  2790. /**
  2791. * This function is called to decode a HTML string (it decodes entities and br tags)
  2792. *
  2793. * @param string $stringtodecode String to decode
  2794. * @param string $pagecodeto Page code for result
  2795. * @return string String decoded
  2796. */
  2797. function dol_htmlentitiesbr_decode($stringtodecode, $pagecodeto = 'UTF-8') {
  2798. $ret = dol_html_entity_decode($stringtodecode, ENT_COMPAT, $pagecodeto);
  2799. $ret = preg_replace('/' . "\r\n" . '<br(\s[\sa-zA-Z_="]*)?\/?>/i', "<br>", $ret);
  2800. $ret = preg_replace('/<br(\s[\sa-zA-Z_="]*)?\/?>' . "\r\n" . '/i', "\r\n", $ret);
  2801. $ret = preg_replace('/<br(\s[\sa-zA-Z_="]*)?\/?>' . "\n" . '/i', "\n", $ret);
  2802. $ret = preg_replace('/<br(\s[\sa-zA-Z_="]*)?\/?>/i', "\n", $ret);
  2803. return $ret;
  2804. }
  2805. /**
  2806. * This function remove all ending \n and br at end
  2807. *
  2808. * @param string $stringtodecode String to decode
  2809. * @return string String decoded
  2810. */
  2811. function dol_htmlcleanlastbr($stringtodecode) {
  2812. $ret = preg_replace('/(<br>|<br(\s[\sa-zA-Z_="]*)?\/?>|' . "\n" . '|' . "\r" . ')+$/i', "", $stringtodecode);
  2813. return $ret;
  2814. }
  2815. /**
  2816. * This function remove all accent in a text
  2817. *
  2818. * @param string $str String with accent
  2819. * @return string String without accent
  2820. */
  2821. function dol_delaccents($str, $encoding = 'utf-8') {
  2822. // transformer les caractères accentués en entités HTML
  2823. $str = htmlentities($str, ENT_NOQUOTES, $encoding);
  2824. // remplacer les entités HTML pour avoir juste le premier caractères non accentués
  2825. // Exemple : "&ecute;" => "e", "&Ecute;" => "E", "Ã " => "a" ...
  2826. $str = preg_replace('#&([A-za-z])(?:acute|grave|cedil|circ|orn|ring|slash|th|tilde|uml);#', '\1', $str);
  2827. // Remplacer les ligatures tel que : Œ, Æ ...
  2828. // Exemple "Å“" => "oe"
  2829. $str = preg_replace('#&([A-za-z]{2})(?:lig);#', '\1', $str);
  2830. // Supprimer tout le reste
  2831. $str = preg_replace('#&[^;]+;#', '', $str);
  2832. return $str;
  2833. }
  2834. /**
  2835. * Replace html_entity_decode functions to manage errors
  2836. *
  2837. * @param string $a Operand a
  2838. * @param string $b Operand b
  2839. * @param string $c Operand c
  2840. * @return string String decoded
  2841. */
  2842. function dol_html_entity_decode($a, $b, $c = 'UTF-8') {
  2843. // We use @ to avoid warning on PHP4 that does not support entity decoding to UTF8;
  2844. $ret = @html_entity_decode($a, $b, $c);
  2845. return $ret;
  2846. }
  2847. /**
  2848. * Replace htmlentities functions to manage errors
  2849. *
  2850. * @param string $a Operand a
  2851. * @param string $b Operand b
  2852. * @param string $c Operand c
  2853. * @return string String encoded
  2854. */
  2855. function dol_htmlentities($a, $b, $c = 'UTF-8') {
  2856. // We use @ to avoid warning on PHP4 that does not support entity decoding to UTF8;
  2857. $ret = @htmlentities($a, $b, $c);
  2858. return $ret;
  2859. }
  2860. /**
  2861. * Check if a string is a correct iso string
  2862. * If not, it will we considered not HTML encoded even if it is by FPDF.
  2863. * Example, if string contains euro symbol that has ascii code 128
  2864. *
  2865. * @param string $s String to check
  2866. * @return int 0 if bad iso, 1 if good iso
  2867. */
  2868. function dol_string_is_good_iso($s) {
  2869. $len = dol_strlen($s);
  2870. $ok = 1;
  2871. for ($scursor = 0; $scursor < $len; $scursor++) {
  2872. $ordchar = ord($s{$scursor});
  2873. //print $scursor.'-'.$ordchar.'<br>';
  2874. if ($ordchar < 32 && $ordchar != 13 && $ordchar != 10) {
  2875. $ok = 0;
  2876. break;
  2877. }
  2878. if ($ordchar > 126 && $ordchar < 160) {
  2879. $ok = 0;
  2880. break;
  2881. }
  2882. }
  2883. return $ok;
  2884. }
  2885. /**
  2886. * Return nb of lines of a clear text
  2887. *
  2888. * @param string $s String to check
  2889. * @param string $maxchar Not yet used
  2890. * @return int Number of lines
  2891. */
  2892. function dol_nboflines($s, $maxchar = 0) {
  2893. if ($s == '')
  2894. return 0;
  2895. $arraystring = explode("\n", $s);
  2896. $nb = count($arraystring);
  2897. return $nb;
  2898. }
  2899. /**
  2900. * Return nb of lines of a formated text with \n and <br> (we can't have both \n and br)
  2901. *
  2902. * @param string $text Text
  2903. * @param int $maxlinesize Largeur de ligne en caracteres (ou 0 si pas de limite - defaut)
  2904. * @param string $charset Give the charset used to encode the $text variable in memory.
  2905. * @return int Number of lines
  2906. */
  2907. function dol_nboflines_bis($text, $maxlinesize = 0, $charset = 'UTF-8') {
  2908. $repTable = array("\t" => " ", "\n" => "<br>", "\r" => " ", "\0" => " ", "\x0B" => " ");
  2909. if (dol_textishtml($text))
  2910. $repTable = array("\t" => " ", "\n" => " ", "\r" => " ", "\0" => " ", "\x0B" => " ");
  2911. $text = strtr($text, $repTable);
  2912. if ($charset == 'UTF-8') {
  2913. $pattern = '/(<br[^>]*>)/Uu';
  2914. } // /U is to have UNGREEDY regex to limit to one html tag. /u is for UTF8 support
  2915. else
  2916. $pattern = '/(<br[^>]*>)/U'; // /U is to have UNGREEDY regex to limit to one html tag.
  2917. $a = preg_split($pattern, $text, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
  2918. $nblines = floor((count($a) + 1) / 2);
  2919. // count possible auto line breaks
  2920. if ($maxlinesize) {
  2921. foreach ($a as $line) {
  2922. if (dol_strlen($line) > $maxlinesize) {
  2923. //$line_dec = html_entity_decode(strip_tags($line));
  2924. $line_dec = html_entity_decode($line);
  2925. if (dol_strlen($line_dec) > $maxlinesize) {
  2926. $line_dec = wordwrap($line_dec, $maxlinesize, '\n', true);
  2927. $nblines+=substr_count($line_dec, '\n');
  2928. }
  2929. }
  2930. }
  2931. }
  2932. return $nblines;
  2933. }
  2934. /**
  2935. * Same function than microtime in PHP 5 but compatible with PHP4
  2936. *
  2937. * @return float Time (millisecondes) with microsecondes in decimal part
  2938. */
  2939. function dol_microtime_float() {
  2940. list($usec, $sec) = explode(" ", microtime());
  2941. return ((float) $usec + (float) $sec);
  2942. }
  2943. /**
  2944. * Return if a text is a html content
  2945. *
  2946. * @param string $msg Content to check
  2947. * @param int $option 0=Full detection, 1=Fast check
  2948. * @return boolean true/false
  2949. * @see dol_concatdesc
  2950. */
  2951. function dol_textishtml($msg, $option = 0) {
  2952. if ($option == 1) {
  2953. if (preg_match('/<html/i', $msg))
  2954. return true;
  2955. elseif (preg_match('/<body/i', $msg))
  2956. return true;
  2957. elseif (preg_match('/<br/i', $msg))
  2958. return true;
  2959. return false;
  2960. }
  2961. else {
  2962. if (preg_match('/<html/i', $msg))
  2963. return true;
  2964. elseif (preg_match('/<body/i', $msg))
  2965. return true;
  2966. elseif (preg_match('/<br/i', $msg))
  2967. return true;
  2968. elseif (preg_match('/<span/i', $msg))
  2969. return true;
  2970. elseif (preg_match('/<div/i', $msg))
  2971. return true;
  2972. elseif (preg_match('/<li/i', $msg))
  2973. return true;
  2974. elseif (preg_match('/<table/i', $msg))
  2975. return true;
  2976. elseif (preg_match('/<font/i', $msg))
  2977. return true;
  2978. elseif (preg_match('/<strong/i', $msg))
  2979. return true;
  2980. elseif (preg_match('/<img/i', $msg))
  2981. return true;
  2982. elseif (preg_match('/<i>/i', $msg))
  2983. return true;
  2984. elseif (preg_match('/<b>/i', $msg))
  2985. return true;
  2986. elseif (preg_match('/&[A-Z0-9]{1,6};/i', $msg))
  2987. return true; // Html entities names (http://www.w3schools.com/tags/ref_entities.asp)
  2988. elseif (preg_match('/&#[0-9]{2,3};/i', $msg))
  2989. return true; // Html entities numbers (http://www.w3schools.com/tags/ref_entities.asp)
  2990. return false;
  2991. }
  2992. }
  2993. /**
  2994. * Concat 2 descriptions (second one after first one)
  2995. * text1 html + text2 html => text1 + '<br>' + text2
  2996. * text1 html + text2 txt => text1 + '<br>' + dol_nl2br(text2)
  2997. * text1 txt + text2 html => dol_nl2br(text1) + '<br>' + text2
  2998. * text1 txt + text2 txt => text1 + '\n' + text2
  2999. *
  3000. * @param string $text1 Text 1
  3001. * @param string $text2 Text 2
  3002. * @param string $forxml false=Use <br>, true=Use <br />
  3003. * @return string Text 1 + new line + Text2
  3004. * @see dol_textishtml
  3005. */
  3006. function dol_concatdesc($text1, $text2, $forxml = false) {
  3007. $ret = '';
  3008. $ret.= (!dol_textishtml($text1) && dol_textishtml($text2)) ? dol_nl2br($text1, 0, $forxml) : $text1;
  3009. $ret.= (!empty($text1) && !empty($text2)) ? ((dol_textishtml($text1) || dol_textishtml($text2)) ? ($forxml ? "<br \>\n" : "<br>\n") : "\n") : "";
  3010. $ret.= (dol_textishtml($text1) && !dol_textishtml($text2)) ? dol_nl2br($text2, 0, $forxml) : $text2;
  3011. return $ret;
  3012. }
  3013. /**
  3014. * Make substition into a string
  3015. * There is two type of substitions:
  3016. * - From $substitutionarray (oldval=>newval)
  3017. * - From special constants (__XXX__=>f(objet->xxx)) by substitutions modules
  3018. *
  3019. * @param string $chaine Source string in which we must do substitution
  3020. * @param array $substitutionarray Array with key->val to substitute
  3021. * @return string Output string after subsitutions
  3022. * @see complete_substitutions_array
  3023. */
  3024. function make_substitutions($chaine, $substitutionarray) {
  3025. global $conf;
  3026. if (!is_array($substitutionarray))
  3027. return 'ErrorBadParameterSubstitutionArrayWhenCalling_make_substitutions';
  3028. // Make substitition
  3029. foreach ($substitutionarray as $key => $value) {
  3030. if ($key == '__SIGNATURE__' && (!empty($conf->global->MAIL_DO_NOT_USE_SIGN)))
  3031. $value = '';
  3032. $chaine = str_replace("$key", "$value", $chaine); // We must keep the " to work when value is 123.5 for example
  3033. }
  3034. return $chaine;
  3035. }
  3036. /**
  3037. * Complete the $substitutionarray with more entries
  3038. *
  3039. * @param array &$substitutionarray Array substitution old value => new value value
  3040. * @param Translate $outputlangs If we want substitution from special constants, we provide a language
  3041. * @param Object $object If we want substitution from special constants, we provide data in a source object
  3042. * @param Object/array $parameters Add more parameters (useful to pass product lines)
  3043. * @param string $callfunc What is the name of the custom function that will be called? (default: completesubstitutionarray)
  3044. * @return void
  3045. * @see make_substitutions
  3046. */
  3047. function complete_substitutions_array(&$substitutionarray, $outputlangs, $object = '', $parameters = null, $callfunc = "completesubstitutionarray") {
  3048. global $conf, $user;
  3049. require_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php';
  3050. // Check if there is external substitution to do asked by plugins
  3051. $dirsubstitutions = array_merge(array(), (array) $conf->modules_parts['substitutions']);
  3052. foreach ($dirsubstitutions as $reldir) {
  3053. $dir = dol_buildpath($reldir, 0);
  3054. // Check if directory exists
  3055. if (!dol_is_dir($dir))
  3056. continue;
  3057. $substitfiles = dol_dir_list($dir, 'files', 0, 'functions_');
  3058. foreach ($substitfiles as $substitfile) {
  3059. if (preg_match('/functions_(.*)\.lib\.php/i', $substitfile['name'], $reg)) {
  3060. $module = $reg[1];
  3061. dol_syslog("Library functions_" . $substitfile['name'] . " found into " . $dir);
  3062. require_once $dir . $substitfile['name'];
  3063. $function_name = $module . "_" . $callfunc;
  3064. if (function_exists($function_name))
  3065. $function_name($substitutionarray, $outputlangs, $object, $parameters);
  3066. }
  3067. }
  3068. }
  3069. }
  3070. /**
  3071. * Format output for start and end date
  3072. *
  3073. * @param timestamp $date_start Start date
  3074. * @param timestamp $date_end End date
  3075. * @param string $format Output format
  3076. * @param Translate $outputlangs Output language
  3077. * @return void
  3078. */
  3079. function print_date_range($date_start, $date_end, $format = '', $outputlangs = '') {
  3080. print get_date_range($date_start, $date_end, $format, $outputlangs);
  3081. }
  3082. /**
  3083. * Format output for start and end date
  3084. *
  3085. * @param timestamp $date_start Start date
  3086. * @param timestamp $date_end End date
  3087. * @param string $format Output format
  3088. * @param Translate $outputlangs Output language
  3089. * @return string String
  3090. */
  3091. function get_date_range($date_start, $date_end, $format = '', $outputlangs = '') {
  3092. global $langs;
  3093. $out = '';
  3094. if (!is_object($outputlangs))
  3095. $outputlangs = $langs;
  3096. if ($date_start && $date_end) {
  3097. $out.= ' (' . $outputlangs->trans('DateFromTo', dol_print_date($date_start, $format, false, $outputlangs), dol_print_date($date_end, $format, false, $outputlangs)) . ')';
  3098. }
  3099. if ($date_start && !$date_end) {
  3100. $out.= ' (' . $outputlangs->trans('DateFrom', dol_print_date($date_start, $format, false, $outputlangs)) . ')';
  3101. }
  3102. if (!$date_start && $date_end) {
  3103. $out.= ' (' . $outputlangs->trans('DateUntil', dol_print_date($date_end, $format, false, $outputlangs)) . ')';
  3104. }
  3105. return $out;
  3106. }
  3107. /**
  3108. * Set event message in dol_events session
  3109. *
  3110. * @param mixed $mesgs Message string or array
  3111. * @param string $style Which style to use ('mesgs', 'warnings', 'errors')
  3112. * @return void
  3113. * @see dol_htmloutput_events
  3114. */
  3115. function setEventMessage($mesgs, $style = 'mesgs') {
  3116. if (!in_array((string) $style, array('mesgs', 'warnings', 'errors')))
  3117. dol_print_error('', 'Bad parameter for setEventMessage');
  3118. $events = array();
  3119. if (!is_array($mesgs)) { // If mesgs is a string
  3120. if (!empty($mesgs))
  3121. $events[] = (object) array('message' => $mesgs);
  3122. //$_SESSION['dol_events'][$style][] = $mesgs;
  3123. } else { // If mesgs is an array
  3124. foreach ($mesgs as $mesg) {
  3125. if (!empty($mesg))
  3126. $events[] = (object) array('message' => $mesg);
  3127. //$_SESSION['dol_events'][$style][] = $mesg;
  3128. }
  3129. }
  3130. dol_setcache($style, $events);
  3131. }
  3132. /**
  3133. * Print formated messages to output (Used to show messages on html output).
  3134. *
  3135. * @return void
  3136. * @see dol_htmloutput_mesg
  3137. */
  3138. function dol_htmloutput_events() {
  3139. // Show mesgs
  3140. /*
  3141. if (isset($_SESSION['dol_events']['mesgs'])) {
  3142. dol_htmloutput_mesg('', $_SESSION['dol_events']['mesgs']);
  3143. unset($_SESSION['dol_events']['mesgs']);
  3144. }
  3145. // Show errors
  3146. if (isset($_SESSION['dol_events']['errors'])) {
  3147. dol_htmloutput_mesg('', $_SESSION['dol_events']['errors'], 'error');
  3148. unset($_SESSION['dol_events']['errors']);
  3149. }
  3150. // Show warnings
  3151. if (isset($_SESSION['dol_events']['warnings'])) {
  3152. dol_htmloutput_mesg('', $_SESSION['dol_events']['warnings'], 'warning');
  3153. unset($_SESSION['dol_events']['warnings']);
  3154. } */
  3155. // Log in memcached
  3156. $type = array("errors", "warnings", "mesgs");
  3157. foreach ($type as $aRow) {
  3158. $logs = dol_getcache($aRow);
  3159. if (is_array($logs)) {
  3160. switch ($aRow) {
  3161. case "errors":
  3162. $color = "red-gradient";
  3163. $icon = 'theme/common/emotes/face-sad.png';
  3164. $closeDelay = 8000;
  3165. break;
  3166. case "warnings":
  3167. $color = "orange-gradient";
  3168. $icon = 'theme/common/emotes/face-uncertain.png';
  3169. $closeDelay = 8000;
  3170. break;
  3171. case "mesgs":
  3172. $color = "green-gradient";
  3173. $icon = 'theme/common/emotes/face-smile.png';
  3174. $closeDelay = 5000;
  3175. break;
  3176. }
  3177. foreach ($logs as $row) {
  3178. ?>
  3179. <script>
  3180. $(document).ready(function() {
  3181. notify('<?php echo dol_escape_js($row->title); ?>', '<?php echo dol_escape_js($row->message); ?>', {
  3182. autoClose: true,
  3183. delay: 500,
  3184. closeDelay: <?php echo $closeDelay; ?>,
  3185. classes: ["<?php echo $color; ?>"],
  3186. icon: '<?php echo $icon; ?>'
  3187. });
  3188. });
  3189. </script>
  3190. <?php
  3191. }
  3192. dol_delcache($aRow);
  3193. }
  3194. }
  3195. }
  3196. /**
  3197. * Get formated messages to output (Used to show messages on html output).
  3198. *
  3199. * @param string $mesgstring Message string
  3200. * @param array $mesgarray Messages array
  3201. * @param string $style Style of message output ('ok' or 'error')
  3202. * @param int $keepembedded Set to 1 in error message must be kept embedded into its html place (this disable jnotify)
  3203. * @return string Return html output
  3204. *
  3205. * @see dol_print_error
  3206. * @see dol_htmloutput_errors
  3207. */
  3208. function get_htmloutput_mesg($mesgstring = '', $mesgarray = '', $style = 'ok', $keepembedded = 0) {
  3209. global $conf, $langs;
  3210. $ret = '';
  3211. $out = '';
  3212. $divstart = $divend = '';
  3213. if ((is_array($mesgarray) && count($mesgarray)) || $mesgstring) {
  3214. $langs->load("errors");
  3215. $out.=$divstart;
  3216. if (is_array($mesgarray) && count($mesgarray)) {
  3217. foreach ($mesgarray as $message) {
  3218. $ret++;
  3219. $out.= $langs->trans($message);
  3220. if ($ret < count($mesgarray))
  3221. $out.= "<br>\n";
  3222. }
  3223. }
  3224. if ($mesgstring) {
  3225. $langs->load("errors");
  3226. $ret++;
  3227. $out.= $langs->trans($mesgstring);
  3228. }
  3229. $out.=$divend;
  3230. }
  3231. if ($out) {
  3232. switch ($style) {
  3233. case "error":
  3234. $color = "red-gradient";
  3235. $icon = 'theme/common/emotes/face-sad.png';
  3236. $closeDelay = 10000;
  3237. break;
  3238. case "warning":
  3239. $color = "orange-gradient";
  3240. $icon = 'theme/common/emotes/face-uncertain.png';
  3241. $closeDelay = 10000;
  3242. break;
  3243. case "ok":
  3244. $color = "green-gradient";
  3245. $icon = 'theme/common/emotes/face-smile.png';
  3246. $closeDelay = 5000;
  3247. break;
  3248. }
  3249. ?><script>
  3250. $(document).ready(function() {
  3251. notify('<?php echo dol_escape_js($row->title); ?>', '<?php echo dol_escape_js($out); ?>', {
  3252. autoClose: true,
  3253. delay: 500,
  3254. closeDelay: <?php echo $closeDelay; ?>,
  3255. classes: ["<?php echo $color; ?>"],
  3256. icon: '<?php echo $icon; ?>'
  3257. });
  3258. });
  3259. </script><?php
  3260. }
  3261. return $return;
  3262. }
  3263. /**
  3264. * Get formated error messages to output (Used to show messages on html output).
  3265. *
  3266. * @param string $mesgstring Error message
  3267. * @param array $mesgarray Error messages array
  3268. * @param int $keepembedded Set to 1 in error message must be kept embedded into its html place (this disable jnotify)
  3269. * @return string Return html output
  3270. *
  3271. * @see dol_print_error
  3272. * @see dol_htmloutput_mesg
  3273. */
  3274. function get_htmloutput_errors($mesgstring = '', $mesgarray = '', $keepembedded = 0) {
  3275. return get_htmloutput_mesg($mesgstring, $mesgarray, 'error', $keepembedded);
  3276. }
  3277. /**
  3278. * Print formated messages to output (Used to show messages on html output).
  3279. *
  3280. * @param string $mesgstring Message
  3281. * @param array $mesgarray Messages array
  3282. * @param string $style Which style to use ('ok', 'warning', 'error')
  3283. * @param int $keepembedded Set to 1 if message must be kept embedded into its html place (this disable jnotify)
  3284. * @return void
  3285. *
  3286. * @see dol_print_error
  3287. * @see dol_htmloutput_errors
  3288. */
  3289. function dol_htmloutput_mesg($mesgstring = '', $mesgarray = '', $style = 'ok', $keepembedded = 0) {
  3290. if (empty($mesgstring) && (!is_array($mesgarray) || count($mesgarray) == 0))
  3291. return;
  3292. $iserror = 0;
  3293. $iswarning = 0;
  3294. if (is_array($mesgarray)) {
  3295. foreach ($mesgarray as $val) {
  3296. if ($val && preg_match('/class="error"/i', $val)) {
  3297. $iserror++;
  3298. break;
  3299. }
  3300. if ($val && preg_match('/class="warning"/i', $val)) {
  3301. $iswarning++;
  3302. break;
  3303. }
  3304. }
  3305. } else if ($mesgstring && preg_match('/class="error"/i', $mesgstring))
  3306. $iserror++;
  3307. else if ($mesgstring && preg_match('/class="warning"/i', $mesgstring))
  3308. $iswarning++;
  3309. if ($style == 'error')
  3310. $iserror++;
  3311. if ($style == 'warning')
  3312. $iswarning++;
  3313. if ($iserror || $iswarning) {
  3314. // Remove div from texts
  3315. $mesgstring = preg_replace('/<\/div><div class="(error|warning)">/', '<br>', $mesgstring);
  3316. $mesgstring = preg_replace('/<div class="(error|warning)">/', '', $mesgstring);
  3317. $mesgstring = preg_replace('/<\/div>/', '', $mesgstring);
  3318. // Remove div from texts array
  3319. if (is_array($mesgarray)) {
  3320. $newmesgarray = array();
  3321. foreach ($mesgarray as $val) {
  3322. $tmpmesgstring = preg_replace('/<\/div><div class="(error|warning)">/', '<br>', $val);
  3323. $tmpmesgstring = preg_replace('/<div class="(error|warning)">/', '', $tmpmesgstring);
  3324. $tmpmesgstring = preg_replace('/<\/div>/', '', $tmpmesgstring);
  3325. $newmesgarray[] = $tmpmesgstring;
  3326. }
  3327. $mesgarray = $newmesgarray;
  3328. }
  3329. print get_htmloutput_mesg($mesgstring, $mesgarray, ($iserror ? 'error' : 'warning'), $keepembedded);
  3330. }
  3331. else
  3332. print get_htmloutput_mesg($mesgstring, $mesgarray, 'ok', $keepembedded);
  3333. }
  3334. /**
  3335. * Print formated error messages to output (Used to show messages on html output).
  3336. *
  3337. * @param string $mesgstring Error message
  3338. * @param array $mesgarray Error messages array
  3339. * @param int $keepembedded Set to 1 in error message must be kept embedded into its html place (this disable jnotify)
  3340. * @return void
  3341. *
  3342. * @see dol_print_error
  3343. * @see dol_htmloutput_mesg
  3344. */
  3345. function dol_htmloutput_errors($mesgstring = '', $mesgarray = '', $keepembedded = 0) {
  3346. dol_htmloutput_mesg($mesgstring, $mesgarray, 'error', $keepembedded);
  3347. }
  3348. /**
  3349. * Advanced sort array by second index function, which produces ascending (default)
  3350. * or descending output and uses optionally natural case insensitive sorting (which
  3351. * can be optionally case sensitive as well).
  3352. *
  3353. * @param array &$array Array to sort (array of array('key','otherkey1','otherkey2'...))
  3354. * @param string $index Key in array to use for sorting criteria
  3355. * @param int $order Sort order
  3356. * @param int $natsort 1=use "natural" sort (natsort), 0=use "standard sort (asort)
  3357. * @param int $case_sensitive 1=sort is case sensitive, 0=not case sensitive
  3358. * @return array Sorted array
  3359. */
  3360. function dol_sort_array(&$array, $index, $order = 'asc', $natsort = 0, $case_sensitive = 0) {
  3361. // Clean parameters
  3362. $order = strtolower($order);
  3363. $sizearray = count($array);
  3364. if (is_array($array) && $sizearray > 0) {
  3365. foreach (array_keys($array) as $key)
  3366. $temp[$key] = $array[$key][$index];
  3367. if (!$natsort)
  3368. ($order == 'asc') ? asort($temp) : arsort($temp);
  3369. else {
  3370. ($case_sensitive) ? natsort($temp) : natcasesort($temp);
  3371. if ($order != 'asc')
  3372. $temp = array_reverse($temp, TRUE);
  3373. }
  3374. foreach (array_keys($temp) as $key)
  3375. (is_numeric($key)) ? $sorted[] = $array[$key] : $sorted[$key] = $array[$key];
  3376. return $sorted;
  3377. }
  3378. return $array;
  3379. }
  3380. /**
  3381. * Check if a string is in UTF8
  3382. *
  3383. * @param string $str String to check
  3384. * @return boolean True if string is UTF8 or ISO compatible with UTF8, False if not (ISO with special char or Binary)
  3385. */
  3386. function utf8_check($str) {
  3387. // We must use here a binary strlen function (so not dol_strlen)
  3388. $strLength = dol_strlen($str);
  3389. for ($i = 0; $i < $strLength; $i++) {
  3390. if (ord($str[$i]) < 0x80)
  3391. continue; // 0bbbbbbb
  3392. elseif ((ord($str[$i]) & 0xE0) == 0xC0)
  3393. $n = 1; // 110bbbbb
  3394. elseif ((ord($str[$i]) & 0xF0) == 0xE0)
  3395. $n = 2; // 1110bbbb
  3396. elseif ((ord($str[$i]) & 0xF8) == 0xF0)
  3397. $n = 3; // 11110bbb
  3398. elseif ((ord($str[$i]) & 0xFC) == 0xF8)
  3399. $n = 4; // 111110bb
  3400. elseif ((ord($str[$i]) & 0xFE) == 0xFC)
  3401. $n = 5; // 1111110b
  3402. else
  3403. return false; // Does not match any model
  3404. for ($j = 0; $j < $n; $j++) { // n bytes matching 10bbbbbb follow ?
  3405. if ((++$i == strlen($str)) || ((ord($str[$i]) & 0xC0) != 0x80))
  3406. return false;
  3407. }
  3408. }
  3409. return true;
  3410. }
  3411. /**
  3412. * Return an UTF-8 string encoded into OS filesystem encoding. This function is used to define
  3413. * value to pass to filesystem PHP functions.
  3414. *
  3415. * @param string $str String to encode (UTF-8)
  3416. * @return string Encoded string (UTF-8, ISO-8859-1)
  3417. */
  3418. function dol_osencode($str) {
  3419. global $conf;
  3420. $tmp = ini_get("unicode.filesystem_encoding"); // Disponible avec PHP 6.0
  3421. if (empty($tmp) && !empty($_SERVER["WINDIR"]))
  3422. $tmp = 'iso-8859-1'; // By default for windows
  3423. if (empty($tmp))
  3424. $tmp = 'utf-8'; // By default for other
  3425. if (!empty($conf->global->MAIN_FILESYSTEM_ENCODING))
  3426. $tmp = $conf->global->MAIN_FILESYSTEM_ENCODING;
  3427. if ($tmp == 'iso-8859-1')
  3428. return utf8_decode($str);
  3429. return $str;
  3430. }
  3431. /**
  3432. * Return an id or code from a code or id. Store Code-Id in a cache.
  3433. *
  3434. * @param DoliDB $db Database handler
  3435. * @param string $key Code to get Id
  3436. * @param string $tablename Table name without prefix
  3437. * @param string $fieldkey Field for code
  3438. * @param string $fieldid Field for id
  3439. * @return int Id of code
  3440. */
  3441. function dol_getIdFromCode($db, $key, $tablename, $fieldkey = 'code', $fieldid = 'id') {
  3442. global $cache_codes;
  3443. // If key empty
  3444. if ($key == '')
  3445. return '';
  3446. // Check in cache
  3447. if (isset($cache_codes[$tablename][$key])) { // Can be defined to 0 or ''
  3448. return $cache_codes[$tablename][$key]; // Found in cache
  3449. }
  3450. $sql = "SELECT " . $fieldid . " as id";
  3451. $sql.= " FROM " . MAIN_DB_PREFIX . $tablename;
  3452. $sql.= " WHERE " . $fieldkey . " = '" . $key . "'";
  3453. dol_syslog('dol_getIdFromCode sql=' . $sql, LOG_DEBUG);
  3454. $resql = $db->query($sql);
  3455. if ($resql) {
  3456. $obj = $db->fetch_object($resql);
  3457. if ($obj)
  3458. $cache_codes[$tablename][$key] = $obj->id;
  3459. else
  3460. $cache_codes[$tablename][$key] = '';
  3461. $db->free($resql);
  3462. return $cache_codes[$tablename][$key];
  3463. }
  3464. else {
  3465. dol_syslog("dol_getIdFromCode error=" . $db->lasterror(), LOG_ERR);
  3466. return -1;
  3467. }
  3468. }
  3469. /**
  3470. * Verify if condition in string is ok or not
  3471. *
  3472. * @param string $strRights String with condition to check
  3473. * @return boolean True or False. Return true if strRights is ''
  3474. */
  3475. function verifCond($strRights) {
  3476. global $user, $conf, $langs;
  3477. //global $rights; // To export to dol_eval function
  3478. //print $strRights."<br>\n";
  3479. $rights = true;
  3480. if ($strRights != '') {
  3481. $str = 'if(!(' . $strRights . ')) { $rights = false; }';
  3482. dol_eval($str);
  3483. }
  3484. return $rights;
  3485. }
  3486. /**
  3487. * Replace eval function to add more security.
  3488. * This function is called by verifCond()
  3489. *
  3490. * @param string $s String to evaluate
  3491. * @return mixed Result of eval
  3492. */
  3493. function dol_eval($s) {
  3494. // Only global variables can be changed by eval function and returned to caller
  3495. global $langs, $user, $conf;
  3496. global $leftmenu;
  3497. global $rights;
  3498. //print $s."<br>\n";
  3499. eval($s);
  3500. }
  3501. /**
  3502. * Return if var element is ok
  3503. *
  3504. * @param string $element Variable to check
  3505. * @return boolean Return true of variable is not empty
  3506. */
  3507. function dol_validElement($element) {
  3508. return (trim($element) != '');
  3509. }
  3510. /**
  3511. * Return img flag of country for a language code or country code
  3512. *
  3513. * @param string $codelang Language code (en_IN, fr_CA...) or Country code (IN, FR)
  3514. * @return string HTML img string with flag.
  3515. */
  3516. function picto_from_langcode($codelang) {
  3517. global $langs;
  3518. if ($codelang == 'auto') {
  3519. return img_picto_common($langs->trans('AutoDetectLang'), 'flags/int.png');
  3520. }
  3521. $langtocountryflag = array(
  3522. 'ar_AR' => '',
  3523. 'ca_ES' => 'catalonia',
  3524. 'da_DA' => 'dk',
  3525. 'fr_CA' => 'mq',
  3526. 'sv_SV' => 'se'
  3527. );
  3528. if (isset($langtocountryflag[$codelang]))
  3529. $flagImage = $langtocountryflag[$codelang];
  3530. else {
  3531. $tmparray = explode('_', $codelang);
  3532. $flagImage = empty($tmparray[1]) ? $tmparray[0] : $tmparray[1];
  3533. }
  3534. return img_picto_common($codelang, 'flags/' . strtolower($flagImage) . '.png');
  3535. }
  3536. /**
  3537. * Complete or removed entries into a head array (used to build tabs) with value added by external modules.
  3538. * Such values are declared into $conf->tabs_modules.
  3539. *
  3540. * @param Conf $conf Object conf
  3541. * @param Translate $langs Object langs
  3542. * @param Object $object Object object
  3543. * @param array &$head Object head
  3544. * @param int &$h New position to fill
  3545. * @param string $type Value for object where objectvalue can be
  3546. * 'thirdparty' to add a tab in third party view
  3547. * 'intervention' to add a tab in intervention view
  3548. * 'supplier_order' to add a tab in supplier order view
  3549. * 'supplier_invoice' to add a tab in supplier invoice view
  3550. * 'invoice' to add a tab in customer invoice view
  3551. * 'order' to add a tab in customer order view
  3552. * 'product' to add a tab in product view
  3553. * 'propal' to add a tab in propal view
  3554. * 'user' to add a tab in user view
  3555. * 'group' to add a tab in group view
  3556. * 'member' to add a tab in fundation member view
  3557. * 'categories_x' to add a tab in category view ('x': type of category (0=product, 1=supplier, 2=customer, 3=member)
  3558. * @param string $mode 'add' to complete head, 'remove' to remove entries
  3559. * @return void
  3560. */
  3561. function complete_head_from_modules($conf, $langs, $object, &$head, &$h, $type, $mode = 'add') {
  3562. if (isset($conf->tabs_modules[$type]) && is_array($conf->tabs_modules[$type])) {
  3563. foreach ($conf->tabs_modules[$type] as $value) {
  3564. $values = explode(':', $value);
  3565. if ($mode == 'add' && !preg_match('/^\-/', $values[1])) {
  3566. if (count($values) == 6) { // new declaration with permissions: $value='objecttype:+tabname1:Title1:langfile@mymodule:$user->rights->mymodule->read:/mymodule/mynewtab1.php?id=__ID__'
  3567. if ($values[0] != $type)
  3568. continue;
  3569. if (verifCond($values[4])) {
  3570. if ($values[3])
  3571. $langs->load($values[3]);
  3572. $head[$h][0] = dol_buildpath(preg_replace('/__ID__/i', (!empty($object->id) ? $object->id : ''), $values[5]), 1);
  3573. $head[$h][1] = $langs->trans($values[2]);
  3574. $head[$h][2] = str_replace('+', '', $values[1]);
  3575. $h++;
  3576. }
  3577. }
  3578. else if (count($values) == 5) { // new declaration
  3579. if ($values[0] != $type)
  3580. continue;
  3581. if ($values[3])
  3582. $langs->load($values[3]);
  3583. $head[$h][0] = dol_buildpath(preg_replace('/__ID__/i', (!empty($object->id) ? $object->id : ''), $values[4]), 1);
  3584. $head[$h][1] = $langs->trans($values[2]);
  3585. $head[$h][2] = str_replace('+', '', $values[1]);
  3586. $h++;
  3587. }
  3588. else if (count($values) == 4) { // old declaration, for backward compatibility
  3589. if ($values[0] != $type)
  3590. continue;
  3591. if ($values[2])
  3592. $langs->load($values[2]);
  3593. $head[$h][0] = dol_buildpath(preg_replace('/__ID__/i', (!empty($object->id) ? $object->id : ''), $values[3]), 1);
  3594. $head[$h][1] = $langs->trans($values[1]);
  3595. $head[$h][2] = 'tab' . $values[1];
  3596. $h++;
  3597. }
  3598. }
  3599. else if ($mode == 'remove' && preg_match('/^\-/', $values[1])) {
  3600. if ($values[0] != $type)
  3601. continue;
  3602. $tabname = str_replace('-', '', $values[1]);
  3603. foreach ($head as $key => $val) {
  3604. $condition = (!empty($values[3]) ? verifCond($values[3]) : 1);
  3605. if ($head[$key][2] == $tabname && $condition) {
  3606. unset($head[$key]);
  3607. break;
  3608. }
  3609. }
  3610. }
  3611. }
  3612. }
  3613. }
  3614. /**
  3615. * Print common footer :
  3616. * conf->global->MAIN_HTML_FOOTER
  3617. * conf->global->MAIN_GOOGLE_AN_ID
  3618. * DOL_TUNING
  3619. * conf->logbuffer
  3620. *
  3621. * @param string $zone 'private' (for private pages) or 'public' (for public pages)
  3622. * @return void
  3623. */
  3624. function printCommonFooter($zone = 'private') {
  3625. global $conf;
  3626. global $micro_start_time;
  3627. if ($zone == 'private')
  3628. print "\n" . '<!-- Common footer for private page -->' . "\n";
  3629. else
  3630. print "\n" . '<!-- Common footer for public page -->' . "\n";
  3631. if (!empty($conf->global->MAIN_HTML_FOOTER))
  3632. print $conf->global->MAIN_HTML_FOOTER . "\n";
  3633. // Google Analytics (need Google module)
  3634. if (!empty($conf->global->MAIN_GOOGLE_AN_ID)) {
  3635. print "\n";
  3636. print '<script type="text/javascript">' . "\n";
  3637. print ' var _gaq = _gaq || [];' . "\n";
  3638. print ' _gaq.push([\'_setAccount\', \'' . $conf->global->MAIN_GOOGLE_AN_ID . '\']);' . "\n";
  3639. print ' _gaq.push([\'_trackPageview\']);' . "\n";
  3640. print '' . "\n";
  3641. print ' (function() {' . "\n";
  3642. print ' var ga = document.createElement(\'script\'); ga.type = \'text/javascript\'; ga.async = true;' . "\n";
  3643. print ' ga.src = (\'https:\' == document.location.protocol ? \'https://ssl\' : \'http://www\') + \'.google-analytics.com/ga.js\';' . "\n";
  3644. print ' var s = document.getElementsByTagName(\'script\')[0]; s.parentNode.insertBefore(ga, s);' . "\n";
  3645. print ' })();' . "\n";
  3646. print '</script>' . "\n";
  3647. }
  3648. // End of tuning
  3649. if (!empty($_SERVER['DOL_TUNING'])) {
  3650. $micro_end_time = dol_microtime_float(true);
  3651. print "\n" . '<script type="text/javascript">' . "\n";
  3652. print 'console.log("';
  3653. if (!empty($conf->global->MEMCACHED_SERVER))
  3654. print 'MEMCACHED_SERVER=' . $conf->global->MEMCACHED_SERVER . ' - ';
  3655. print 'MAIN_OPTIMIZE_SPEED=' . (isset($conf->global->MAIN_OPTIMIZE_SPEED) ? $conf->global->MAIN_OPTIMIZE_SPEED : 'off');
  3656. print ' - Build time: ' . ceil(1000 * ($micro_end_time - $micro_start_time)) . ' ms';
  3657. if (function_exists("memory_get_usage")) {
  3658. print ' - Mem: ' . memory_get_usage();
  3659. }
  3660. if (function_exists("xdebug_memory_usage")) {
  3661. print ' - XDebug time: ' . ceil(1000 * xdebug_time_index()) . ' ms';
  3662. print ' - XDebug mem: ' . xdebug_memory_usage();
  3663. print ' - XDebug mem peak: ' . xdebug_peak_memory_usage();
  3664. }
  3665. if (function_exists("zend_loader_file_encoded")) {
  3666. print ' - Zend encoded file: ' . (zend_loader_file_encoded() ? 'yes' : 'no');
  3667. }
  3668. print '");' . "\n";
  3669. print '</script>' . "\n";
  3670. // Add Xdebug coverage of code
  3671. if (defined('XDEBUGCOVERAGE')) {
  3672. var_dump(xdebug_get_code_coverage());
  3673. }
  3674. }
  3675. // If there is some logs in buffer to show
  3676. if (count($conf->logbuffer)) {
  3677. print "\n";
  3678. print "<!-- Start of log output\n";
  3679. //print '<div class="hidden">'."\n";
  3680. foreach ($conf->logbuffer as $logline) {
  3681. print $logline . "<br>\n";
  3682. }
  3683. //print '</div>'."\n";
  3684. print "End of log output -->\n";
  3685. }
  3686. }
  3687. /**
  3688. * Convert an array with RGB value into hex RGB value
  3689. *
  3690. * @param array $arraycolor Array
  3691. * @param string $colorifnotfound Color code to return if entry not defined
  3692. * @return string RGB hex value (without # before). For example: FF00FF
  3693. */
  3694. function colorArrayToHex($arraycolor, $colorifnotfound = '888888') {
  3695. if (!is_array($arraycolor))
  3696. return $colorifnotfound;
  3697. return dechex($arraycolor[0]) . dechex($arraycolor[1]) . dechex($arraycolor[2]);
  3698. }
  3699. /**
  3700. * Convert an object to an array
  3701. *
  3702. * @param object $data Object to convert
  3703. * @return array Object converted
  3704. */
  3705. function object2array($data) {
  3706. if (!is_object($data) && !is_array($data))
  3707. return $data;
  3708. if (is_object($data))
  3709. $data = get_object_vars($data);
  3710. return array_map('object2array', $data);
  3711. }
  3712. if (!function_exists('getmypid')) {
  3713. /**
  3714. * Return random PID
  3715. * Some web hosts disable this php function for security reasons
  3716. *
  3717. * @return int
  3718. */
  3719. function getmypid() {
  3720. return rand(1, 32768);
  3721. }
  3722. }
  3723. ?>