function.php 59 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950
  1. <?php
  2. function secondToTime($seconds) {
  3. $t = round($seconds);
  4. return sprintf('%02d:%02d:%02d', ($t/3600),($t/60%60), $t%60);
  5. }
  6. function app_autoloader($class_name) {
  7. $roots = array(__ROOT__.'class');
  8. require_once(__ROOT__.'class'.SLASH.'Plugin.class.php');
  9. Plugin::callHook('class_root',array(&$roots));
  10. foreach ($roots as $root) {
  11. if(file_exists($root.SLASH.$class_name.'.class.php')){
  12. require_once($root.SLASH.$class_name.'.class.php');
  13. break;
  14. }
  15. }
  16. }
  17. function errorToException( $errno, $errstr, $errfile, $errline, $errcontext) {
  18. throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
  19. }
  20. function unhandledException($ex){
  21. global $myUser,$_;
  22. $source = 'ui';
  23. if(isset($_SERVER['SCRIPT_NAME']) && $_SERVER['SCRIPT_NAME'] == '/action.php') $source = 'action';
  24. if(php_sapi_name()=='cli') $source = 'shell';
  25. $error = array();
  26. $error['code'] = $ex->getCode();
  27. $error['message'] = $ex->getMessage();
  28. $error['file'] = $ex->getFile();
  29. $error['line'] = $ex->getLine();
  30. $error['trace'] = $ex->getTraceAsString();
  31. $debugLink ='';
  32. if(isset($_SERVER['SERVER_NAME']) && $_SERVER['SERVER_NAME']=='127.0.0.1') $debugLink = exception_link($ex);
  33. $advanced = (isset($myUser) && $myUser->superadmin) || (isset($_SERVER['HTTP_HOST']) && $_SERVER['HTTP_HOST']== '127.0.0.1');
  34. switch($source){
  35. case 'ui':
  36. $response = '';
  37. //Récuperation de la requete échouée si l'utilisateur n'est pas authentifié
  38. switch($ex->getCode()){
  39. case 401:
  40. $_SESSION['last_request'] = $_SERVER['REQUEST_URI'];
  41. if(isset($_SESSION['logout_redirect'])){
  42. echo '<script type="text/javascript">window.location="'.$_SESSION['logout_redirect'].'";</script>';
  43. }
  44. echo '<div id="message" class="alert alert-info"><strong>Connexion requise : </strong><span>'.$error['message'];
  45. echo '<br> Pour vous connecter, cliquez sur le menu "Connexion" en haut à droite de cet écran';
  46. echo '</span></div>';
  47. break;
  48. default:
  49. $response = '<div "id="message" class="d-block alert alert-danger m-3">';
  50. $response .= '<a style="color:inherit;text-decoration:none;" class="d-block" href="'.$debugLink.'">';
  51. if($advanced && isset($_['action'])) $response .= '<strong>Action : </strong><span>'.$_['action'].'</span><br>';
  52. $response .= '<strong>Erreur : </strong><span>'.$error['message'].'</span>';
  53. $response .= '</a>';
  54. if($advanced){
  55. $response .= '<small style="opacity:0.8;">'.$error['file'].' <strong>L'.$error['line'].'</strong><pre class="mb-0">';
  56. $response .= exception_trace($ex);
  57. $response .= '</pre></small>';
  58. }
  59. $response .= '</div>';
  60. break;
  61. }
  62. echo $response;
  63. require_once(__DIR__.SLASH.'footer.php');
  64. break;
  65. case 'shell':
  66. $response = PHP_EOL.str_repeat('-',100).PHP_EOL." \033[31m ERREUR : \033[0m ".$ex->getFile()." L\033[33m".$ex->getLine()."\033[0m".PHP_EOL.' '."\033[94m".$ex->getMessage()."\033[0m".PHP_EOL.str_repeat('-',100).PHP_EOL;
  67. echo $response;
  68. break;
  69. case 'action':
  70. $error['error'] = $error['message'];
  71. $response = json_encode($error);
  72. echo $response;
  73. break;
  74. default:
  75. $response = '[Erreur '.$error['code'].'] '.$error['file'].' L'.$error['line'].PHP_EOL.$error['message'].PHP_EOL.$error['trace'];
  76. echo $response;
  77. break;
  78. }
  79. exit();
  80. }
  81. function get_OS(){
  82. return strtoupper(substr(PHP_OS, 0, 3));
  83. }
  84. function OS_path_max_length(){
  85. switch(get_OS()){
  86. case 'WIN':
  87. return 259;
  88. break;
  89. default:
  90. return 4096;
  91. break;
  92. }
  93. }
  94. function OS_element_max_length(){
  95. switch(get_OS()){
  96. case 'WIN':
  97. return 255;
  98. break;
  99. default:
  100. return 255;
  101. break;
  102. }
  103. }
  104. function exception_link($ex,$type = 'exception'){
  105. if($type=='exception'){
  106. $filePath = $ex->getFile();
  107. $line = $ex->getLine();
  108. }else if($type=='trace'){
  109. $filePath = isset($ex['file']) ? $ex['file'] : '';
  110. $line = isset($ex['line']) ? $ex['line']: '';
  111. }
  112. $filePath = explode('/',$filePath);
  113. $filePath = implode('\\',$filePath);
  114. return 'w2d://'.base64_encode(
  115. json_encode(
  116. array(
  117. 'action'=>'alias',
  118. 'alias'=>'sublime',
  119. 'arguments'=>$filePath.'":'.$line
  120. )
  121. )
  122. );
  123. }
  124. function exception_trace($ex){
  125. $error = '';
  126. foreach($ex->getTrace() as $trace){
  127. $error .= '<hr class="my-1" /><a style="color:inherit;text-decoration:none;" href="'.exception_link($trace,'trace').'">'.str_replace(__ROOT__,'',(isset($trace['file']) ? $trace['file'] : 0 )).' <strong>L'.(isset($trace['line']) ? $trace['line'] : 0 ).'</strong> - ';
  128. if(!empty($trace['class'])) $error .= $trace['class'];
  129. if(!empty($trace['type'])) $error .= $trace['type'];
  130. if(!empty($trace['function'])) $error .= $trace['function'];
  131. if(!empty($trace['args'])){
  132. $error .= '(';
  133. $stringArgs = array();
  134. foreach($trace['args'] as $arg){
  135. $stringArgs[]=gettype($arg).( in_array(gettype($arg),array('string','integer','double','boolean','null')) ? ' <strong>'.$arg.'</strong>': '');
  136. }
  137. $error .= implode(', ',$stringArgs);
  138. $error .= ')';
  139. }
  140. $error .= '</a>';
  141. }
  142. return $error;
  143. }
  144. function ip(){
  145. if(isset($_SERVER['HTTP_X_FORWARDED_FOR']))
  146. $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
  147. elseif(isset($_SERVER['HTTP_CLIENT_IP']))
  148. $ip = $_SERVER['HTTP_CLIENT_IP'];
  149. else
  150. $ip = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] :'';
  151. return $ip;
  152. }
  153. //Check si l'url serveur est en HTTPS
  154. function is_url_securised(){
  155. //La verification de HTTP_X_FORWARDED_PROTO permet de gerer les reverse proxy qui font du https -> http
  156. return (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO']=='https') || (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off');
  157. }
  158. //Définit le schéma d'URL à utiliser
  159. function define_url_scheme(){
  160. return is_url_securised() ? 'https' : 'http';
  161. }
  162. function encode_uri($uri){
  163. return preg_replace_callback("{[^0-9a-z_.!~*'();,/?:@&=+$#-]}i", function ($m) {
  164. return sprintf('%%%02X', ord($m[0]));
  165. }, $uri);
  166. }
  167. //Définit la racine des médias en
  168. //fonction du schéma d'URL (http ou https)
  169. function define_media_root(){
  170. return is_url_securised() ? preg_replace('|http(s)?://|i',define_url_scheme().'://',ROOT_URL) : ROOT_URL;
  171. }
  172. function encrypt($data){
  173. $keyHash = md5(CRYPTKEY);
  174. $data = openssl_encrypt ($data,'aes256',$keyHash,true,'1234567812345678');
  175. return base64_encode($data);
  176. }
  177. function decrypt($data){
  178. $keyHash = md5(CRYPTKEY);
  179. $data = base64_decode($data);
  180. return openssl_decrypt ($data,'aes256',$keyHash,true,'1234567812345678');
  181. }
  182. //Génère un slug unique pour l'element de liste utilisable dans le code
  183. // $label => string du label à slugifier
  184. // $column => la colonne en base où checker les slugs existants
  185. function generateSlug($label, $class, $column, $allowChars = '', $separator = '-'){
  186. $slug = slugify($label,$allowChars,$separator);
  187. $item = new $class();
  188. if(!array_key_exists($column, $item->fieldMapping)) return;
  189. $params = array_key_exists('state', $item->fieldMapping) ? array('state'=>$class::ACTIVE) : array();
  190. $i='';
  191. while($class::rowCount(array_merge(array($column=>($i==''?$slug:$slug.$separator.$i)), $params)) > 0) $i++;
  192. return $i==''?$slug:$slug.$separator.$i;
  193. }
  194. function slugify($text,$allowChars = '', $separator='-') {
  195. setlocale(LC_CTYPE, 'fr_FR.UTF-8');
  196. try{
  197. $encoding = mb_detect_encoding($text, mb_detect_order(), false);
  198. if($encoding == "UTF-8") $text = mb_convert_encoding($text, 'UTF-8', 'UTF-8');
  199. $clean = iconv(mb_detect_encoding($text, mb_detect_order(), false), 'ASCII//TRANSLIT', $text);
  200. }catch(Exception $e){
  201. $clean = $text;
  202. }
  203. $clean = normalize_chars($clean);
  204. $clean = preg_replace("/[^a-zA-Z0-9\/_|+ -".preg_quote($allowChars)."]/", '', $clean);
  205. $clean = strtolower(trim($clean, $separator));
  206. $clean = preg_replace("/[\\".preg_quote(str_replace(str_split($allowChars),'','/_|+ -'))."]+/", $separator, $clean);
  207. return $clean;
  208. }
  209. if(!function_exists('glob_recursive')) {
  210. // Does not support flag GLOB_BRACE
  211. function glob_recursive($pattern, $flags = 0,$forbiddenPathes = array(),$root = null){
  212. $files = glob($pattern, $flags);
  213. foreach (glob(dirname($pattern).SLASH.'*', GLOB_ONLYDIR|GLOB_NOSORT) as $dir) {
  214. if(isset($root))
  215. if(in_array(str_replace($root,'',$dir), $forbiddenPathes)) continue;
  216. $files = array_merge($files, glob_recursive($dir.SLASH.basename($pattern), $flags,$forbiddenPathes,$root));
  217. }
  218. return $files;
  219. }
  220. }
  221. //Récupère la dernière clé d'un tableau
  222. //avec fallback pour versions de PHP < 7
  223. if (!function_exists("array_key_last")) {
  224. function array_key_last($array) {
  225. if (!is_array($array) || empty($array)) return NULL;
  226. return array_keys($array)[count($array)-1];
  227. }
  228. }
  229. //Récupère la première clé d'un tableau
  230. //avec fallback pour versions de PHP < 7
  231. if(!function_exists('array_key_first')) {
  232. function array_key_first($array) {
  233. $array = array_keys($array);
  234. return isset($array[0]) ? $array[0] : NULL;
  235. }
  236. }
  237. //Aplatit un tableau multidimensionnel
  238. //en un tableau à 1 seul niveau
  239. function array_flatten($array) {
  240. $return = array();
  241. foreach($array as $key => $value) {
  242. if(is_array($value)){
  243. $return = array_merge($return, array_flatten($value));
  244. } else {
  245. $return[$key] = $value;
  246. }
  247. }
  248. return $return;
  249. }
  250. function array_map_recursive($callback, $array) {
  251. $func = function ($item) use (&$func, &$callback) {
  252. return is_array($item) ? array_map($func, $item) : call_user_func($callback, $item);
  253. };
  254. return array_map($func, $array);
  255. }
  256. //Même principe que le ORDER BY de MySQL
  257. //mais sur différentes clés d'un tableau
  258. //Auteur: jimpoz -> https://www.php.net/manual/fr/function.array-multisort.php#100534
  259. function array_orderby() {
  260. //Permet de récupérer les paramètres passés dynamiquement
  261. //Car on ne sait pas combien de paramètres on peut avoir
  262. $args = func_get_args();
  263. $data = array_shift($args);
  264. foreach ($args as $n => $field) {
  265. if (is_string($field)) {
  266. $tmp = array();
  267. foreach ($data as $key => $row)
  268. $tmp[$key] = $row[$field];
  269. $args[$n] = $tmp;
  270. }
  271. }
  272. $args[] = &$data;
  273. call_user_func_array('array_multisort', $args);
  274. return array_pop($args);
  275. }
  276. function secure_user_vars($var){
  277. if(is_array($var)){
  278. $array = array();
  279. foreach($var as $key=>$value):
  280. $array[secure_user_vars($key)] = secure_user_vars($value);
  281. endforeach;
  282. return $array;
  283. } else {
  284. return str_replace('&amp;','&',htmlspecialchars($var, ENT_NOQUOTES, "UTF-8"));
  285. }
  286. }
  287. function base64_to_image($base64_string, $output_file) {
  288. $ifp = fopen($output_file, "wb");
  289. $data = explode(',', $base64_string);
  290. fwrite($ifp, base64_decode($data[1]));
  291. fclose($ifp);
  292. return $output_file;
  293. }
  294. function getExt($file){
  295. $ext = explode('.',$file);
  296. return strtolower(array_pop($ext));
  297. }
  298. function get_gravatar($mail,$size = 100){
  299. return file_get_contents("http://www.gravatar.com/avatar/" . md5( strtolower( trim( $mail ) ) ) . "?&s=".$size);
  300. }
  301. function getExtIcon($ext){
  302. $icon = '';
  303. switch($ext){
  304. case '7z':
  305. case 'rar':
  306. case 'gz':
  307. case 'zip':
  308. $icon = 'far fa-file-archive text-warning';
  309. break;
  310. case 'php':
  311. case 'js':
  312. case 'py':
  313. case 'c':
  314. case 'cpp':
  315. case 'css':
  316. case 'h':
  317. case 'hpp':
  318. case 'html':
  319. case 'htm':
  320. case 'asp':
  321. case 'jsp':
  322. $icon = 'fas fa-file-code text-secondary text-warning';
  323. break;
  324. case 'xls':
  325. case 'xlsx':
  326. case 'xlsb':
  327. case 'csv':
  328. $icon = 'far fa-file-excel text-success';
  329. break;
  330. case 'bmp':
  331. case 'jpg':
  332. case 'jfif':
  333. case 'jpeg':
  334. case 'ico':
  335. case 'gif':
  336. case 'png':
  337. case 'svg':
  338. $icon = 'far fa-file-image text-info';
  339. break;
  340. case 'pdf':
  341. $icon = 'far fa-file-pdf text-danger';
  342. break;
  343. case 'ppt':
  344. case 'pptx':
  345. $icon = 'fa-file-powerpoint-o text-warning' ;
  346. break;
  347. case 'txt':
  348. case 'htaccess':
  349. case 'md':
  350. $icon = 'far fa-file-alt';
  351. break;
  352. case 'doc':
  353. case 'docx':
  354. case 'word':
  355. $icon = 'far fa-file-word text-primary';
  356. break;
  357. case 'avi':
  358. case 'wmv':
  359. case 'mov':
  360. case 'divx':
  361. case 'xvid':
  362. case 'mkv':
  363. case 'flv':
  364. case 'mpeg':
  365. case 'h264':
  366. case 'rmvb':
  367. case 'mp4':
  368. $icon = 'far fa-file-video text-secondary';
  369. break;
  370. case 'wav':
  371. case 'ogg':
  372. case 'ogv':
  373. case 'ogx':
  374. case 'oga':
  375. case 'riff':
  376. case 'bwf':
  377. case 'wma':
  378. case 'flac':
  379. case 'aac':
  380. case 'mp3':
  381. $icon = 'far fa-file-audio text-secondary';
  382. break;
  383. default:
  384. $icon = 'far fa-file';
  385. break;
  386. }
  387. return $icon;
  388. }
  389. function getExtContentType($ext){
  390. $cType = '';
  391. switch($ext){
  392. case '7z':
  393. $cType = 'application/x-7z-compressed';
  394. break;
  395. case 'rar':
  396. $cType = 'application/x-rar-compressed';
  397. break;
  398. case 'gz':
  399. $cType = 'application/x-gzip';
  400. break;
  401. case 'zip':
  402. $cType = 'application/zip';
  403. break;
  404. case 'xls':
  405. $cType = 'application/vnd.ms-excel';
  406. break;
  407. case 'xlsx':
  408. $cType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
  409. break;
  410. case 'csv':
  411. $cType = 'text/csv';
  412. break;
  413. case 'jpg':
  414. case 'jpeg':
  415. $cType = 'image/jpeg';
  416. break;
  417. case 'bmp':
  418. case 'gif':
  419. case 'png':
  420. $cType = 'image/'.$ext;
  421. break;
  422. case 'ppt':
  423. $cType = 'application/vnd.ms-powerpoint';
  424. break;
  425. case 'pptx':
  426. $cType = 'application/vnd.openxmlformats-officedocument.presentationml.presentation';
  427. break;
  428. case 'pdf':
  429. $cType = 'application/pdf';
  430. break;
  431. case 'txt':
  432. $cType = 'text/plain';
  433. break;
  434. case 'doc':
  435. case 'word':
  436. $cType = 'application/msword';
  437. break;
  438. case 'docx':
  439. $cType = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
  440. break;
  441. case 'aac':
  442. case 'wav':
  443. $cType = 'audio/'.$ext;
  444. break;
  445. $cType = 'audio/aac';
  446. break;
  447. case 'mp3':
  448. $cType = 'audio/mpeg3';
  449. break;
  450. case 'otf':
  451. case 'ttf':
  452. case 'woff':
  453. case 'woff2':
  454. $cType = 'font/'.$ext;
  455. break;
  456. default:
  457. $cType = 'application/octet-stream';
  458. break;
  459. }
  460. return $cType;
  461. }
  462. function max_upload_size($limits = array()){
  463. $limits[] = str_replace('M','',ini_get('post_max_size')) *1048576;
  464. $limits[] = str_replace('M','',ini_get('upload_max_filesize')) *1048576;
  465. return readable_size(min($limits));
  466. }
  467. function readable_size($bytes)
  468. {
  469. if(empty($bytes) || !is_numeric($bytes)) return '0 o';
  470. if($bytes<1024){
  471. return round(($bytes / 1024), 2).' o';
  472. }elseif(1024<$bytes && $bytes<1048576){
  473. return round(($bytes / 1024), 2).' ko';
  474. }elseif(1048576<=$bytes && $bytes<1073741824){
  475. return round(($bytes / 1024)/1024, 2).' Mo';
  476. }elseif(1073741824<=$bytes){
  477. return round(($bytes / 1024)/1024/1024, 2).' Go';
  478. }
  479. }
  480. function relative_time($date, $date2=null, $relativeLimit=null, $detailled=false){
  481. $from = new DateTime();
  482. $from->setTimestamp($date);
  483. $to = new DateTime("now");
  484. if(isset($date2)) $to->setTimestamp($date2);
  485. $intervalle = $from->diff($to);
  486. if(isset($relativeLimit) && $intervalle->days > $relativeLimit){
  487. $limitFormat = $detailled ? 'd/m/Y - H:i' : 'd/m/Y';
  488. return date($limitFormat, $date);
  489. }
  490. $prefixe = $from > $to ? 'Dans ' :'Il y a ' ;
  491. if(isset($date2)) $prefixe = '';
  492. $years = $intervalle->format('%y');
  493. $month = $intervalle->format('%m');
  494. $days = $intervalle->format('%d');
  495. $hours = $intervalle->format('%h');
  496. $minutes = $intervalle->format('%i');
  497. if ($years != 0) {
  498. $relative_date = $prefixe . $years . ' an' . (($years > 1) ? 's' : '');
  499. if ($month >= 6) $relative_date .= ' et demi';
  500. } elseif ($month != 0) {
  501. $relative_date = $prefixe . $month . ' mois';
  502. if ($days >= 15) $relative_date .= ' et demi';
  503. } elseif ($days != 0) {
  504. $relative_date = $prefixe . $days . ' jour' . (($days > 1) ? 's' : '');
  505. } elseif ($hours != 0) {
  506. $relative_date = $prefixe . $hours . ' heure' . (($hours > 1) ? 's' : '');
  507. } elseif ($minutes != 0) {
  508. $relative_date = $prefixe . $minutes . ' minute' . (($minutes > 1) ? 's' : '');
  509. } else {
  510. $relative_date = $prefixe . ' quelques secondes';
  511. }
  512. return $relative_date;
  513. }
  514. function image_resize($image,$w,$h){
  515. $resource = imagecreatefromstring(file_get_contents($image));
  516. $size = getimagesize($image);
  517. $h = (($size[1] * (($w)/$size[0])));
  518. $thumbnail = imagecreatetruecolor($w , $h);
  519. imagecopyresampled($thumbnail ,$resource, 0,0, 0,0, $w, $h, $size[0],$size[1]);
  520. imagedestroy($resource);
  521. imagejpeg($thumbnail , $image, 100);
  522. }
  523. function arand($array){
  524. return $array[array_rand($array)];
  525. }
  526. //Convertis une date en timestamp
  527. //(format possible dd-mm-yyyy ou dd/mm/yyyy)
  528. function timestamp_date($date){
  529. $date = explode('/',str_replace('-', '/', $date));
  530. if(count($date)!=3) return 0;
  531. $year = $date[2];
  532. $m = 0;
  533. $h = 0;
  534. if(strpos($year, ':')){
  535. $yinfos = explode(' ',$year);
  536. $year = $yinfos[0];
  537. list($h,$m) = explode(':',$yinfos[1]);
  538. }
  539. return mktime($h,$m,0,$date[1],$date[0],$year);
  540. }
  541. //Convertis une heur en timestamp à partir du 01/01/1970
  542. //(format possible hh:mm)
  543. function timestamp_hour($hour){
  544. $hour = explode(':',$hour);
  545. if(count($hour)!=2) return 0;
  546. return mktime($hour[0],$hour[1],0,1,1,1970);
  547. }
  548. // Récupère la différence entre 2 dates
  549. // avec le format spécifique fourni en paramètres
  550. // On compare Date1 à Date2
  551. // (format possible)
  552. function format_date_diff($date1, $date2, $format='%a'){
  553. $datetime1 = date_create($date1);
  554. $datetime2 = date_create($date2);
  555. $interval = $datetime1->diff($datetime2);
  556. return $interval->format($format);
  557. }
  558. /**
  559. * Normalise un tableau de filtres pour le composant Filter
  560. *
  561. * $filters : Array => tableau des paramètres avancés au format
  562. * array(
  563. * "jean", //Mot clé de la recherche simple
  564. * array(
  565. * 'nom_de_votre_colonne:operateur' => 'valeur_attendue',
  566. * 'join' => 'and|or', //Facultatif
  567. * ),
  568. * etc... (à répéter pour les N critères)
  569. * )
  570. * Eg. :
  571. * filters_default(array(
  572. * "jean",
  573. * array(
  574. * 'birth' => "17/09/1998",
  575. * 'join' => 'or'
  576. * ),
  577. * array(
  578. * 'phone:like' => "9754"
  579. * )
  580. * ));
  581. */
  582. function filters_default($filters){
  583. $finalFilters = array();
  584. foreach ($filters as $filter) {
  585. //Gestion du keyword
  586. if(!is_array($filter) && !is_object($filter)){
  587. array_unshift($finalFilters, $filter);
  588. continue;
  589. }
  590. $tempFilter = array();
  591. foreach ($filter as $column => $value) {
  592. //Gestion du join
  593. if ($column == 'join') {
  594. $tempFilter['join'] = $value;
  595. continue;
  596. }
  597. //Gestion de la colonne ciblée avec opérator
  598. $column = explode(':', $column);
  599. $tempFilter['column'] = $column[0];
  600. if(isset($column[1])) $tempFilter['operator'] = $column[1];
  601. //Gestion de la value
  602. $tempFilter['value'] = $value;
  603. }
  604. if(!empty($tempFilter)) $finalFilters[] = $tempFilter;
  605. }
  606. return filters_set($finalFilters);
  607. }
  608. /**
  609. * Normalise et contrôles sur un tableau
  610. * de filtres pour le composant Filter.
  611. *
  612. * $filters : Array => tableau des paramètres avancés au format
  613. * array(
  614. * "jean", //Mot clé de la recherche simple, peut aussi être nommée 'keyword' => "jean"
  615. * array(
  616. * 'column' => 'nom_de_votre_colonne]',
  617. * 'operator' => '=|!=|LIKE:<:>', //Facultatif => "=" par défaut
  618. * 'value' => 'valeur_attendue', //Peut être du type array si plusieurs valeurs attendues
  619. * 'join' => 'and|or' //Facultatif => "and" par défaut
  620. * ),
  621. * etc... (à répéter pour les N critères)
  622. * )
  623. * Eg. :
  624. * filters_set(array(
  625. * 'test',
  626. * array(
  627. * 'column' => 'login',
  628. * 'value' => 'admin'
  629. * )
  630. * ));
  631. */
  632. function filters_set($filters){
  633. if(!is_array($filters)) return array();
  634. $finalFilters = array(
  635. 'k' => '',
  636. 'a' => array()
  637. );
  638. foreach ($filters as $key => $filter) {
  639. if($key==="keyword" || (!is_array($filter)) ) {
  640. $finalFilters['k'] = $filter;
  641. continue;
  642. }
  643. if(isset($filter['group'])){
  644. $subfilters = filters_set($filter['group']);
  645. if(isset($subfilters['a'])) $finalFilters['a'][] = array('g'=>$subfilters['a']);
  646. continue;
  647. }
  648. if(!isset($filter['column']) || !isset($filter['value'])) continue;
  649. $filter['operator'] = isset($filter['operator']) ? $filter['operator'] : '=';
  650. $filter['operator'] = html_entity_decode($filter['operator']);
  651. if(!in_array(strtolower($filter['operator']), array('<','>','=','!=','like','not like','between','is null','is not null'))) continue;
  652. $tempFilter = array(
  653. "c" => $filter['column'],
  654. "o" => $filter['operator'],
  655. "v" => is_array($filter['value']) ? $filter['value'] : array($filter['value']),
  656. );
  657. if(isset($filter['subcolumn'])) $tempFilter['s'] = $filter['subcolumn'];
  658. if(isset($filter['join'])){
  659. if(!in_array(strtolower($filter['join']), array('and','or'))) continue;
  660. $tempFilter['j'] = $filter['join'];
  661. }
  662. if(isset($filter['type'])) $tempFilter['t'] = $filter['type'];
  663. $finalFilters['a'][] = $tempFilter;
  664. }
  665. return $finalFilters;
  666. }
  667. //altère un fitlre de recherche avancée de façon personnalisée et récursive
  668. function filter_alteration($filters,$index,$mutator){
  669. foreach ($filters as $key => $value) {
  670. if(isset($value['group'])){
  671. $filters[$key]['group'] = filter_alteration($filters[$key]['group'],$index,$mutator);
  672. }else{
  673. if($value['column'] != $index) continue;
  674. $initialFilter = $filters[$key];
  675. $filters[$key] = $mutator($value);
  676. //Si la fonction d'alteration retourne null on supprime le filtre initial
  677. if($filters[$key] == null){
  678. //Gestion des joins, si le filtre supprimé avait un prédécesseur
  679. if(isset($filters[$key-1])){
  680. //si le filtre supprimé avait un join, on le transfere au prédécesseur
  681. if(isset($filters[$key+1]) && !empty($initialFilter['join']) ){
  682. $filters[$key-1]['join'] = $initialFilter['join'];
  683. //sinon on se content de supprimer le join du prédecesseur
  684. }else{
  685. unset($filters[$key-1]['join']);
  686. }
  687. }
  688. //suppression du filtre
  689. unset($filters[$key]);
  690. }
  691. }
  692. }
  693. return $filters;
  694. }
  695. // Construit une requete sécurisée pour le composant filtre
  696. function filter_secure_query($filters,$allowedColumns,&$query,&$data,$iteration = 0,$columnEscape="`"){
  697. if($iteration==0 && !empty($filters)) $query .= ' AND (';
  698. global $databases_credentials;
  699. $connector = $databases_credentials['local']['connector'];
  700. $operators = $connector::operators();
  701. $allowedOperators = array_keys($operators);
  702. foreach ($filters as $filter) {
  703. if(isset($filter['group'])){
  704. $query .= ' ( ';
  705. filter_secure_query($filter['group'],$allowedColumns,$query,$data,$iteration+1);
  706. $query .= ' ) ';
  707. }else{
  708. $filter['operator'] = html_entity_decode($filter['operator']);
  709. if(!in_array($filter['column'], $allowedColumns)) throw new Exception("Colonne '".$filter['column']."' interdite", 400);
  710. if(!in_array(strtolower($filter['operator']), $allowedOperators)) return;
  711. if(isset($filter['join']) && !in_array(strtolower($filter['join']), array('and','or'))) return;
  712. if(!preg_match("/.*\..*/i", $filter['column']))
  713. $filter['column'] = $columnEscape.$filter['column'].$columnEscape;
  714. if(strtolower($filter['type']) == 'date' && isset($filter['value'])){
  715. $filter['column'] = 'UNIX_TIMESTAMP(STR_TO_DATE(DATE_FORMAT(FROM_UNIXTIME('.$filter['column'].'),"%d/%m/%Y"), "%d/%m/%Y"))';
  716. if(is_array($filter['value'])){
  717. foreach($filter['value'] as $j=>$value){
  718. $filter['value'][$j] = timestamp_date($value);
  719. }
  720. } else {
  721. $filter['value'] = timestamp_date($filter['value']);
  722. }
  723. }
  724. $operator = $operators[strtolower($filter['operator'])];
  725. if(is_string($operator['sql'])){
  726. $method = function($column,$value = null,&$query,&$data) use($operator){
  727. $query .= str_replace(array('{{column}}','{{value}}'),array($column,'?'),$operator['sql']);
  728. if(isset($value) && isset($value[0])) $data[] = $value[0];
  729. };
  730. }else{
  731. $method = $operator['sql'];
  732. }
  733. $query.=' ( ';
  734. $method($filter['column'],isset($filter['value'])?$filter['value']:null,$query,$data);
  735. $query.=' ) ';
  736. }
  737. if(isset($filter['join'])) $query .= ' '.$filter['join'].' ';
  738. }
  739. if($iteration==0 && !empty($filters)) $query .= ')';
  740. }
  741. //remplace {{column}} par les colonnes dans $available - les colonnes dans $_['columns']['unselected']
  742. function column_secure_query($columns,$_,&$query){
  743. $unselected = isset($_['columns']) && isset($_['columns']['unselected']) ? $_['columns']['unselected'] : array();
  744. $columns = array_diff($columns, $unselected);
  745. $query = str_replace('{{columns}}',implode(',',$columns),$query);
  746. }
  747. function sort_secure_query($sort,$allowedColumns,&$query){
  748. if(!in_array($sort['sortable'], $allowedColumns)) return;
  749. if(!in_array(strtolower($sort['sort']), array('asc','desc',''))) return;
  750. $query .= ' ORDER BY '.$sort['sortable'].' '.$sort['sort'];
  751. }
  752. function check_mail($mail){
  753. return ($mail && !empty($mail) && filter_var($mail, FILTER_VALIDATE_EMAIL));
  754. }
  755. function truncate($text, $length = 100, $options = array()) {
  756. $default = array(
  757. 'ending' => '...',
  758. 'exact' => true,
  759. 'html' => false,
  760. 'keepTags' => true,
  761. );
  762. $options = array_merge($default, $options);
  763. extract($options);
  764. if ($html) {
  765. if (mb_strlen(preg_replace('/<.*?>/', '', $text)) <= $length) {
  766. return $text;
  767. }
  768. $totalLength = mb_strlen(strip_tags($ending));
  769. $openTags = array();
  770. $truncate = '';
  771. preg_match_all('/(<\/?([\w+]+)[^>]*>)?([^<>]*)/', $text, $tags, PREG_SET_ORDER);
  772. foreach ($tags as $tag) {
  773. if (!preg_match('/img|br|input|hr|area|base|basefont|col|frame|isindex|link|meta|param/s', $tag[2])) {
  774. if (preg_match('/<[\w]+[^>]*>/s', $tag[0])) {
  775. array_unshift($openTags, $tag[2]);
  776. } else if (preg_match('/<\/([\w]+)[^>]*>/s', $tag[0], $closeTag)) {
  777. $pos = array_search($closeTag[1], $openTags);
  778. if ($pos !== false) {
  779. array_splice($openTags, $pos, 1);
  780. }
  781. }
  782. }
  783. $truncate .= $tag[1];
  784. $contentLength = mb_strlen(preg_replace('/&[0-9a-z]{2,8};|&#[0-9]{1,7};|&#x[0-9a-f]{1,6};/i', ' ', $tag[3]));
  785. if ($contentLength + $totalLength > $length) {
  786. $left = $length - $totalLength;
  787. $entitiesLength = 0;
  788. if (preg_match_all('/&[0-9a-z]{2,8};|&#[0-9]{1,7};|&#x[0-9a-f]{1,6};/i', $tag[3], $entities, PREG_OFFSET_CAPTURE)) {
  789. foreach ($entities[0] as $entity) {
  790. if ($entity[1] + 1 - $entitiesLength <= $left) {
  791. $left--;
  792. $entitiesLength += mb_strlen($entity[0]);
  793. } else {
  794. break;
  795. }
  796. }
  797. }
  798. $truncate .= mb_substr($tag[3], 0 , $left + $entitiesLength);
  799. break;
  800. } else {
  801. $truncate .= $tag[3];
  802. $totalLength += $contentLength;
  803. }
  804. if ($totalLength >= $length) {
  805. break;
  806. }
  807. }
  808. } else {
  809. if (mb_strlen($text) <= $length) {
  810. return $text;
  811. } else {
  812. $truncate = mb_substr($text, 0, $length - mb_strlen($ending));
  813. }
  814. }
  815. if (!$exact) {
  816. $spacepos = mb_strrpos($truncate, ' ');
  817. if (isset($spacepos)) {
  818. if ($html) {
  819. $bits = mb_substr($truncate, $spacepos);
  820. preg_match_all('/<\/([a-z]+)>/', $bits, $droppedTags, PREG_SET_ORDER);
  821. if (!empty($droppedTags)) {
  822. foreach ($droppedTags as $closingTag) {
  823. if (!in_array($closingTag[1], $openTags)) {
  824. array_unshift($openTags, $closingTag[1]);
  825. }
  826. }
  827. }
  828. }
  829. $truncate = mb_substr($truncate, 0, $spacepos);
  830. }
  831. }
  832. $truncate .= $ending;
  833. if ($html) {
  834. foreach ($openTags as $tag) {
  835. $truncate .= '</'.$tag.'>';
  836. }
  837. }
  838. return (!$keepTags ? strip_tags($truncate) : $truncate);
  839. }
  840. /**
  841. * Permet de tronquer un texte en fonction d'un
  842. * nombre de caractères donné
  843. * @param string $content le texte à tronquer
  844. * @param int $limit le nombre de caractères qu'on garde
  845. * @param string $limiter le caractère de remplacement de fin de chaine
  846. * @return string le texte final, tronqué
  847. */
  848. function truncate_content($content,$limit,$limiter){
  849. if(strlen($content)>$limit) $content = mb_substr($content, 0,$limit).$limiter;
  850. return $content;
  851. }
  852. //Permet de décoder la chaîne d'entrée $string
  853. //en UTF-8 et de décoder les caractères spéciaux
  854. //pour l'affichage HTML
  855. function html_decode_utf8($string){
  856. return htmlspecialchars(html_entity_decode($string), ENT_QUOTES, 'UTF-8');
  857. }
  858. //Convertit la première lettre de la chaine $string
  859. //en majuscule et le reste de la chaine en minuscule UTF-8
  860. //pour l'affichage HTML
  861. function mb_ucfirst($string,$encoding = 'UTF-8'){
  862. $length = mb_strlen($string, $encoding);
  863. $firstChar = mb_substr($string, 0, 1, $encoding);
  864. $rest = mb_substr($string, 1, $length - 1, $encoding);
  865. return mb_strtoupper($firstChar, $encoding).$rest;
  866. }
  867. // Permet de mettre au bon format le n° de
  868. // téléphone fourni dans le formulaire
  869. function normalize_phone_number($number){
  870. $nb = str_replace(array(' ', '.', ',', '-'), '', $number);
  871. $nb = chunk_split($nb, 2, ' ');
  872. $nb = rtrim($nb);
  873. preg_match("/^[0-9]{2} [0-9]{2} [0-9]{2} [0-9]{2} [0-9]{2}/", $nb, $matches);
  874. return isset($matches[0]) ? $matches[0] : $nb;
  875. }
  876. // Permet de voir si le format du n° de téléphone
  877. // fourni correspond à un format correct
  878. function check_phone_number($number, $international=false){
  879. if(!$international && preg_match("/\+/i", $number)) return false;
  880. $nb = str_replace(array(' ', '.', ',', '-'), '', $number);
  881. if (!is_numeric($nb)) return false;
  882. return true;
  883. }
  884. //Retourne la valeur la plus proche d'un
  885. //nombre donné par rapport à un tableau de
  886. //nombres
  887. function get_closest_number($search, $arr){
  888. $closest = null;
  889. foreach ($arr as $item) {
  890. if ($closest === null || abs($search - $closest) > abs($item - $search)) {
  891. $closest = $item;
  892. }
  893. }
  894. return $closest;
  895. }
  896. // Permet de convertir string encodée en UTF-8
  897. // en ASCII pour ensuite appliquer une méthode
  898. // de Levenshtein sans avoir de divergences
  899. // trop importantes dues aux accents présents.
  900. function utf8_to_extended_ascii($str, &$map) {
  901. // find all multibyte characters (cf. utf-8 encoding specs)
  902. $matches = array();
  903. if (!preg_match_all('/[\xC0-\xF7][\x80-\xBF]+/', $str, $matches))
  904. return $str; // plain ascii string
  905. // update the encoding map with the characters not already met
  906. foreach ($matches[0] as $mbc)
  907. if (!isset($map[$mbc]))
  908. $map[$mbc] = chr(128 + count($map));
  909. // finally remap non-ascii characters
  910. return strtr($str, $map);
  911. }
  912. // Override de la méthode de Levenshtein pour
  913. // compérer 2 strings encondées en UTF-8
  914. function levenshtein_utf8($s1, $s2) {
  915. $charMap = array();
  916. $s1 = utf8_to_extended_ascii($s1, $charMap);
  917. $s2 = utf8_to_extended_ascii($s2, $charMap);
  918. return levenshtein($s1, $s2);
  919. }
  920. // Méthode qui retourne sous forme de tableau
  921. // les metaphones // des différents mots d'une
  922. // phrase.
  923. function get_metaphones($sentence) {
  924. $metaphones = array();
  925. $words = explode(' ',$sentence);
  926. foreach ($words as $word) {
  927. $metaphones[] = metaphone($word);
  928. }
  929. return $metaphones;
  930. }
  931. // Permet de trouver une chaîne de caractère s'approchant
  932. // le plus de l'entrée fournie en paramètres
  933. function find_best_match($words = array(), $input = '') {
  934. $closest = '';
  935. $foundBestMatch = -1;
  936. $tmpInput = implode(' ', get_metaphones($input));
  937. foreach($words as $word) {
  938. $tmpGauge = implode(' ', get_metaphones($word));
  939. $similarity = levenshtein_utf8($tmpInput, $tmpGauge);
  940. if ($similarity == 0) {
  941. $closest = $word;
  942. $foundBestMatch = 0;
  943. break;
  944. }
  945. if ($similarity <= $foundBestMatch || $foundBestMatch < 0) {
  946. $closest = $word;
  947. $foundBestMatch = $similarity;
  948. }
  949. }
  950. return $closest;
  951. }
  952. // Convertit nombres en lettres (utile pour Excel)
  953. function numbers_to_letters($num){
  954. $num = intval($num);
  955. $letter = '';
  956. if ($num <= 0) return $letter;
  957. while($num != 0){
  958. $p = ($num - 1) % 26;
  959. $num = intval(($num - $p) / 26);
  960. $letter = chr(65 + $p) . $letter;
  961. }
  962. return $letter;
  963. }
  964. //Convertit lettres en nombres (utile pour Excel)
  965. function letters_to_numbers($col){
  966. $col = str_pad($col,3,'0', STR_PAD_LEFT);
  967. $i = 0;
  968. if ($col[0] != '0') {
  969. $i = ((ord($col[0]) - 64) * 676) + 26;
  970. $i += ($col[1] == '0') ? 0 : (ord($col[1]) - 65) * 26;
  971. } else {
  972. $i += ($col[1] == '0') ? 0 : (ord($col[1]) - 64) * 26;
  973. }
  974. $i += ord($col[2]) - 64;
  975. return $i;
  976. }
  977. //Check si c'est un date bien formattée
  978. function is_date($date){
  979. $date = str_replace(array('-',' ','\\'),'/',trim($date));
  980. if(trim($date)=='') return false;
  981. if (count(explode('/',$date)) < 3) return false;
  982. list($d,$m,$y) = explode('/',$date);
  983. if( !is_numeric($d) || !is_numeric($m) || !is_numeric($y) ) return false;
  984. return checkdate ( $m , $d , $y );
  985. }
  986. //Cherche la position de $needles dans
  987. //$haystack, où $needles est un array
  988. //de string et $haystack est le string à
  989. //comparer
  990. function strpos_array($haystack, $needles=array(), $offset=0) {
  991. $chr = array();
  992. foreach($needles as $needle) {
  993. $res = strpos($haystack, $needle, $offset);
  994. if ($res !== false) $chr[$needle] = $res;
  995. }
  996. if(empty($chr)) return false;
  997. return min($chr);
  998. }
  999. //Supprime un dossier et son contenu
  1000. //de manière récursive
  1001. function delete_folder_tree($dir, $selfDestroy=false) {
  1002. if(!file_exists($dir)) return;
  1003. $files = array_diff(scandir($dir), array('.','..'));
  1004. foreach ($files as $file)
  1005. (is_dir("$dir/$file")) ? delete_folder_tree("$dir/$file") : unlink("$dir/$file");
  1006. if($selfDestroy) return rmdir($dir);
  1007. }
  1008. //Normalise les caractères un peu spéciaux
  1009. //d'une chaîne de caractère
  1010. function normalize_chars($string, $mask=array()) {
  1011. $normalizeChars = array(
  1012. 'Š'=>'S', 'š'=>'s', 'Ð'=>'Dj','Ž'=>'Z', 'ž'=>'z', 'À'=>'A', 'Á'=>'A', 'Â'=>'A', 'Ã'=>'A', 'Ä'=>'A',
  1013. 'Å'=>'A', 'Æ'=>'A', 'Ç'=>'C', 'È'=>'E', 'É'=>'E', 'Ê'=>'E', 'Ë'=>'E', 'Ì'=>'I', 'Í'=>'I', 'Î'=>'I',
  1014. 'Ï'=>'I', 'Ñ'=>'N', 'Ń'=>'N', 'Ò'=>'O', 'Ó'=>'O', 'Ô'=>'O', 'Õ'=>'O', 'Ö'=>'O', 'Ø'=>'O', 'Ù'=>'U',
  1015. 'Ú'=>'U', 'Û'=>'U', 'Ü'=>'U', 'Ý'=>'Y', 'Þ'=>'B', 'ß'=>'Ss','à'=>'a', 'á'=>'a', 'â'=>'a', 'ã'=>'a',
  1016. 'ä'=>'a', 'å'=>'a', 'æ'=>'a', 'ç'=>'c', 'è'=>'e', 'é'=>'e', 'ê'=>'e', 'ë'=>'e', 'ì'=>'i', 'í'=>'i',
  1017. 'î'=>'i', 'ï'=>'i', 'ð'=>'o', 'ñ'=>'n', 'ń'=>'n', 'ò'=>'o', 'ó'=>'o', 'ô'=>'o', 'õ'=>'o', 'ö'=>'o',
  1018. 'ø'=>'o', 'ù'=>'u', 'ú'=>'u', 'û'=>'u', 'ü'=>'u', 'ý'=>'y', 'ý'=>'y', 'þ'=>'b', 'ÿ'=>'y', 'ƒ'=>'f',
  1019. 'ă'=>'a', 'î'=>'i', 'â'=>'a', 'ș'=>'s', 'ț'=>'t', 'Ă'=>'A', 'Î'=>'I', 'Â'=>'A', 'Ș'=>'S', 'Ț'=>'T',
  1020. '’'=>'\'', '–'=>'-', '€'=>'&euro;', '&'=>'&amp;','œ'=>'oe', '•'=>'-'
  1021. );
  1022. return strtr($string, array_diff_key($normalizeChars, array_flip($mask)));
  1023. }
  1024. //Convertit un nombre en son équivalent écrit
  1025. //e.g: 23 --> VINGT-TROIS
  1026. function number_to_words($number, $feminine=false) {
  1027. $hyphen = '-';
  1028. $conjunction = ' et ';
  1029. $negative = 'moins ';
  1030. $decimal = ' virgule ';
  1031. $dictionary = array(
  1032. 0 => 'zero',
  1033. 1 => !$feminine?'un':'une',
  1034. 2 => 'deux',
  1035. 3 => 'trois',
  1036. 4 => 'quatre',
  1037. 5 => 'cinq',
  1038. 6 => 'six',
  1039. 7 => 'sept',
  1040. 8 => 'huit',
  1041. 9 => 'neuf',
  1042. 10 => 'dix',
  1043. 11 => 'onze',
  1044. 12 => 'douze',
  1045. 13 => 'treize',
  1046. 14 => 'quatorze',
  1047. 15 => 'quinze',
  1048. 16 => 'seize',
  1049. 17 => 'dix-sept',
  1050. 18 => 'dix-huit',
  1051. 19 => 'dix-neuf',
  1052. 20 => 'vingt',
  1053. 30 => 'trente',
  1054. 40 => 'quarante',
  1055. 50 => 'cinquante',
  1056. 60 => 'soixante',
  1057. 70 => 'soixante-dix',
  1058. 80 => 'quatre-vingt',
  1059. 90 => 'quatre-vingt dix',
  1060. 100 => 'cent',
  1061. 1000 => 'mille',
  1062. 1000000 => 'million',
  1063. 1000000000 => 'milliard',
  1064. 1000000000000 => 'trillion',
  1065. 1000000000000000 => 'quadrillion',
  1066. 1000000000000000000 => 'quintillion'
  1067. );
  1068. if (!is_numeric($number)) return false;
  1069. if (($number >= 0 && (int) $number < 0) || (int) $number < 0 - PHP_INT_MAX) throw new Exception('number_to_words accepte uniquement des nombres compris entre -'.PHP_INT_MAX.' et '.PHP_INT_MAX);
  1070. if ($number < 0) return $negative.number_to_words(abs($number));
  1071. $string = $fraction = null;
  1072. if (strpos($number, '.') !== false)
  1073. list($number, $fraction) = explode('.', $number);
  1074. switch (true) {
  1075. case $number < 21:
  1076. $string = $dictionary[$number];
  1077. break;
  1078. case $number == 21:
  1079. $string = $dictionary[20].$conjunction.$dictionary[1];
  1080. break;
  1081. case $number == 31:
  1082. $string = $dictionary[30].$conjunction.$dictionary[1];
  1083. break;
  1084. case $number == 41:
  1085. $string = $dictionary[40].$conjunction.$dictionary[1];
  1086. break;
  1087. case $number == 51:
  1088. $string = $dictionary[50].$conjunction.$dictionary[1];
  1089. break;
  1090. case $number == 61:
  1091. $string = $dictionary[60].$conjunction.$dictionary[1];
  1092. break;
  1093. case $number == 71:
  1094. $string = $dictionary[60].$conjunction.$dictionary[11];
  1095. break;
  1096. case $number == 81:
  1097. $string = $dictionary[80].$hyphen.$dictionary[1];
  1098. break;
  1099. case $number == 91:
  1100. $string = $dictionary[80].$hyphen.$dictionary[11];
  1101. break;
  1102. case $number < 100:
  1103. $tens = ((int) ($number / 10)) * 10;
  1104. $units = $number % 10;
  1105. $string = $dictionary[$tens];
  1106. if ($units) {
  1107. $string .= $hyphen . $dictionary[$units];
  1108. }
  1109. break;
  1110. case $number < 1000:
  1111. $hundreds = $number / 100;
  1112. $remainder = $number % 100;
  1113. $string = ((int)$hundreds==1 ? '' : $dictionary[$hundreds].' ') . $dictionary[100];
  1114. if ($remainder) {
  1115. $string .= ' ' . number_to_words($remainder);
  1116. }
  1117. break;
  1118. default:
  1119. $baseUnit = pow(1000, floor(log($number, 1000)));
  1120. $numBaseUnits = (int) ($number / $baseUnit);
  1121. $remainder = $number % $baseUnit;
  1122. $string = number_to_words($numBaseUnits) . ' ' . $dictionary[$baseUnit];
  1123. if ($remainder) {
  1124. $string .= $remainder < 100 ? $conjunction : ' ';
  1125. $string .= number_to_words($remainder);
  1126. }
  1127. break;
  1128. }
  1129. if (null !== $fraction && is_numeric($fraction)) {
  1130. $string .= $decimal;
  1131. if(strlen($fraction) <= 3) {
  1132. $string .= number_to_words($fraction);
  1133. } else {
  1134. $words = array();
  1135. foreach (str_split((string) $fraction) as $number)
  1136. $words[] = $dictionary[$number];
  1137. $string .= implode(' ', $words);
  1138. }
  1139. }
  1140. return mb_strtoupper($string);
  1141. }
  1142. /**
  1143. * Retrourne le numéral ordinal compact
  1144. * d'un nombre passé en paramètre.
  1145. * eg:
  1146. * 1 --> 1er,
  1147. * 2 --> 2ème, etc..
  1148. * Les nombres ordinaux sont définis par un
  1149. * l'ensemble des entiers naturels non nuls
  1150. * représenté N*={1,2,3,...}
  1151. */
  1152. function number_to_ordinal($number, $feminine=false){
  1153. $number = (int) $number;
  1154. //Aucun ordinal pour le rang 0
  1155. if($number == 0) return;
  1156. if($number == 1)
  1157. return $number.($feminine?'ère':'er');
  1158. return $number.'ème';
  1159. }
  1160. /**
  1161. * Vérifie si un nombre est entre 2 bornes
  1162. * Possibilité d'inclure ou d'exclure les bornes avec $strict
  1163. */
  1164. function number_between($number, $low, $high, $strict=false) {
  1165. if(!$strict && ($number<$low || $number>$high)) return false;
  1166. if($strict && ($number<=$low || $number>=$high)) return false;
  1167. return true;
  1168. }
  1169. /*
  1170. * Fonction pour vérifier si un nombre
  1171. * est un nombre décimal
  1172. *
  1173. * Eg: - 95.00 --> false
  1174. * - 95.5 --> true
  1175. * Les nombres avec décimales à 0 sont donc exclus
  1176. */
  1177. function is_decimal($val) {
  1178. return is_numeric($val) && floor($val)!=$val;
  1179. }
  1180. /**
  1181. * Retourne les fonction interdites
  1182. * utilisées dans une fonction eval()
  1183. * @param string $source [le string qui va $etre eval()]
  1184. * @return Array [Tableau des méthodes utilisées interdites]
  1185. */
  1186. function forbidden_macro($source){
  1187. $tokens = token_get_all('<?php '.$source.' ?>');
  1188. $forbiddens = array();
  1189. $allowed_functions = array(
  1190. 'ucfirst',
  1191. 'strto.*',
  1192. 'str_.*',
  1193. 'substr',
  1194. 'password_encrypt',
  1195. 'strpos',
  1196. 'date',
  1197. '[im|ex]plode',
  1198. 'preg_*',
  1199. 'count',
  1200. 'time',
  1201. 'array_.*',
  1202. '.sort',
  1203. );
  1204. foreach($tokens as $token){
  1205. if(is_string($token)) continue;
  1206. list($id, $text,$line) = $token;
  1207. if(in_array($id, array(T_FUNCTION,T_FUNC_C,T_EVAL,T_STRING))){
  1208. $allowed = false;
  1209. foreach ($allowed_functions as $function) {
  1210. preg_match('/'.$function.'/i', $text, $matches);
  1211. if(count($matches)!=0){
  1212. $allowed = true;
  1213. break;
  1214. }
  1215. }
  1216. if(!$allowed) $forbiddens[] = $text.' L'.$line;
  1217. }
  1218. if(in_array($id, array(
  1219. T_INCLUDE,
  1220. T_EXTENDS,
  1221. T_CLONE,
  1222. T_EXIT,
  1223. T_GLOBAL,
  1224. T_HALT_COMPILER,
  1225. T_IMPLEMENTS,
  1226. T_INCLUDE_ONCE,
  1227. T_REQUIRE,
  1228. T_REQUIRE_ONCE,
  1229. T_IMPLEMENTS
  1230. ))){
  1231. $forbiddens[] = $text.' L'.$line;
  1232. }
  1233. }
  1234. return $forbiddens;
  1235. }
  1236. //Fonction respectant la syntaxe mustache (prototype a roder)
  1237. function mustache_template($stream,$data){
  1238. //blocks (loop, if, else)
  1239. $stream = preg_replace_callback('/\{\{(#|\^)?([^\}]*)\}\}(.*?)\{\{\/\2\}\}/is',function($matches) use ($data) {
  1240. $stream = '';
  1241. $expression = $matches[0];
  1242. $key = $matches[2];
  1243. $template = $matches[3];
  1244. if(!isset($data[$key])){
  1245. $stream = '';$expression;
  1246. return $stream;
  1247. }
  1248. $value = $data[$key];
  1249. //if ou loop
  1250. if($matches[1] == '#'){
  1251. //loop
  1252. if(is_array($value)) {
  1253. $length = count($value);
  1254. $i = 0;
  1255. foreach ($value as $key=>$value2) {
  1256. //gère les exception de derniere occurence de boucle (ex,toutes les occurences finissent par , sauf la derniere)
  1257. // syntaxe : {{;}}mon texte partout sauf derniere occurence{{/;}}
  1258. $lastOccurenceReplace = $i!=$length-1 ? '$1' : '';
  1259. $lineTemplate = preg_replace('/\{\{;\}\}(.*)\{\{\/;\}\}/isU', $lastOccurenceReplace, $template);
  1260. $localData = is_array($value2) ? array_merge($data,$value2) : $data;
  1261. $stream.= mustache_template($lineTemplate,$localData);
  1262. $i++;
  1263. }
  1264. return $stream;
  1265. //if
  1266. }else{
  1267. if(!empty($value) && $value!=false){
  1268. return mustache_template($template,$data);
  1269. }
  1270. return '';
  1271. }
  1272. //else
  1273. }else if($matches[1] == '^'){
  1274. if(!$value) return mustache_template($template,$data);
  1275. return '';
  1276. //cas de block non gérés car sans char operateur # ou ^ ex : {{expression}}{{/expression}}
  1277. }else{
  1278. $stream = $expression;
  1279. return $stream;
  1280. }
  1281. },$stream);
  1282. //simple vars
  1283. $stream = preg_replace_callback('/\{\{([^\}]*)\}\}/isU',function($matches) use ($data) {
  1284. $key = $matches[1];
  1285. if(isset($data[$key]) && (is_string($data[$key]) || is_numeric($data[$key])) ) return $data[$key];
  1286. $value = '';
  1287. $attributes = explode('.',$key);
  1288. $current = $data;
  1289. foreach ($attributes as $attribute) {
  1290. if ( !isset($current[$attribute]) ) return;
  1291. $current = $current[$attribute];
  1292. $value = $current;
  1293. }
  1294. return $value;
  1295. },$stream);
  1296. return $stream;
  1297. }
  1298. function template($stream,$data,$mustacheTemplate = false){
  1299. if($mustacheTemplate) return mustache_template($stream,$data);
  1300. //loop
  1301. $stream = preg_replace_callback('/{{\:([^\/\:\?}]*)}}(.*?){{\/\:[^\/\:\?}]*}}/is',function($matches) use ($data) {
  1302. $tag = $matches[1];
  1303. $streamTpl = $matches[2];
  1304. $stream = '';
  1305. if(!isset($data[$tag])) return $stream;
  1306. $values = $data[$tag];
  1307. foreach($values as $join){
  1308. $occurence = $streamTpl;
  1309. foreach($join as $key=>$value){
  1310. if(is_array($value) || is_object($value)) continue;
  1311. $occurence = str_replace(array('{{'.$key.'}}'),array($value),$occurence);
  1312. }
  1313. $stream .= $occurence;
  1314. }
  1315. return $stream;
  1316. },$stream);
  1317. //conditions
  1318. $stream = preg_replace_callback('/{{\?([^\/\:\?}]*)}}(.*?){{\/\?[^\/\:\?}]*}}/is',function($matches) use ($data) {
  1319. $key = $matches[1];
  1320. $stream = $matches[2];
  1321. return !isset($data[$key]) || (is_array($data[$key]) && count($data[$key])==0) ?'':$stream;
  1322. },$stream);
  1323. //simple vars
  1324. $stream = preg_replace_callback('/{{([^\/\:\;\?}]*)}}/',function($matches) use ($data) {
  1325. $key = $matches[1];
  1326. if(isset($data[$key]) && (is_string($data[$key]) || is_numeric($data[$key])) ) return $data[$key];
  1327. $value = '';
  1328. $attributes = explode('.',$key);
  1329. $current = $data;
  1330. foreach ($attributes as $attribute) {
  1331. if ( !isset($current[$attribute]) ) return;
  1332. $current = $current[$attribute];
  1333. $value = $current;
  1334. }
  1335. return $value;
  1336. },$stream);
  1337. return $stream;
  1338. }
  1339. /**
  1340. * Auteur: Anonymous
  1341. * Lien: https://www.php.net/manual/en/features.file-upload.post-method.php#120686
  1342. *
  1343. * Normalise le tableau de fichier récupérés
  1344. * pour une utilisation plus efficace et intuitive
  1345. *
  1346. * Exemple de format initial pour 2 fichiers dans $_FILES :
  1347. * Array (
  1348. [name] => Array (
  1349. [0] => foo.txt
  1350. [1] => bar.txt
  1351. ),
  1352. [type] => Array(
  1353. [0] => text/plain
  1354. [1] => text/plain
  1355. ),
  1356. [tmp_name] => Array(
  1357. [0] => /tmp/phpYzdqkD
  1358. [1] => /tmp/phpeEwEWG
  1359. ),
  1360. [error] => Array(
  1361. [0] => 0
  1362. [1] => 0
  1363. ),
  1364. [size] => Array(
  1365. [0] => 123
  1366. [1] => 456
  1367. )
  1368. * )
  1369. *
  1370. * Exemple de format de retour pour 2 fichiers :
  1371. * Array(
  1372. [0] => Array(
  1373. [name] => foo.txt
  1374. [type] => text/plain
  1375. [tmp_name] => /tmp/phpYzdqkD
  1376. [error] => 0
  1377. [size] => 123
  1378. ),
  1379. [1] => Array(
  1380. [name] => bar.txt
  1381. [type] => text/plain
  1382. [tmp_name] => /tmp/phpeEwEWG
  1383. [error] => 0
  1384. [size] => 456
  1385. )
  1386. )
  1387. * @param Array &$file_post [tableau de fichiers $_FILES]
  1388. * @return Array [le tableau ré-arrangé]
  1389. */
  1390. function normalize_php_files() {
  1391. $function = function($files, $fixedFiles=array(), $path=array()) use (&$function) {
  1392. foreach ($files as $key => $value) {
  1393. $temp = $path;
  1394. $temp[] = $key;
  1395. if(is_array($value)) {
  1396. $fixedFiles = $function($value, $fixedFiles, $temp);
  1397. } else {
  1398. $next = array_splice($temp, 1, 1);
  1399. $temp = array_merge($temp, $next);
  1400. $new = &$fixedFiles;
  1401. foreach ($temp as $key)
  1402. $new = &$new[$key];
  1403. $new = $value;
  1404. }
  1405. }
  1406. return $fixedFiles;
  1407. };
  1408. return $function($_FILES);
  1409. }
  1410. /**
  1411. * Incrémente automatiquement le nom d'un
  1412. * fichier si celui-ci existe déjà
  1413. * Fonction récursive.
  1414. * @param String $extension [extension du fichier]
  1415. * @param String $folder [dossier où localiser le fichier]
  1416. * @param String $filename [nom du fichier]
  1417. * @return String [nom de fichier final]
  1418. */
  1419. function autoincrement_filename($extension, $folder, $filename){
  1420. static $counter = 0;
  1421. $fileNb = count(glob(FILE_PATH.$folder.$filename));
  1422. $filenameProps = explode('.', $filename);
  1423. unset($filenameProps[count($filenameProps)-1]);
  1424. $finalFilename = implode('.', $filenameProps);
  1425. if($fileNb>0) {
  1426. $counter+=1;
  1427. $filename = preg_match("/(^.*?\()(\d+)([^\\d]*\)\..*$)/", $filename, $matches) ? $matches[1].$counter.$matches[3] : $finalFilename.'('.$counter.')'.'.'.$extension;
  1428. $filename = autoincrement_filename($extension, $folder, $filename);
  1429. }
  1430. return $filename;
  1431. }
  1432. function relative_path($absolutePath,$reference = __ROOT__){
  1433. $absolutePath = str_replace(array('\\','/'),SLASH,$absolutePath);
  1434. $reference = str_replace(array('\\','/'),SLASH,$reference);
  1435. return str_replace($reference,'',$absolutePath);
  1436. }
  1437. //Définit si une couleur hexadecimale est claire
  1438. //ou sombre en fonction d'un seuil de luminosité
  1439. function get_light($hexcode,$treshold = 510.0) {
  1440. $rgb = to_rgb($hexcode);
  1441. return (max($rgb[0], $rgb[1], $rgb[2]) + min($rgb[0], $rgb[1], $rgb[2])) / $treshold;
  1442. }
  1443. //Génère une couleur hexadécimale aléatoire
  1444. function random_hex_color() {
  1445. return '#'.str_pad(dechex(mt_rand(0, 0xFFFFFF)), 6, '0', STR_PAD_LEFT);
  1446. }
  1447. //Génère une couleur pastel basé sur
  1448. //le hash md5 du mot passé en paramètre
  1449. function random_hex_pastel_color($name) {
  1450. $hash = md5($name);
  1451. $red = hexdec(substr($hash, 8, 2));
  1452. $green = hexdec(substr($hash, 4, 2));
  1453. $blue = hexdec(substr($hash, 0, 2));
  1454. if($red < 128) $red += 128;
  1455. if($green < 128) $green += 128;
  1456. if($blue < 128) $blue += 128;
  1457. return "#" . dechex($red) . dechex($green) . dechex($blue);
  1458. }
  1459. //Convertit un code hexadecimal en code RGB
  1460. function to_rgb($hexcode) {
  1461. $hexcode = substr($hexcode, 1);
  1462. return array(hexdec($hexcode[0] . $hexcode[1]),
  1463. hexdec($hexcode[2] . $hexcode[3]),
  1464. hexdec($hexcode[4] . $hexcode[5]));
  1465. }
  1466. //Retourne le nom complet d'un mois en fonction de son numéro
  1467. function month_name($month){
  1468. $translates = array('Janvier','Fevrier','Mars','Avril','Mai','Juin','Juillet','Aout','Septembre','Octobre','Novembre','Décembre');
  1469. return $translates[$month-1];
  1470. }
  1471. //Retourne le nom complet d'un jour en fonction de son numéro (1 : lundi,..., 7 :dimanche)
  1472. function day_name($day){
  1473. $translates = array('Lundi','Mardi','Mercredi','Jeudi','Vendredi','Samedi','Dimanche');
  1474. return isset($translates[$day-1])? $translates[$day-1]:$day;
  1475. }
  1476. //Convertit un timestamp dans un format
  1477. //agréable et complet : ex Mardi 18 Avril 2019
  1478. function complete_date($time=null){
  1479. if(!isset($time)) $time = time();
  1480. return day_name(date('N',$time)).' '.date('d',$time).' '.month_name(date('m',$time)).' '.date('Y',$time);
  1481. }
  1482. //Récuperation des jours féries
  1483. function get_not_workable($date=null){
  1484. if ($date === null)
  1485. $date = time();
  1486. $date = strtotime(date('m/d/Y',$date));
  1487. $year = date('Y',$date);
  1488. if($year < 1970 || $year > 2037) throw new exception("Date non valide inférieure à 1970 ou supérieure à 2037", 400);
  1489. $easterDate = easter_date($year);
  1490. $easterDay = date('j', $easterDate);
  1491. $easterMonth = date('n', $easterDate);
  1492. $easterYear = date('Y', $easterDate);
  1493. $holidays = array(
  1494. // Dates fixes
  1495. mktime(0, 0, 0, 1, 1, $year), // 1er janvier
  1496. mktime(0, 0, 0, 5, 1, $year), // Fête du travail
  1497. mktime(0, 0, 0, 5, 8, $year), // Victoire des alliés
  1498. mktime(0, 0, 0, 7, 14, $year), // Fête nationale
  1499. mktime(0, 0, 0, 8, 15, $year), // Assomption
  1500. mktime(0, 0, 0, 11, 1, $year), // Toussaint
  1501. mktime(0, 0, 0, 11, 11, $year), // Armistice
  1502. mktime(0, 0, 0, 12, 25, $year), // Noel
  1503. // Dates variables
  1504. mktime(0, 0, 0, $easterMonth, $easterDay + 1, $easterYear),
  1505. mktime(0, 0, 0, $easterMonth, $easterDay + 39, $easterYear),
  1506. mktime(0, 0, 0, $easterMonth, $easterDay + 50, $easterYear),
  1507. );
  1508. return $holidays;
  1509. }
  1510. //Retourne le chemin web d'un fichier en fonction de son chemin
  1511. //physique (ex : /img/logo.png pour /var/www/erp-core/img/logo.png)
  1512. function webpath($path){
  1513. $url = ROOT_URL.str_replace(array(__DIR__.SLASH,"\\","/"),array('','/','/'),$path);
  1514. $url = preg_replace('/([^\:])(\/{2,})/i', '$1/', $url);
  1515. return $url;
  1516. }
  1517. //Retourne un tableau clé/valeur des valeurs
  1518. //existantes en doublons du tableau passé en paramètre
  1519. function array_not_unique($array=array()){
  1520. return array_diff_key($array, array_unique($array));
  1521. }
  1522. //Retourne true si aucune valeur du tableau passé
  1523. //en paramètre a un doublon, false sinon.
  1524. function is_array_unique($array=array()){
  1525. return empty(array_not_unique($array));
  1526. }
  1527. function make_cookie($name, $value, $expire='', $ns ='/') {
  1528. if($expire == ''){
  1529. setcookie($name, $value, mktime(0,0,0, date("d"), date("m"), (date("Y")+1)), $ns);
  1530. } else {
  1531. setcookie($name, '', mktime(0,0,0, date("d"), date("m"), (date("Y")-1)), $ns);
  1532. }
  1533. }
  1534. //Permet de formatter les prix à afficher
  1535. //de la même manière partout sur l'ERP.
  1536. //Si jamais on veut changer de normalisation
  1537. //pour l'affichage des prix, il suffit de changer
  1538. //le fonctionnement ici uniquement.
  1539. function display_price($price){
  1540. return number_format($price, 2, ',', ' ');
  1541. }
  1542. //Permet de formatter les prix à enregistrer
  1543. //de la même manière partout sur l'ERP.
  1544. //Si jamais on veut changer de normalisation
  1545. //pour l'enregistrement des prix, il suffit de changer
  1546. //le fonctionnement ici uniquement.
  1547. function format_price($price){
  1548. return str_replace(',','.',$price);
  1549. }
  1550. //Permet de calculer un age en fonction de la date du jour
  1551. //Paramètre : la date de départ(format timestamp), l'unité de retour souhaitée(format 'd', 'm', 'Y'... voir fonction diff de php)
  1552. //Renvoie : l'age en entier
  1553. function age($from,$unit = 'y'){
  1554. if(!isset($from) || !is_numeric($from)) return 'N/A';
  1555. $from = new \DateTime(date('Y-m-d',$from));
  1556. $to = new \DateTime('today');
  1557. $age = $from->diff($to);
  1558. if(!$age || !array_key_exists($unit, $age))
  1559. return 'N/A';
  1560. return $age = $age->$unit;
  1561. }
  1562. //Permet d'échapper tous les caractères interdits dans une chaine json
  1563. function escape_json_string($value) { # list from www.json.org: (\b backspace, \f formfeed)
  1564. $escapers = array("\\", "/", "\"", "\n", "\r", "\t", "\x08", "\x0c");
  1565. $replacements = array("\\\\", "\\/", "\\\"", "\\n", "\\r", "\\t", "\\f", "\\b");
  1566. $result = str_replace($escapers, $replacements, $value);
  1567. return $result;
  1568. }
  1569. if( !function_exists('apache_request_headers') ) {
  1570. ///
  1571. function apache_request_headers() {
  1572. $arh = array();
  1573. $rx_http = '/\AHTTP_/';
  1574. foreach($_SERVER as $key => $val) {
  1575. if( preg_match($rx_http, $key) ) {
  1576. $arh_key = preg_replace($rx_http, '', $key);
  1577. $rx_matches = array();
  1578. // do some nasty string manipulations to restore the original letter case
  1579. // this should work in most cases
  1580. $rx_matches = explode('_', $arh_key);
  1581. if( count($rx_matches) > 0 and strlen($arh_key) > 2 ) {
  1582. foreach($rx_matches as $ak_key => $ak_val) $rx_matches[$ak_key] = ucfirst($ak_val);
  1583. $arh_key = implode('-', $rx_matches);
  1584. }
  1585. $arh[$arh_key] = $val;
  1586. }
  1587. }
  1588. return( $arh );
  1589. }
  1590. }
  1591. if(!function_exists('apache_get_version')){
  1592. function apache_get_version(){
  1593. if(!isset($_SERVER['SERVER_SOFTWARE']) || strlen($_SERVER['SERVER_SOFTWARE']) == 0){
  1594. return false;
  1595. }
  1596. return $_SERVER["SERVER_SOFTWARE"];
  1597. }
  1598. }
  1599. //Effectue un basename en tenant compte des caractères
  1600. //utf8( non pris en compte par basename PHP sous linux)
  1601. function mt_basename($path){
  1602. $path = str_replace(array("\\","/"),SLASH, $path);
  1603. $nameSplit = explode(SLASH,$path);
  1604. return end($nameSplit);
  1605. }
  1606. //filtre les balises dangeureuses (script,link..) dans les contenus wysiwyg
  1607. function wysiwyg_filter($html){
  1608. $html = preg_replace('#<(script|link)(.*?)>(.*?)</(script|link)>#is', '', $html);
  1609. $html = preg_replace('#<(script|link)([^>]*?)>#is', '', $html);
  1610. return $html;
  1611. }
  1612. function display_format_price($price) {
  1613. return display_price(format_price($price));
  1614. }
  1615. function unzip($zipPath,$destination,$options = array()){
  1616. $zip = new ZipArchive();
  1617. if(!$zip->open($zipPath)) throw new Exception("Impossible d'ouvrir l'archive");
  1618. for( $u = 0; $u < $zip->numFiles; $u++ ){
  1619. $infos = $zip->statIndex( $u );
  1620. //dossier
  1621. if(substr($infos['name'],-1,1)=='/'){
  1622. $infos['name'] = str_replace('..','.',$infos['name']);
  1623. mkdir($destination.SLASH.$infos['name'],0755,true);
  1624. //fichier
  1625. }else{
  1626. $parentDir = dirname($infos['name']);
  1627. if(!empty($parentDir) && !file_exists($parentDir)) mkdir($parentDir,0755,true);
  1628. if(!empty($options['allowedExtensions'])){
  1629. if(!in_array(getExt($infos['name']),$options['allowedExtensions'])) continue;
  1630. }
  1631. file_put_contents($destination.SLASH.$infos['name'], $zip->getFromName($infos['name']));
  1632. }
  1633. }
  1634. }
  1635. //retourne le tableaux des mentions depuis un texte libre ité de notre composant wysiwyg
  1636. //#mention #wysiwyg
  1637. function get_mention($text){
  1638. $mentionned = array(
  1639. 'user'=> array(),
  1640. 'rank'=> array(),
  1641. 'object'=> array(),
  1642. );
  1643. preg_match_all('|class="data-mention-user".*data-mention-value="([^"]*)"|isU', $text, $matches,PREG_SET_ORDER);
  1644. $users = User::getAll();
  1645. $ranks = Rank::loadAll();
  1646. foreach($matches as $match){
  1647. foreach($users as $user){
  1648. if($match[1] == $user->login)
  1649. $mentionned['user'][] = $user;
  1650. }
  1651. foreach($ranks as $rank){
  1652. if($match[1] == $rank->id)
  1653. $mentionned['rank'][] = $rank;
  1654. }
  1655. }
  1656. preg_match_all('|class="data-mention-object".*data-mention-value="([^"]*)"|isU', $text, $matches,PREG_SET_ORDER);
  1657. foreach ($matches as $match){
  1658. $mentionned['object'][] = $match[1];
  1659. }
  1660. return $mentionned;
  1661. }
  1662. function value_encapsulate($value, $char = ',') {
  1663. $value = trim($value, $char);
  1664. $value = $char.$value.$char;
  1665. return $value;
  1666. }
  1667. /*
  1668. Donne le differentiel en heures/jours entre deux dates en prenant en compte les horaires ouvrés et de la pause déjeuner
  1669. $start : timestamp de début
  1670. $end : timestamp de fin
  1671. $openStartHour : heure ouvrée de début de journée
  1672. $openEndHour : heure ouvrée de fin de journée
  1673. $lunchHour : temps de pause déjeuner (en heure)
  1674. */
  1675. /*
  1676. Donne le differentiel en heures/jours entre deux dates en prenant en compte les horaires ouvrés et de la pause déjeuner
  1677. $start : timestamp de début
  1678. $end : timestamp de fin
  1679. $openStartHour : heure ouvrée de début de journée
  1680. $openEndHour : heure ouvrée de fin de journée
  1681. $lunchHour : temps de pause déjeuner (en heure)
  1682. */
  1683. function date_workable_diff($start,$end,$openStartHour = 9,$openEndHour = 18,$lunchHour = 1){
  1684. $startTime = (new DateTime())->setTimestamp($start)->setTime(0,0,0);
  1685. $endTime = (new DateTime())->setTimestamp($end)->setTime(0,0,0);
  1686. $maxHours = $openEndHour - $openStartHour - $lunchHour;
  1687. $days = array();
  1688. //Si la fin n'est pas le même jour que le début
  1689. if($startTime->format('d-m-Y') != $endTime->format('d-m-Y')){
  1690. for($i=0;$i<$endTime->diff($startTime)->format("%a")+1;$i++){
  1691. $current = clone $startTime;
  1692. $current->add(new DateInterval('P'.$i.'D'));
  1693. $intervalStart = clone $current;
  1694. $intervalEnd = clone $current;
  1695. if($startTime->format('d-m-Y') != $intervalStart->format('d-m-Y')){
  1696. $intervalStart->setTime($openStartHour,0,0);
  1697. }else{
  1698. $intervalStart = (new DateTime())->setTimestamp($start);
  1699. }
  1700. if($endTime->format('d-m-Y') != $intervalEnd->format('d-m-Y')){
  1701. $intervalEnd->setTime($openEndHour,0,0);
  1702. }else{
  1703. $intervalEnd = (new DateTime())->setTimestamp($end);
  1704. }
  1705. $days[] = array('start'=>$intervalStart,'end'=>$intervalEnd);
  1706. }
  1707. }else{
  1708. $days[]= array('start'=>(new DateTime())->setTimestamp($start),'end'=> (new DateTime())->setTimestamp($end));
  1709. }
  1710. $deltaHours = 0;
  1711. foreach($days as $day){
  1712. $hours = $day['end']->format('H') - $day['start']->format("H");
  1713. //On enleve $lunchHour de pause déjeuner (12h-13h) dans les cas ou le temps pietine sur la pause
  1714. if( ($day['end']->format('H') < 13 && $day['end']->format('H') > 12) ||
  1715. ($day['start']->format('H') < 13 && $day['start']->format('H') > 12) ||
  1716. ($day['start']->format('H') <12 && $day['end']->format('H') > 13)
  1717. ) $hours-= $lunchHour;
  1718. $deltaHours += $hours;
  1719. }
  1720. $deltaDays = round($deltaHours / $maxHours,2);
  1721. return array(
  1722. 'hours' => $deltaHours,
  1723. 'days' => $deltaDays
  1724. );
  1725. }
  1726. if (!function_exists('getallheaders')) {
  1727. function getallheaders() {
  1728. $headers = [];
  1729. foreach ($_SERVER as $name => $value) {
  1730. if (substr($name, 0, 5) == 'HTTP_') {
  1731. $headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value;
  1732. }
  1733. }
  1734. return $headers;
  1735. }
  1736. }
  1737. ?>