getCode(); $error['message'] = $ex->getMessage(); $error['file'] = $ex->getFile(); $error['line'] = $ex->getLine(); $error['trace'] = $ex->getTraceAsString(); $debugLink =''; if(isset($_SERVER['SERVER_NAME']) && $_SERVER['SERVER_NAME']=='127.0.0.1') $debugLink = exception_link($ex); $advanced = (isset($myUser) && $myUser->superadmin) || (isset($_SERVER['HTTP_HOST']) && $_SERVER['HTTP_HOST']== '127.0.0.1'); switch($source){ case 'ui': $response = ''; //Récuperation de la requete échouée si l'utilisateur n'est pas authentifié switch($ex->getCode()){ case 401: $_SESSION['last_request'] = $_SERVER['REQUEST_URI']; if(isset($_SESSION['logout_redirect'])){ echo ''; } echo '
Connexion requise : '.$error['message']; echo '
Pour vous connecter, cliquez sur le menu "Connexion" en haut à droite de cet écran'; echo '
'; break; default: $response = '
'; $response .= ''; if($advanced && isset($_['action'])) $response .= 'Action : '.$_['action'].'
'; $response .= 'Erreur : '.$error['message'].''; $response .= '
'; if($advanced){ $response .= ''.$error['file'].' L'.$error['line'].'
';
			 			$response .= exception_trace($ex);
			        	$response .= '
'; } $response .= '
'; break; } echo $response; require_once(__DIR__.SLASH.'footer.php'); break; case 'shell': $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; echo $response; break; case 'action': $error['error'] = $error['message']; $response = json_encode($error); echo $response; break; default: $response = '[Erreur '.$error['code'].'] '.$error['file'].' L'.$error['line'].PHP_EOL.$error['message'].PHP_EOL.$error['trace']; echo $response; break; } exit(); } function get_OS(){ return strtoupper(substr(PHP_OS, 0, 3)); } function OS_path_max_length(){ switch(get_OS()){ case 'WIN': return 259; break; default: return 4096; break; } } function OS_element_max_length(){ switch(get_OS()){ case 'WIN': return 255; break; default: return 255; break; } } function exception_link($ex,$type = 'exception'){ if($type=='exception'){ $filePath = $ex->getFile(); $line = $ex->getLine(); }else if($type=='trace'){ $filePath = isset($ex['file']) ? $ex['file'] : ''; $line = isset($ex['line']) ? $ex['line']: ''; } $filePath = explode('/',$filePath); $filePath = implode('\\',$filePath); return 'w2d://'.base64_encode( json_encode( array( 'action'=>'alias', 'alias'=>'sublime', 'arguments'=>$filePath.'":'.$line ) ) ); } function exception_trace($ex){ $error = ''; foreach($ex->getTrace() as $trace){ $error .= '
'.str_replace(__ROOT__,'',(isset($trace['file']) ? $trace['file'] : 0 )).' L'.(isset($trace['line']) ? $trace['line'] : 0 ).' - '; if(!empty($trace['class'])) $error .= $trace['class']; if(!empty($trace['type'])) $error .= $trace['type']; if(!empty($trace['function'])) $error .= $trace['function']; if(!empty($trace['args'])){ $error .= '('; $stringArgs = array(); foreach($trace['args'] as $arg){ $stringArgs[]=gettype($arg).( in_array(gettype($arg),array('string','integer','double','boolean','null')) ? ' '.$arg.'': ''); } $error .= implode(', ',$stringArgs); $error .= ')'; } $error .= ''; } return $error; } function ip(){ if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])) $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; elseif(isset($_SERVER['HTTP_CLIENT_IP'])) $ip = $_SERVER['HTTP_CLIENT_IP']; else $ip = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] :''; return $ip; } //Check si l'url serveur est en HTTPS function is_url_securised(){ //La verification de HTTP_X_FORWARDED_PROTO permet de gerer les reverse proxy qui font du https -> http return (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO']=='https') || (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off'); } //Définit le schéma d'URL à utiliser function define_url_scheme(){ return is_url_securised() ? 'https' : 'http'; } function encode_uri($uri){ return preg_replace_callback("{[^0-9a-z_.!~*'();,/?:@&=+$#-]}i", function ($m) { return sprintf('%%%02X', ord($m[0])); }, $uri); } //Définit la racine des médias en //fonction du schéma d'URL (http ou https) function define_media_root(){ return is_url_securised() ? preg_replace('|http(s)?://|i',define_url_scheme().'://',ROOT_URL) : ROOT_URL; } function encrypt($data){ $keyHash = md5(CRYPTKEY); $data = openssl_encrypt ($data,'aes256',$keyHash,true,'1234567812345678'); return base64_encode($data); } function decrypt($data){ $keyHash = md5(CRYPTKEY); $data = base64_decode($data); return openssl_decrypt ($data,'aes256',$keyHash,true,'1234567812345678'); } //Génère un slug unique pour l'element de liste utilisable dans le code // $label => string du label à slugifier // $column => la colonne en base où checker les slugs existants function generateSlug($label, $class, $column, $allowChars = '', $separator = '-'){ $slug = slugify($label,$allowChars,$separator); $item = new $class(); if(!array_key_exists($column, $item->fieldMapping)) return; $params = array_key_exists('state', $item->fieldMapping) ? array('state'=>$class::ACTIVE) : array(); $i=''; while($class::rowCount(array_merge(array($column=>($i==''?$slug:$slug.$separator.$i)), $params)) > 0) $i++; return $i==''?$slug:$slug.$separator.$i; } function slugify($text,$allowChars = '', $separator='-') { setlocale(LC_CTYPE, 'fr_FR.UTF-8'); try{ $encoding = mb_detect_encoding($text, mb_detect_order(), false); if($encoding == "UTF-8") $text = mb_convert_encoding($text, 'UTF-8', 'UTF-8'); $clean = iconv(mb_detect_encoding($text, mb_detect_order(), false), 'ASCII//TRANSLIT', $text); }catch(Exception $e){ $clean = $text; } $clean = normalize_chars($clean); $clean = preg_replace("/[^a-zA-Z0-9\/_|+ -".preg_quote($allowChars)."]/", '', $clean); $clean = strtolower(trim($clean, $separator)); $clean = preg_replace("/[\\".preg_quote(str_replace(str_split($allowChars),'','/_|+ -'))."]+/", $separator, $clean); return $clean; } if(!function_exists('glob_recursive')) { // Does not support flag GLOB_BRACE function glob_recursive($pattern, $flags = 0,$forbiddenPathes = array(),$root = null){ $files = glob($pattern, $flags); foreach (glob(dirname($pattern).SLASH.'*', GLOB_ONLYDIR|GLOB_NOSORT) as $dir) { if(isset($root)) if(in_array(str_replace($root,'',$dir), $forbiddenPathes)) continue; $files = array_merge($files, glob_recursive($dir.SLASH.basename($pattern), $flags,$forbiddenPathes,$root)); } return $files; } } //Récupère la dernière clé d'un tableau //avec fallback pour versions de PHP < 7 if (!function_exists("array_key_last")) { function array_key_last($array) { if (!is_array($array) || empty($array)) return NULL; return array_keys($array)[count($array)-1]; } } //Récupère la première clé d'un tableau //avec fallback pour versions de PHP < 7 if(!function_exists('array_key_first')) { function array_key_first($array) { $array = array_keys($array); return isset($array[0]) ? $array[0] : NULL; } } //Aplatit un tableau multidimensionnel //en un tableau à 1 seul niveau function array_flatten($array) { $return = array(); foreach($array as $key => $value) { if(is_array($value)){ $return = array_merge($return, array_flatten($value)); } else { $return[$key] = $value; } } return $return; } function array_map_recursive($callback, $array) { $func = function ($item) use (&$func, &$callback) { return is_array($item) ? array_map($func, $item) : call_user_func($callback, $item); }; return array_map($func, $array); } //Même principe que le ORDER BY de MySQL //mais sur différentes clés d'un tableau //Auteur: jimpoz -> https://www.php.net/manual/fr/function.array-multisort.php#100534 function array_orderby() { //Permet de récupérer les paramètres passés dynamiquement //Car on ne sait pas combien de paramètres on peut avoir $args = func_get_args(); $data = array_shift($args); foreach ($args as $n => $field) { if (is_string($field)) { $tmp = array(); foreach ($data as $key => $row) $tmp[$key] = $row[$field]; $args[$n] = $tmp; } } $args[] = &$data; call_user_func_array('array_multisort', $args); return array_pop($args); } function secure_user_vars($var){ if(is_array($var)){ $array = array(); foreach($var as $key=>$value): $array[secure_user_vars($key)] = secure_user_vars($value); endforeach; return $array; } else { return str_replace('&','&',htmlspecialchars($var, ENT_NOQUOTES, "UTF-8")); } } function base64_to_image($base64_string, $output_file) { $ifp = fopen($output_file, "wb"); $data = explode(',', $base64_string); fwrite($ifp, base64_decode($data[1])); fclose($ifp); return $output_file; } function getExt($file){ $ext = explode('.',$file); return strtolower(array_pop($ext)); } function get_gravatar($mail,$size = 100){ return file_get_contents("http://www.gravatar.com/avatar/" . md5( strtolower( trim( $mail ) ) ) . "?&s=".$size); } function getExtIcon($ext){ $icon = ''; switch($ext){ case '7z': case 'rar': case 'gz': case 'zip': $icon = 'far fa-file-archive text-warning'; break; case 'php': case 'js': case 'py': case 'c': case 'cpp': case 'css': case 'h': case 'hpp': case 'html': case 'htm': case 'asp': case 'jsp': $icon = 'fas fa-file-code text-secondary text-warning'; break; case 'xls': case 'xlsx': case 'xlsb': case 'csv': $icon = 'far fa-file-excel text-success'; break; case 'bmp': case 'jpg': case 'jfif': case 'jpeg': case 'ico': case 'gif': case 'png': case 'svg': $icon = 'far fa-file-image text-info'; break; case 'pdf': $icon = 'far fa-file-pdf text-danger'; break; case 'ppt': case 'pptx': $icon = 'fa-file-powerpoint-o text-warning' ; break; case 'txt': case 'htaccess': case 'md': $icon = 'far fa-file-alt'; break; case 'doc': case 'docx': case 'word': $icon = 'far fa-file-word text-primary'; break; case 'avi': case 'wmv': case 'mov': case 'divx': case 'xvid': case 'mkv': case 'flv': case 'mpeg': case 'h264': case 'rmvb': case 'mp4': $icon = 'far fa-file-video text-secondary'; break; case 'wav': case 'ogg': case 'ogv': case 'ogx': case 'oga': case 'riff': case 'bwf': case 'wma': case 'flac': case 'aac': case 'mp3': $icon = 'far fa-file-audio text-secondary'; break; default: $icon = 'far fa-file'; break; } return $icon; } function getExtContentType($ext){ $cType = ''; switch($ext){ case '7z': $cType = 'application/x-7z-compressed'; break; case 'rar': $cType = 'application/x-rar-compressed'; break; case 'gz': $cType = 'application/x-gzip'; break; case 'zip': $cType = 'application/zip'; break; case 'xls': $cType = 'application/vnd.ms-excel'; break; case 'xlsx': $cType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'; break; case 'csv': $cType = 'text/csv'; break; case 'jpg': case 'jpeg': $cType = 'image/jpeg'; break; case 'bmp': case 'gif': case 'png': $cType = 'image/'.$ext; break; case 'ppt': $cType = 'application/vnd.ms-powerpoint'; break; case 'pptx': $cType = 'application/vnd.openxmlformats-officedocument.presentationml.presentation'; break; case 'pdf': $cType = 'application/pdf'; break; case 'txt': $cType = 'text/plain'; break; case 'doc': case 'word': $cType = 'application/msword'; break; case 'docx': $cType = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'; break; case 'aac': case 'wav': $cType = 'audio/'.$ext; break; $cType = 'audio/aac'; break; case 'mp3': $cType = 'audio/mpeg3'; break; case 'otf': case 'ttf': case 'woff': case 'woff2': $cType = 'font/'.$ext; break; default: $cType = 'application/octet-stream'; break; } return $cType; } function max_upload_size($limits = array()){ $limits[] = str_replace('M','',ini_get('post_max_size')) *1048576; $limits[] = str_replace('M','',ini_get('upload_max_filesize')) *1048576; return readable_size(min($limits)); } function readable_size($bytes) { if(empty($bytes) || !is_numeric($bytes)) return '0 o'; if($bytes<1024){ return round(($bytes / 1024), 2).' o'; }elseif(1024<$bytes && $bytes<1048576){ return round(($bytes / 1024), 2).' ko'; }elseif(1048576<=$bytes && $bytes<1073741824){ return round(($bytes / 1024)/1024, 2).' Mo'; }elseif(1073741824<=$bytes){ return round(($bytes / 1024)/1024/1024, 2).' Go'; } } function relative_time($date, $date2=null, $relativeLimit=null, $detailled=false){ $from = new DateTime(); $from->setTimestamp($date); $to = new DateTime("now"); if(isset($date2)) $to->setTimestamp($date2); $intervalle = $from->diff($to); if(isset($relativeLimit) && $intervalle->days > $relativeLimit){ $limitFormat = $detailled ? 'd/m/Y - H:i' : 'd/m/Y'; return date($limitFormat, $date); } $prefixe = $from > $to ? 'Dans ' :'Il y a ' ; if(isset($date2)) $prefixe = ''; $years = $intervalle->format('%y'); $month = $intervalle->format('%m'); $days = $intervalle->format('%d'); $hours = $intervalle->format('%h'); $minutes = $intervalle->format('%i'); if ($years != 0) { $relative_date = $prefixe . $years . ' an' . (($years > 1) ? 's' : ''); if ($month >= 6) $relative_date .= ' et demi'; } elseif ($month != 0) { $relative_date = $prefixe . $month . ' mois'; if ($days >= 15) $relative_date .= ' et demi'; } elseif ($days != 0) { $relative_date = $prefixe . $days . ' jour' . (($days > 1) ? 's' : ''); } elseif ($hours != 0) { $relative_date = $prefixe . $hours . ' heure' . (($hours > 1) ? 's' : ''); } elseif ($minutes != 0) { $relative_date = $prefixe . $minutes . ' minute' . (($minutes > 1) ? 's' : ''); } else { $relative_date = $prefixe . ' quelques secondes'; } return $relative_date; } function image_resize($image,$w,$h){ $resource = imagecreatefromstring(file_get_contents($image)); $size = getimagesize($image); $h = (($size[1] * (($w)/$size[0]))); $thumbnail = imagecreatetruecolor($w , $h); imagecopyresampled($thumbnail ,$resource, 0,0, 0,0, $w, $h, $size[0],$size[1]); imagedestroy($resource); imagejpeg($thumbnail , $image, 100); } function arand($array){ return $array[array_rand($array)]; } //Convertis une date en timestamp //(format possible dd-mm-yyyy ou dd/mm/yyyy) function timestamp_date($date){ $date = explode('/',str_replace('-', '/', $date)); if(count($date)!=3) return 0; $year = $date[2]; $m = 0; $h = 0; if(strpos($year, ':')){ $yinfos = explode(' ',$year); $year = $yinfos[0]; list($h,$m) = explode(':',$yinfos[1]); } return mktime($h,$m,0,$date[1],$date[0],$year); } //Convertis une heur en timestamp à partir du 01/01/1970 //(format possible hh:mm) function timestamp_hour($hour){ $hour = explode(':',$hour); if(count($hour)!=2) return 0; return mktime($hour[0],$hour[1],0,1,1,1970); } // Récupère la différence entre 2 dates // avec le format spécifique fourni en paramètres // On compare Date1 à Date2 // (format possible) function format_date_diff($date1, $date2, $format='%a'){ $datetime1 = date_create($date1); $datetime2 = date_create($date2); $interval = $datetime1->diff($datetime2); return $interval->format($format); } /** * Normalise un tableau de filtres pour le composant Filter * * $filters : Array => tableau des paramètres avancés au format * array( * "jean", //Mot clé de la recherche simple * array( * 'nom_de_votre_colonne:operateur' => 'valeur_attendue', * 'join' => 'and|or', //Facultatif * ), * etc... (à répéter pour les N critères) * ) * Eg. : * filters_default(array( * "jean", * array( * 'birth' => "17/09/1998", * 'join' => 'or' * ), * array( * 'phone:like' => "9754" * ) * )); */ function filters_default($filters){ $finalFilters = array(); foreach ($filters as $filter) { //Gestion du keyword if(!is_array($filter) && !is_object($filter)){ array_unshift($finalFilters, $filter); continue; } $tempFilter = array(); foreach ($filter as $column => $value) { //Gestion du join if ($column == 'join') { $tempFilter['join'] = $value; continue; } //Gestion de la colonne ciblée avec opérator $column = explode(':', $column); $tempFilter['column'] = $column[0]; if(isset($column[1])) $tempFilter['operator'] = $column[1]; //Gestion de la value $tempFilter['value'] = $value; } if(!empty($tempFilter)) $finalFilters[] = $tempFilter; } return filters_set($finalFilters); } /** * Normalise et contrôles sur un tableau * de filtres pour le composant Filter. * * $filters : Array => tableau des paramètres avancés au format * array( * "jean", //Mot clé de la recherche simple, peut aussi être nommée 'keyword' => "jean" * array( * 'column' => 'nom_de_votre_colonne]', * 'operator' => '=|!=|LIKE:<:>', //Facultatif => "=" par défaut * 'value' => 'valeur_attendue', //Peut être du type array si plusieurs valeurs attendues * 'join' => 'and|or' //Facultatif => "and" par défaut * ), * etc... (à répéter pour les N critères) * ) * Eg. : * filters_set(array( * 'test', * array( * 'column' => 'login', * 'value' => 'admin' * ) * )); */ function filters_set($filters){ if(!is_array($filters)) return array(); $finalFilters = array( 'k' => '', 'a' => array() ); foreach ($filters as $key => $filter) { if($key==="keyword" || (!is_array($filter)) ) { $finalFilters['k'] = $filter; continue; } if(isset($filter['group'])){ $subfilters = filters_set($filter['group']); if(isset($subfilters['a'])) $finalFilters['a'][] = array('g'=>$subfilters['a']); continue; } if(!isset($filter['column']) || !isset($filter['value'])) continue; $filter['operator'] = isset($filter['operator']) ? $filter['operator'] : '='; $filter['operator'] = html_entity_decode($filter['operator']); if(!in_array(strtolower($filter['operator']), array('<','>','=','!=','like','not like','between','is null','is not null'))) continue; $tempFilter = array( "c" => $filter['column'], "o" => $filter['operator'], "v" => is_array($filter['value']) ? $filter['value'] : array($filter['value']), ); if(isset($filter['subcolumn'])) $tempFilter['s'] = $filter['subcolumn']; if(isset($filter['join'])){ if(!in_array(strtolower($filter['join']), array('and','or'))) continue; $tempFilter['j'] = $filter['join']; } if(isset($filter['type'])) $tempFilter['t'] = $filter['type']; $finalFilters['a'][] = $tempFilter; } return $finalFilters; } //altère un fitlre de recherche avancée de façon personnalisée et récursive function filter_alteration($filters,$index,$mutator){ foreach ($filters as $key => $value) { if(isset($value['group'])){ $filters[$key]['group'] = filter_alteration($filters[$key]['group'],$index,$mutator); }else{ if($value['column'] != $index) continue; $initialFilter = $filters[$key]; $filters[$key] = $mutator($value); //Si la fonction d'alteration retourne null on supprime le filtre initial if($filters[$key] == null){ //Gestion des joins, si le filtre supprimé avait un prédécesseur if(isset($filters[$key-1])){ //si le filtre supprimé avait un join, on le transfere au prédécesseur if(isset($filters[$key+1]) && !empty($initialFilter['join']) ){ $filters[$key-1]['join'] = $initialFilter['join']; //sinon on se content de supprimer le join du prédecesseur }else{ unset($filters[$key-1]['join']); } } //suppression du filtre unset($filters[$key]); } } } return $filters; } // Construit une requete sécurisée pour le composant filtre function filter_secure_query($filters,$allowedColumns,&$query,&$data,$iteration = 0,$columnEscape="`"){ if($iteration==0 && !empty($filters)) $query .= ' AND ('; global $databases_credentials; $connector = $databases_credentials['local']['connector']; $operators = $connector::operators(); $allowedOperators = array_keys($operators); foreach ($filters as $filter) { if(isset($filter['group'])){ $query .= ' ( '; filter_secure_query($filter['group'],$allowedColumns,$query,$data,$iteration+1); $query .= ' ) '; }else{ $filter['operator'] = html_entity_decode($filter['operator']); if(!in_array($filter['column'], $allowedColumns)) throw new Exception("Colonne '".$filter['column']."' interdite", 400); if(!in_array(strtolower($filter['operator']), $allowedOperators)) return; if(isset($filter['join']) && !in_array(strtolower($filter['join']), array('and','or'))) return; if(!preg_match("/.*\..*/i", $filter['column'])) $filter['column'] = $columnEscape.$filter['column'].$columnEscape; if(strtolower($filter['type']) == 'date' && isset($filter['value'])){ $filter['column'] = 'UNIX_TIMESTAMP(STR_TO_DATE(DATE_FORMAT(FROM_UNIXTIME('.$filter['column'].'),"%d/%m/%Y"), "%d/%m/%Y"))'; if(is_array($filter['value'])){ foreach($filter['value'] as $j=>$value){ $filter['value'][$j] = timestamp_date($value); } } else { $filter['value'] = timestamp_date($filter['value']); } } $operator = $operators[strtolower($filter['operator'])]; if(is_string($operator['sql'])){ $method = function($column,$value = null,&$query,&$data) use($operator){ $query .= str_replace(array('{{column}}','{{value}}'),array($column,'?'),$operator['sql']); if(isset($value) && isset($value[0])) $data[] = $value[0]; }; }else{ $method = $operator['sql']; } $query.=' ( '; $method($filter['column'],isset($filter['value'])?$filter['value']:null,$query,$data); $query.=' ) '; } if(isset($filter['join'])) $query .= ' '.$filter['join'].' '; } if($iteration==0 && !empty($filters)) $query .= ')'; } //remplace {{column}} par les colonnes dans $available - les colonnes dans $_['columns']['unselected'] function column_secure_query($columns,$_,&$query){ $unselected = isset($_['columns']) && isset($_['columns']['unselected']) ? $_['columns']['unselected'] : array(); $columns = array_diff($columns, $unselected); $query = str_replace('{{columns}}',implode(',',$columns),$query); } function sort_secure_query($sort,$allowedColumns,&$query){ if(!in_array($sort['sortable'], $allowedColumns)) return; if(!in_array(strtolower($sort['sort']), array('asc','desc',''))) return; $query .= ' ORDER BY '.$sort['sortable'].' '.$sort['sort']; } function check_mail($mail){ return ($mail && !empty($mail) && filter_var($mail, FILTER_VALIDATE_EMAIL)); } function truncate($text, $length = 100, $options = array()) { $default = array( 'ending' => '...', 'exact' => true, 'html' => false, 'keepTags' => true, ); $options = array_merge($default, $options); extract($options); if ($html) { if (mb_strlen(preg_replace('/<.*?>/', '', $text)) <= $length) { return $text; } $totalLength = mb_strlen(strip_tags($ending)); $openTags = array(); $truncate = ''; preg_match_all('/(<\/?([\w+]+)[^>]*>)?([^<>]*)/', $text, $tags, PREG_SET_ORDER); foreach ($tags as $tag) { if (!preg_match('/img|br|input|hr|area|base|basefont|col|frame|isindex|link|meta|param/s', $tag[2])) { if (preg_match('/<[\w]+[^>]*>/s', $tag[0])) { array_unshift($openTags, $tag[2]); } else if (preg_match('/<\/([\w]+)[^>]*>/s', $tag[0], $closeTag)) { $pos = array_search($closeTag[1], $openTags); if ($pos !== false) { array_splice($openTags, $pos, 1); } } } $truncate .= $tag[1]; $contentLength = mb_strlen(preg_replace('/&[0-9a-z]{2,8};|&#[0-9]{1,7};|&#x[0-9a-f]{1,6};/i', ' ', $tag[3])); if ($contentLength + $totalLength > $length) { $left = $length - $totalLength; $entitiesLength = 0; 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)) { foreach ($entities[0] as $entity) { if ($entity[1] + 1 - $entitiesLength <= $left) { $left--; $entitiesLength += mb_strlen($entity[0]); } else { break; } } } $truncate .= mb_substr($tag[3], 0 , $left + $entitiesLength); break; } else { $truncate .= $tag[3]; $totalLength += $contentLength; } if ($totalLength >= $length) { break; } } } else { if (mb_strlen($text) <= $length) { return $text; } else { $truncate = mb_substr($text, 0, $length - mb_strlen($ending)); } } if (!$exact) { $spacepos = mb_strrpos($truncate, ' '); if (isset($spacepos)) { if ($html) { $bits = mb_substr($truncate, $spacepos); preg_match_all('/<\/([a-z]+)>/', $bits, $droppedTags, PREG_SET_ORDER); if (!empty($droppedTags)) { foreach ($droppedTags as $closingTag) { if (!in_array($closingTag[1], $openTags)) { array_unshift($openTags, $closingTag[1]); } } } } $truncate = mb_substr($truncate, 0, $spacepos); } } $truncate .= $ending; if ($html) { foreach ($openTags as $tag) { $truncate .= ''; } } return (!$keepTags ? strip_tags($truncate) : $truncate); } /** * Permet de tronquer un texte en fonction d'un * nombre de caractères donné * @param string $content le texte à tronquer * @param int $limit le nombre de caractères qu'on garde * @param string $limiter le caractère de remplacement de fin de chaine * @return string le texte final, tronqué */ function truncate_content($content,$limit,$limiter){ if(strlen($content)>$limit) $content = mb_substr($content, 0,$limit).$limiter; return $content; } //Permet de décoder la chaîne d'entrée $string //en UTF-8 et de décoder les caractères spéciaux //pour l'affichage HTML function html_decode_utf8($string){ return htmlspecialchars(html_entity_decode($string), ENT_QUOTES, 'UTF-8'); } //Convertit la première lettre de la chaine $string //en majuscule et le reste de la chaine en minuscule UTF-8 //pour l'affichage HTML function mb_ucfirst($string,$encoding = 'UTF-8'){ $length = mb_strlen($string, $encoding); $firstChar = mb_substr($string, 0, 1, $encoding); $rest = mb_substr($string, 1, $length - 1, $encoding); return mb_strtoupper($firstChar, $encoding).$rest; } // Permet de mettre au bon format le n° de // téléphone fourni dans le formulaire function normalize_phone_number($number){ $nb = str_replace(array(' ', '.', ',', '-'), '', $number); $nb = chunk_split($nb, 2, ' '); $nb = rtrim($nb); preg_match("/^[0-9]{2} [0-9]{2} [0-9]{2} [0-9]{2} [0-9]{2}/", $nb, $matches); return isset($matches[0]) ? $matches[0] : $nb; } // Permet de voir si le format du n° de téléphone // fourni correspond à un format correct function check_phone_number($number, $international=false){ if(!$international && preg_match("/\+/i", $number)) return false; $nb = str_replace(array(' ', '.', ',', '-'), '', $number); if (!is_numeric($nb)) return false; return true; } //Retourne la valeur la plus proche d'un //nombre donné par rapport à un tableau de //nombres function get_closest_number($search, $arr){ $closest = null; foreach ($arr as $item) { if ($closest === null || abs($search - $closest) > abs($item - $search)) { $closest = $item; } } return $closest; } // Permet de convertir string encodée en UTF-8 // en ASCII pour ensuite appliquer une méthode // de Levenshtein sans avoir de divergences // trop importantes dues aux accents présents. function utf8_to_extended_ascii($str, &$map) { // find all multibyte characters (cf. utf-8 encoding specs) $matches = array(); if (!preg_match_all('/[\xC0-\xF7][\x80-\xBF]+/', $str, $matches)) return $str; // plain ascii string // update the encoding map with the characters not already met foreach ($matches[0] as $mbc) if (!isset($map[$mbc])) $map[$mbc] = chr(128 + count($map)); // finally remap non-ascii characters return strtr($str, $map); } // Override de la méthode de Levenshtein pour // compérer 2 strings encondées en UTF-8 function levenshtein_utf8($s1, $s2) { $charMap = array(); $s1 = utf8_to_extended_ascii($s1, $charMap); $s2 = utf8_to_extended_ascii($s2, $charMap); return levenshtein($s1, $s2); } // Méthode qui retourne sous forme de tableau // les metaphones // des différents mots d'une // phrase. function get_metaphones($sentence) { $metaphones = array(); $words = explode(' ',$sentence); foreach ($words as $word) { $metaphones[] = metaphone($word); } return $metaphones; } // Permet de trouver une chaîne de caractère s'approchant // le plus de l'entrée fournie en paramètres function find_best_match($words = array(), $input = '') { $closest = ''; $foundBestMatch = -1; $tmpInput = implode(' ', get_metaphones($input)); foreach($words as $word) { $tmpGauge = implode(' ', get_metaphones($word)); $similarity = levenshtein_utf8($tmpInput, $tmpGauge); if ($similarity == 0) { $closest = $word; $foundBestMatch = 0; break; } if ($similarity <= $foundBestMatch || $foundBestMatch < 0) { $closest = $word; $foundBestMatch = $similarity; } } return $closest; } // Convertit nombres en lettres (utile pour Excel) function numbers_to_letters($num){ $num = intval($num); $letter = ''; if ($num <= 0) return $letter; while($num != 0){ $p = ($num - 1) % 26; $num = intval(($num - $p) / 26); $letter = chr(65 + $p) . $letter; } return $letter; } //Convertit lettres en nombres (utile pour Excel) function letters_to_numbers($col){ $col = str_pad($col,3,'0', STR_PAD_LEFT); $i = 0; if ($col[0] != '0') { $i = ((ord($col[0]) - 64) * 676) + 26; $i += ($col[1] == '0') ? 0 : (ord($col[1]) - 65) * 26; } else { $i += ($col[1] == '0') ? 0 : (ord($col[1]) - 64) * 26; } $i += ord($col[2]) - 64; return $i; } //Check si c'est un date bien formattée function is_date($date){ $date = str_replace(array('-',' ','\\'),'/',trim($date)); if(trim($date)=='') return false; if (count(explode('/',$date)) < 3) return false; list($d,$m,$y) = explode('/',$date); if( !is_numeric($d) || !is_numeric($m) || !is_numeric($y) ) return false; return checkdate ( $m , $d , $y ); } //Cherche la position de $needles dans //$haystack, où $needles est un array //de string et $haystack est le string à //comparer function strpos_array($haystack, $needles=array(), $offset=0) { $chr = array(); foreach($needles as $needle) { $res = strpos($haystack, $needle, $offset); if ($res !== false) $chr[$needle] = $res; } if(empty($chr)) return false; return min($chr); } //Supprime un dossier et son contenu //de manière récursive function delete_folder_tree($dir, $selfDestroy=false) { if(!file_exists($dir)) return; $files = array_diff(scandir($dir), array('.','..')); foreach ($files as $file) (is_dir("$dir/$file")) ? delete_folder_tree("$dir/$file") : unlink("$dir/$file"); if($selfDestroy) return rmdir($dir); } //Normalise les caractères un peu spéciaux //d'une chaîne de caractère function normalize_chars($string, $mask=array()) { $normalizeChars = array( 'Š'=>'S', 'š'=>'s', 'Ð'=>'Dj','Ž'=>'Z', 'ž'=>'z', 'À'=>'A', 'Á'=>'A', 'Â'=>'A', 'Ã'=>'A', 'Ä'=>'A', 'Å'=>'A', 'Æ'=>'A', 'Ç'=>'C', 'È'=>'E', 'É'=>'E', 'Ê'=>'E', 'Ë'=>'E', 'Ì'=>'I', 'Í'=>'I', 'Î'=>'I', 'Ï'=>'I', 'Ñ'=>'N', 'Ń'=>'N', 'Ò'=>'O', 'Ó'=>'O', 'Ô'=>'O', 'Õ'=>'O', 'Ö'=>'O', 'Ø'=>'O', 'Ù'=>'U', 'Ú'=>'U', 'Û'=>'U', 'Ü'=>'U', 'Ý'=>'Y', 'Þ'=>'B', 'ß'=>'Ss','à'=>'a', 'á'=>'a', 'â'=>'a', 'ã'=>'a', 'ä'=>'a', 'å'=>'a', 'æ'=>'a', 'ç'=>'c', 'è'=>'e', 'é'=>'e', 'ê'=>'e', 'ë'=>'e', 'ì'=>'i', 'í'=>'i', 'î'=>'i', 'ï'=>'i', 'ð'=>'o', 'ñ'=>'n', 'ń'=>'n', 'ò'=>'o', 'ó'=>'o', 'ô'=>'o', 'õ'=>'o', 'ö'=>'o', 'ø'=>'o', 'ù'=>'u', 'ú'=>'u', 'û'=>'u', 'ü'=>'u', 'ý'=>'y', 'ý'=>'y', 'þ'=>'b', 'ÿ'=>'y', 'ƒ'=>'f', 'ă'=>'a', 'î'=>'i', 'â'=>'a', 'ș'=>'s', 'ț'=>'t', 'Ă'=>'A', 'Î'=>'I', 'Â'=>'A', 'Ș'=>'S', 'Ț'=>'T', '’'=>'\'', '–'=>'-', '€'=>'€', '&'=>'&','œ'=>'oe', '•'=>'-' ); return strtr($string, array_diff_key($normalizeChars, array_flip($mask))); } //Convertit un nombre en son équivalent écrit //e.g: 23 --> VINGT-TROIS function number_to_words($number, $feminine=false) { $hyphen = '-'; $conjunction = ' et '; $negative = 'moins '; $decimal = ' virgule '; $dictionary = array( 0 => 'zero', 1 => !$feminine?'un':'une', 2 => 'deux', 3 => 'trois', 4 => 'quatre', 5 => 'cinq', 6 => 'six', 7 => 'sept', 8 => 'huit', 9 => 'neuf', 10 => 'dix', 11 => 'onze', 12 => 'douze', 13 => 'treize', 14 => 'quatorze', 15 => 'quinze', 16 => 'seize', 17 => 'dix-sept', 18 => 'dix-huit', 19 => 'dix-neuf', 20 => 'vingt', 30 => 'trente', 40 => 'quarante', 50 => 'cinquante', 60 => 'soixante', 70 => 'soixante-dix', 80 => 'quatre-vingt', 90 => 'quatre-vingt dix', 100 => 'cent', 1000 => 'mille', 1000000 => 'million', 1000000000 => 'milliard', 1000000000000 => 'trillion', 1000000000000000 => 'quadrillion', 1000000000000000000 => 'quintillion' ); if (!is_numeric($number)) return false; 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); if ($number < 0) return $negative.number_to_words(abs($number)); $string = $fraction = null; if (strpos($number, '.') !== false) list($number, $fraction) = explode('.', $number); switch (true) { case $number < 21: $string = $dictionary[$number]; break; case $number == 21: $string = $dictionary[20].$conjunction.$dictionary[1]; break; case $number == 31: $string = $dictionary[30].$conjunction.$dictionary[1]; break; case $number == 41: $string = $dictionary[40].$conjunction.$dictionary[1]; break; case $number == 51: $string = $dictionary[50].$conjunction.$dictionary[1]; break; case $number == 61: $string = $dictionary[60].$conjunction.$dictionary[1]; break; case $number == 71: $string = $dictionary[60].$conjunction.$dictionary[11]; break; case $number == 81: $string = $dictionary[80].$hyphen.$dictionary[1]; break; case $number == 91: $string = $dictionary[80].$hyphen.$dictionary[11]; break; case $number < 100: $tens = ((int) ($number / 10)) * 10; $units = $number % 10; $string = $dictionary[$tens]; if ($units) { $string .= $hyphen . $dictionary[$units]; } break; case $number < 1000: $hundreds = $number / 100; $remainder = $number % 100; $string = ((int)$hundreds==1 ? '' : $dictionary[$hundreds].' ') . $dictionary[100]; if ($remainder) { $string .= ' ' . number_to_words($remainder); } break; default: $baseUnit = pow(1000, floor(log($number, 1000))); $numBaseUnits = (int) ($number / $baseUnit); $remainder = $number % $baseUnit; $string = number_to_words($numBaseUnits) . ' ' . $dictionary[$baseUnit]; if ($remainder) { $string .= $remainder < 100 ? $conjunction : ' '; $string .= number_to_words($remainder); } break; } if (null !== $fraction && is_numeric($fraction)) { $string .= $decimal; if(strlen($fraction) <= 3) { $string .= number_to_words($fraction); } else { $words = array(); foreach (str_split((string) $fraction) as $number) $words[] = $dictionary[$number]; $string .= implode(' ', $words); } } return mb_strtoupper($string); } /** * Retrourne le numéral ordinal compact * d'un nombre passé en paramètre. * eg: * 1 --> 1er, * 2 --> 2ème, etc.. * Les nombres ordinaux sont définis par un * l'ensemble des entiers naturels non nuls * représenté N*={1,2,3,...} */ function number_to_ordinal($number, $feminine=false){ $number = (int) $number; //Aucun ordinal pour le rang 0 if($number == 0) return; if($number == 1) return $number.($feminine?'ère':'er'); return $number.'ème'; } /** * Vérifie si un nombre est entre 2 bornes * Possibilité d'inclure ou d'exclure les bornes avec $strict */ function number_between($number, $low, $high, $strict=false) { if(!$strict && ($number<$low || $number>$high)) return false; if($strict && ($number<=$low || $number>=$high)) return false; return true; } /* * Fonction pour vérifier si un nombre * est un nombre décimal * * Eg: - 95.00 --> false * - 95.5 --> true * Les nombres avec décimales à 0 sont donc exclus */ function is_decimal($val) { return is_numeric($val) && floor($val)!=$val; } /** * Retourne les fonction interdites * utilisées dans une fonction eval() * @param string $source [le string qui va $etre eval()] * @return Array [Tableau des méthodes utilisées interdites] */ function forbidden_macro($source){ $tokens = token_get_all(''); $forbiddens = array(); $allowed_functions = array( 'ucfirst', 'strto.*', 'str_.*', 'substr', 'password_encrypt', 'strpos', 'date', '[im|ex]plode', 'preg_*', 'count', 'time', 'array_.*', '.sort', ); foreach($tokens as $token){ if(is_string($token)) continue; list($id, $text,$line) = $token; if(in_array($id, array(T_FUNCTION,T_FUNC_C,T_EVAL,T_STRING))){ $allowed = false; foreach ($allowed_functions as $function) { preg_match('/'.$function.'/i', $text, $matches); if(count($matches)!=0){ $allowed = true; break; } } if(!$allowed) $forbiddens[] = $text.' L'.$line; } if(in_array($id, array( T_INCLUDE, T_EXTENDS, T_CLONE, T_EXIT, T_GLOBAL, T_HALT_COMPILER, T_IMPLEMENTS, T_INCLUDE_ONCE, T_REQUIRE, T_REQUIRE_ONCE, T_IMPLEMENTS ))){ $forbiddens[] = $text.' L'.$line; } } return $forbiddens; } //Fonction respectant la syntaxe mustache (prototype a roder) function mustache_template($stream,$data){ //blocks (loop, if, else) $stream = preg_replace_callback('/\{\{(#|\^)?([^\}]*)\}\}(.*?)\{\{\/\2\}\}/is',function($matches) use ($data) { $stream = ''; $expression = $matches[0]; $key = $matches[2]; $template = $matches[3]; if(!isset($data[$key])){ $stream = '';$expression; return $stream; } $value = $data[$key]; //if ou loop if($matches[1] == '#'){ //loop if(is_array($value)) { $length = count($value); $i = 0; foreach ($value as $key=>$value2) { //gère les exception de derniere occurence de boucle (ex,toutes les occurences finissent par , sauf la derniere) // syntaxe : {{;}}mon texte partout sauf derniere occurence{{/;}} $lastOccurenceReplace = $i!=$length-1 ? '$1' : ''; $lineTemplate = preg_replace('/\{\{;\}\}(.*)\{\{\/;\}\}/isU', $lastOccurenceReplace, $template); $localData = is_array($value2) ? array_merge($data,$value2) : $data; $stream.= mustache_template($lineTemplate,$localData); $i++; } return $stream; //if }else{ if(!empty($value) && $value!=false){ return mustache_template($template,$data); } return ''; } //else }else if($matches[1] == '^'){ if(!$value) return mustache_template($template,$data); return ''; //cas de block non gérés car sans char operateur # ou ^ ex : {{expression}}{{/expression}} }else{ $stream = $expression; return $stream; } },$stream); //simple vars $stream = preg_replace_callback('/\{\{([^\}]*)\}\}/isU',function($matches) use ($data) { $key = $matches[1]; if(isset($data[$key]) && (is_string($data[$key]) || is_numeric($data[$key])) ) return $data[$key]; $value = ''; $attributes = explode('.',$key); $current = $data; foreach ($attributes as $attribute) { if ( !isset($current[$attribute]) ) return; $current = $current[$attribute]; $value = $current; } return $value; },$stream); return $stream; } function template($stream,$data,$mustacheTemplate = false){ if($mustacheTemplate) return mustache_template($stream,$data); //loop $stream = preg_replace_callback('/{{\:([^\/\:\?}]*)}}(.*?){{\/\:[^\/\:\?}]*}}/is',function($matches) use ($data) { $tag = $matches[1]; $streamTpl = $matches[2]; $stream = ''; if(!isset($data[$tag])) return $stream; $values = $data[$tag]; foreach($values as $join){ $occurence = $streamTpl; foreach($join as $key=>$value){ if(is_array($value) || is_object($value)) continue; $occurence = str_replace(array('{{'.$key.'}}'),array($value),$occurence); } $stream .= $occurence; } return $stream; },$stream); //conditions $stream = preg_replace_callback('/{{\?([^\/\:\?}]*)}}(.*?){{\/\?[^\/\:\?}]*}}/is',function($matches) use ($data) { $key = $matches[1]; $stream = $matches[2]; return !isset($data[$key]) || (is_array($data[$key]) && count($data[$key])==0) ?'':$stream; },$stream); //simple vars $stream = preg_replace_callback('/{{([^\/\:\;\?}]*)}}/',function($matches) use ($data) { $key = $matches[1]; if(isset($data[$key]) && (is_string($data[$key]) || is_numeric($data[$key])) ) return $data[$key]; $value = ''; $attributes = explode('.',$key); $current = $data; foreach ($attributes as $attribute) { if ( !isset($current[$attribute]) ) return; $current = $current[$attribute]; $value = $current; } return $value; },$stream); return $stream; } /** * Auteur: Anonymous * Lien: https://www.php.net/manual/en/features.file-upload.post-method.php#120686 * * Normalise le tableau de fichier récupérés * pour une utilisation plus efficace et intuitive * * Exemple de format initial pour 2 fichiers dans $_FILES : * Array ( [name] => Array ( [0] => foo.txt [1] => bar.txt ), [type] => Array( [0] => text/plain [1] => text/plain ), [tmp_name] => Array( [0] => /tmp/phpYzdqkD [1] => /tmp/phpeEwEWG ), [error] => Array( [0] => 0 [1] => 0 ), [size] => Array( [0] => 123 [1] => 456 ) * ) * * Exemple de format de retour pour 2 fichiers : * Array( [0] => Array( [name] => foo.txt [type] => text/plain [tmp_name] => /tmp/phpYzdqkD [error] => 0 [size] => 123 ), [1] => Array( [name] => bar.txt [type] => text/plain [tmp_name] => /tmp/phpeEwEWG [error] => 0 [size] => 456 ) ) * @param Array &$file_post [tableau de fichiers $_FILES] * @return Array [le tableau ré-arrangé] */ function normalize_php_files() { $function = function($files, $fixedFiles=array(), $path=array()) use (&$function) { foreach ($files as $key => $value) { $temp = $path; $temp[] = $key; if(is_array($value)) { $fixedFiles = $function($value, $fixedFiles, $temp); } else { $next = array_splice($temp, 1, 1); $temp = array_merge($temp, $next); $new = &$fixedFiles; foreach ($temp as $key) $new = &$new[$key]; $new = $value; } } return $fixedFiles; }; return $function($_FILES); } /** * Incrémente automatiquement le nom d'un * fichier si celui-ci existe déjà * Fonction récursive. * @param String $extension [extension du fichier] * @param String $folder [dossier où localiser le fichier] * @param String $filename [nom du fichier] * @return String [nom de fichier final] */ function autoincrement_filename($extension, $folder, $filename){ static $counter = 0; $fileNb = count(glob(FILE_PATH.$folder.$filename)); $filenameProps = explode('.', $filename); unset($filenameProps[count($filenameProps)-1]); $finalFilename = implode('.', $filenameProps); if($fileNb>0) { $counter+=1; $filename = preg_match("/(^.*?\()(\d+)([^\\d]*\)\..*$)/", $filename, $matches) ? $matches[1].$counter.$matches[3] : $finalFilename.'('.$counter.')'.'.'.$extension; $filename = autoincrement_filename($extension, $folder, $filename); } return $filename; } function relative_path($absolutePath,$reference = __ROOT__){ $absolutePath = str_replace(array('\\','/'),SLASH,$absolutePath); $reference = str_replace(array('\\','/'),SLASH,$reference); return str_replace($reference,'',$absolutePath); } //Définit si une couleur hexadecimale est claire //ou sombre en fonction d'un seuil de luminosité function get_light($hexcode,$treshold = 510.0) { $rgb = to_rgb($hexcode); return (max($rgb[0], $rgb[1], $rgb[2]) + min($rgb[0], $rgb[1], $rgb[2])) / $treshold; } //Génère une couleur hexadécimale aléatoire function random_hex_color() { return '#'.str_pad(dechex(mt_rand(0, 0xFFFFFF)), 6, '0', STR_PAD_LEFT); } //Génère une couleur pastel basé sur //le hash md5 du mot passé en paramètre function random_hex_pastel_color($name) { $hash = md5($name); $red = hexdec(substr($hash, 8, 2)); $green = hexdec(substr($hash, 4, 2)); $blue = hexdec(substr($hash, 0, 2)); if($red < 128) $red += 128; if($green < 128) $green += 128; if($blue < 128) $blue += 128; return "#" . dechex($red) . dechex($green) . dechex($blue); } //Convertit un code hexadecimal en code RGB function to_rgb($hexcode) { $hexcode = substr($hexcode, 1); return array(hexdec($hexcode[0] . $hexcode[1]), hexdec($hexcode[2] . $hexcode[3]), hexdec($hexcode[4] . $hexcode[5])); } //Retourne le nom complet d'un mois en fonction de son numéro function month_name($month){ $translates = array('Janvier','Fevrier','Mars','Avril','Mai','Juin','Juillet','Aout','Septembre','Octobre','Novembre','Décembre'); return $translates[$month-1]; } //Retourne le nom complet d'un jour en fonction de son numéro (1 : lundi,..., 7 :dimanche) function day_name($day){ $translates = array('Lundi','Mardi','Mercredi','Jeudi','Vendredi','Samedi','Dimanche'); return isset($translates[$day-1])? $translates[$day-1]:$day; } //Convertit un timestamp dans un format //agréable et complet : ex Mardi 18 Avril 2019 function complete_date($time=null){ if(!isset($time)) $time = time(); return day_name(date('N',$time)).' '.date('d',$time).' '.month_name(date('m',$time)).' '.date('Y',$time); } //Récuperation des jours féries function get_not_workable($date=null){ if ($date === null) $date = time(); $date = strtotime(date('m/d/Y',$date)); $year = date('Y',$date); if($year < 1970 || $year > 2037) throw new exception("Date non valide inférieure à 1970 ou supérieure à 2037", 400); $easterDate = easter_date($year); $easterDay = date('j', $easterDate); $easterMonth = date('n', $easterDate); $easterYear = date('Y', $easterDate); $holidays = array( // Dates fixes mktime(0, 0, 0, 1, 1, $year), // 1er janvier mktime(0, 0, 0, 5, 1, $year), // Fête du travail mktime(0, 0, 0, 5, 8, $year), // Victoire des alliés mktime(0, 0, 0, 7, 14, $year), // Fête nationale mktime(0, 0, 0, 8, 15, $year), // Assomption mktime(0, 0, 0, 11, 1, $year), // Toussaint mktime(0, 0, 0, 11, 11, $year), // Armistice mktime(0, 0, 0, 12, 25, $year), // Noel // Dates variables mktime(0, 0, 0, $easterMonth, $easterDay + 1, $easterYear), mktime(0, 0, 0, $easterMonth, $easterDay + 39, $easterYear), mktime(0, 0, 0, $easterMonth, $easterDay + 50, $easterYear), ); return $holidays; } //Retourne le chemin web d'un fichier en fonction de son chemin //physique (ex : /img/logo.png pour /var/www/erp-core/img/logo.png) function webpath($path){ $url = ROOT_URL.str_replace(array(__DIR__.SLASH,"\\","/"),array('','/','/'),$path); $url = preg_replace('/([^\:])(\/{2,})/i', '$1/', $url); return $url; } //Retourne un tableau clé/valeur des valeurs //existantes en doublons du tableau passé en paramètre function array_not_unique($array=array()){ return array_diff_key($array, array_unique($array)); } //Retourne true si aucune valeur du tableau passé //en paramètre a un doublon, false sinon. function is_array_unique($array=array()){ return empty(array_not_unique($array)); } function make_cookie($name, $value, $expire='', $ns ='/') { if($expire == ''){ setcookie($name, $value, mktime(0,0,0, date("d"), date("m"), (date("Y")+1)), $ns); } else { setcookie($name, '', mktime(0,0,0, date("d"), date("m"), (date("Y")-1)), $ns); } } //Permet de formatter les prix à afficher //de la même manière partout sur l'ERP. //Si jamais on veut changer de normalisation //pour l'affichage des prix, il suffit de changer //le fonctionnement ici uniquement. function display_price($price){ return number_format($price, 2, ',', ' '); } //Permet de formatter les prix à enregistrer //de la même manière partout sur l'ERP. //Si jamais on veut changer de normalisation //pour l'enregistrement des prix, il suffit de changer //le fonctionnement ici uniquement. function format_price($price){ return str_replace(',','.',$price); } //Permet de calculer un age en fonction de la date du jour //Paramètre : la date de départ(format timestamp), l'unité de retour souhaitée(format 'd', 'm', 'Y'... voir fonction diff de php) //Renvoie : l'age en entier function age($from,$unit = 'y'){ if(!isset($from) || !is_numeric($from)) return 'N/A'; $from = new \DateTime(date('Y-m-d',$from)); $to = new \DateTime('today'); $age = $from->diff($to); if(!$age || !array_key_exists($unit, $age)) return 'N/A'; return $age = $age->$unit; } //Permet d'échapper tous les caractères interdits dans une chaine json function escape_json_string($value) { # list from www.json.org: (\b backspace, \f formfeed) $escapers = array("\\", "/", "\"", "\n", "\r", "\t", "\x08", "\x0c"); $replacements = array("\\\\", "\\/", "\\\"", "\\n", "\\r", "\\t", "\\f", "\\b"); $result = str_replace($escapers, $replacements, $value); return $result; } if( !function_exists('apache_request_headers') ) { /// function apache_request_headers() { $arh = array(); $rx_http = '/\AHTTP_/'; foreach($_SERVER as $key => $val) { if( preg_match($rx_http, $key) ) { $arh_key = preg_replace($rx_http, '', $key); $rx_matches = array(); // do some nasty string manipulations to restore the original letter case // this should work in most cases $rx_matches = explode('_', $arh_key); if( count($rx_matches) > 0 and strlen($arh_key) > 2 ) { foreach($rx_matches as $ak_key => $ak_val) $rx_matches[$ak_key] = ucfirst($ak_val); $arh_key = implode('-', $rx_matches); } $arh[$arh_key] = $val; } } return( $arh ); } } if(!function_exists('apache_get_version')){ function apache_get_version(){ if(!isset($_SERVER['SERVER_SOFTWARE']) || strlen($_SERVER['SERVER_SOFTWARE']) == 0){ return false; } return $_SERVER["SERVER_SOFTWARE"]; } } //Effectue un basename en tenant compte des caractères //utf8( non pris en compte par basename PHP sous linux) function mt_basename($path){ $path = str_replace(array("\\","/"),SLASH, $path); $nameSplit = explode(SLASH,$path); return end($nameSplit); } //filtre les balises dangeureuses (script,link..) dans les contenus wysiwyg function wysiwyg_filter($html){ $html = preg_replace('#<(script|link)(.*?)>(.*?)#is', '', $html); $html = preg_replace('#<(script|link)([^>]*?)>#is', '', $html); return $html; } function display_format_price($price) { return display_price(format_price($price)); } function unzip($zipPath,$destination,$options = array()){ $zip = new ZipArchive(); if(!$zip->open($zipPath)) throw new Exception("Impossible d'ouvrir l'archive"); for( $u = 0; $u < $zip->numFiles; $u++ ){ $infos = $zip->statIndex( $u ); //dossier if(substr($infos['name'],-1,1)=='/'){ $infos['name'] = str_replace('..','.',$infos['name']); mkdir($destination.SLASH.$infos['name'],0755,true); //fichier }else{ $parentDir = dirname($infos['name']); if(!empty($parentDir) && !file_exists($parentDir)) mkdir($parentDir,0755,true); if(!empty($options['allowedExtensions'])){ if(!in_array(getExt($infos['name']),$options['allowedExtensions'])) continue; } file_put_contents($destination.SLASH.$infos['name'], $zip->getFromName($infos['name'])); } } } //retourne le tableaux des mentions depuis un texte libre ité de notre composant wysiwyg //#mention #wysiwyg function get_mention($text){ $mentionned = array( 'user'=> array(), 'rank'=> array(), 'object'=> array(), ); preg_match_all('|class="data-mention-user".*data-mention-value="([^"]*)"|isU', $text, $matches,PREG_SET_ORDER); $users = User::getAll(); $ranks = Rank::loadAll(); foreach($matches as $match){ foreach($users as $user){ if($match[1] == $user->login) $mentionned['user'][] = $user; } foreach($ranks as $rank){ if($match[1] == $rank->id) $mentionned['rank'][] = $rank; } } preg_match_all('|class="data-mention-object".*data-mention-value="([^"]*)"|isU', $text, $matches,PREG_SET_ORDER); foreach ($matches as $match){ $mentionned['object'][] = $match[1]; } return $mentionned; } function value_encapsulate($value, $char = ',') { $value = trim($value, $char); $value = $char.$value.$char; return $value; } /* Donne le differentiel en heures/jours entre deux dates en prenant en compte les horaires ouvrés et de la pause déjeuner $start : timestamp de début $end : timestamp de fin $openStartHour : heure ouvrée de début de journée $openEndHour : heure ouvrée de fin de journée $lunchHour : temps de pause déjeuner (en heure) */ /* Donne le differentiel en heures/jours entre deux dates en prenant en compte les horaires ouvrés et de la pause déjeuner $start : timestamp de début $end : timestamp de fin $openStartHour : heure ouvrée de début de journée $openEndHour : heure ouvrée de fin de journée $lunchHour : temps de pause déjeuner (en heure) */ function date_workable_diff($start,$end,$openStartHour = 9,$openEndHour = 18,$lunchHour = 1){ $startTime = (new DateTime())->setTimestamp($start)->setTime(0,0,0); $endTime = (new DateTime())->setTimestamp($end)->setTime(0,0,0); $maxHours = $openEndHour - $openStartHour - $lunchHour; $days = array(); //Si la fin n'est pas le même jour que le début if($startTime->format('d-m-Y') != $endTime->format('d-m-Y')){ for($i=0;$i<$endTime->diff($startTime)->format("%a")+1;$i++){ $current = clone $startTime; $current->add(new DateInterval('P'.$i.'D')); $intervalStart = clone $current; $intervalEnd = clone $current; if($startTime->format('d-m-Y') != $intervalStart->format('d-m-Y')){ $intervalStart->setTime($openStartHour,0,0); }else{ $intervalStart = (new DateTime())->setTimestamp($start); } if($endTime->format('d-m-Y') != $intervalEnd->format('d-m-Y')){ $intervalEnd->setTime($openEndHour,0,0); }else{ $intervalEnd = (new DateTime())->setTimestamp($end); } $days[] = array('start'=>$intervalStart,'end'=>$intervalEnd); } }else{ $days[]= array('start'=>(new DateTime())->setTimestamp($start),'end'=> (new DateTime())->setTimestamp($end)); } $deltaHours = 0; foreach($days as $day){ $hours = $day['end']->format('H') - $day['start']->format("H"); //On enleve $lunchHour de pause déjeuner (12h-13h) dans les cas ou le temps pietine sur la pause if( ($day['end']->format('H') < 13 && $day['end']->format('H') > 12) || ($day['start']->format('H') < 13 && $day['start']->format('H') > 12) || ($day['start']->format('H') <12 && $day['end']->format('H') > 13) ) $hours-= $lunchHour; $deltaHours += $hours; } $deltaDays = round($deltaHours / $maxHours,2); return array( 'hours' => $deltaHours, 'days' => $deltaDays ); } if (!function_exists('getallheaders')) { function getallheaders() { $headers = []; foreach ($_SERVER as $name => $value) { if (substr($name, 0, 5) == 'HTTP_') { $headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value; } } return $headers; } } ?>