[A-Za-z0-9]+)(\:(?P-?[0-9])+)?(\:(?P[0-9]+))?(?P[\!\_~%]*)[})]/" ); /** * Build LSformat string * * This function build and return a LSformat string from specified format and provided data. * * @author Benjamin Renard * * @param string $format The LSformat string * @param string|object|array $data Data to build the string * This parameter could be a string, an object or an array of string or object. * @param string $meth The name to the method of objet(s) to call to get the replacement value for a * specified key * * @return string The builded LSformat string */ function getFData($format, $data, $meth=NULL) { $unique = false; if(!is_array($format)) { $format = array($format); $unique = true; } for($i=0; $i $meth(); if (is_array($value)) { $value = $value[0]; } $value = _getFData_extractAndModify($value, $ch); $format[$i] = str_replace($ch[0], $value, $format[$i]); } else { LSerror :: addErrorCode( 'fct_getFData_01', array('meth' => $meth, 'obj' => $ch['key']) ); break; } } } } elseif (is_object($data)) { if (is_null($meth)) { while (preg_match(GETFDATA_REGEX, $format[$i], $ch)) { $value = $data -> $ch['key']; if (is_array($value)) { $value = $value[0]; } $value = _getFData_extractAndModify($value, $ch); $format[$i] = str_replace($ch[0], $value, $format[$i]); } } else { while (preg_match(GETFDATA_REGEX, $format[$i], $ch)) { if (method_exists($data, $meth)) { $value = $data -> $meth($ch['key']); if (is_array($value)) { $value = $value[0]; } $value = _getFData_extractAndModify($value, $ch); $format[$i] = str_replace($ch[0], $value, $format[$i]); } else { LSerror :: addErrorCode( 0, getFData( _("Function 'getFData' : The method %{meth} of the object %{obj} doesn't exist."), array('meth' => $meth, 'obj' => get_class($data)) ) ); break; } } } } else { while (preg_match(GETFDATA_REGEX, $format[$i], $ch)) { $val = _getFData_extractAndModify($data, $ch); $format[$i] = str_replace($ch[0], $val, $format[$i]); } } } if($unique) { return $format[0]; } return $format; } function _getFData_extractAndModify($data, $ch) { /* * Handle substring parameters (substr_a & substr_b) */ // If A if($ch['substr_a']) { // If A and B if ($ch['substr_b']) { // If A and B=0 if ($ch['substr_b'] == 0) { // If A<0 and B=0 if ($ch['substr_a'] < 0) { $s = mb_strlen(strval($data)) - (-1 * $ch['substr_a']); $l = mb_strlen(strval($data)); } // If A >= 0 and B else { $s = $ch['substr_a']; $l = mb_strlen(strval($data)); } } // If A and B > 0 elseif ($ch['substr_b'] > 0) { // If A < 0 and B > 0 or A >= 0 and B > 0 $s = $ch['substr_a']; $l = $ch['substr_b']; } // If A and B < 0 else { // If A < 0 and B < 0 if ($ch['substr_a'] < 0) { $s = $ch['substr_b']; $l = false; } // If A >= 0 and B < 0 else { $s = $ch['substr_a'] + $ch['substr_b']; $l = abs($ch['substr_b']); } } } // If only A else { if ($ch['substr_a'] < 0) { $s = $ch['substr_a']; $l = false; } else { $s = 0; $l = $ch['substr_a']; } } if ($l == false) { $val = mb_substr(strval($data), $s); } else { $val = mb_substr(strval($data), $s, abs($l)); } } else { try { $val = strval($data); } catch (Exception $e) { $val = _('[not string value]'); } } /* * Handle modifiers */ if ($ch['modifiers']) { # Without Accent if (strpos($ch['modifiers'], '~') !== false) { $val = withoutAccents($val); } # Upper / Lower case if (strpos($ch['modifiers'], '!') !== false) { $val = mb_strtoupper($val); } elseif (strpos($ch['modifiers'], '_') !== false) { $val = mb_strtolower($val); } # Escape HTML entities if (strpos($ch['modifiers'], '%') !== false) { $val = htmlentities($val); } } return $val; } function getFieldInFormat($format) { $fields = array(); while (preg_match(GETFDATA_REGEX, $format, $ch)) { $fields[] = $ch['key']; $format = str_replace($ch[0], '', $format); } return $fields; } function loadDir($dir,$regexpr='/^.*\.php$/') { if ($handle = opendir($dir)) { while (false !== ($file = readdir($handle))) { if (preg_match($regexpr,$file)) { require_once($dir.'/'.$file); } } } else { die(_('Folder not found').' : '.$dir); } return true; } function valid($obj) { LSdebug('function valid() : ok'); return true; } function validPas($obj=null) { LSdebug('function valid() : nok'); return false; } function return_data($data) { return $data; } function varDump($data) { ob_start(); var_dump($data); $data=ob_get_contents(); ob_end_clean(); return $data; } /* * LSdebug */ $GLOBALS['LSdebug_fields'] = array(); function LSdebug($data, $dump=false) { if ($dump) $data = varDump($data); if (class_exists('LSlog')) LSlog :: debug($data); $GLOBALS['LSdebug_fields'][] = htmlentities(strval($data)); return true; } function LSdebug_print($return=false) { $result = array(); if (LSdebugDefined()) $result = $GLOBALS['LSdebug_fields']; // Reset $GLOBALS['LSdebug_fields'] = array(); if ($return) return $result; LStemplate :: assign( 'LSdebug_content', base64_encode( json_encode( $result ) ) ); return; } function LSdebugDefined() { if (!LSdebug) return; return ( isset($GLOBALS['LSdebug_fields']) && is_array($GLOBALS['LSdebug_fields']) && !empty($GLOBALS['LSdebug_fields']) ); } /** * Vérifie la compatibilite des DN * * Vérifie que les DNs sont dans la même branche de l'annuaire. * * @param string $dn1 Un premier DN. * @param string $dn2 Un deuxième DN. * * @author Benjamin Renard * * @return boolean true si les DN sont compatibles, false sinon. */ function isCompatibleDNs($dn1,$dn2) { $infos1=ldap_explode_dn($dn1,0); if(!$infos1) return false; $infos2=ldap_explode_dn($dn2,0); if(!$infos2) return false; if($infos2['count']>$infos1['count']) { $tmp=$infos1; $infos1=$infos2; $infos2=$tmp; } $infos1=array_reverse($infos1); $infos2=array_reverse($infos2); for($i=0;$i<$infos1['count'];$i++) { if (!isset($infos2[$i])) continue; if($infos1[$i]==$infos2[$i]) continue; return false; } return true; } /** * Fait la somme de DN * * Retourne un DN qui correspond au point de séparation des DN si les DN * ne sont pas dans la meme dans la meme branche ou le dn le plus long sinon. * * @param string $dn1 Un premier DN. * @param string $dn2 Un deuxième DN. * * @author Benjamin Renard * * @return string|false Un DN (ou false si les DN ne sont pas valide) */ function sumDn($dn1,$dn2) { $infos1=ldap_explode_dn($dn1,0); if(!$infos1) return false; $infos2=ldap_explode_dn($dn2,0); if(!$infos2) return false; if($infos2['count']>$infos1['count']) { $tmp=$infos1; $infos1=$infos2; $infos2=$tmp; } $infos1=array_reverse($infos1); $infos2=array_reverse($infos2); $first=true; $basedn=''; for($i=0;$i<$infos1['count'];$i++) { if(($infos1[$i]==$infos2[$i])||(!isset($infos2[$i]))) { if($first) { $basedn=$infos1[$i]; $first=false; } else $basedn=$infos1[$i].','.$basedn; } else { return $basedn; } } return $basedn; } /** * Extract and retreive RDN from DN * @param string $dn * @param bool $with_attr If true, include the RDN attribute name (optional, default: true) * @return string|null|false The parent object DN, null if no parent or false in case of error */ function getRdn($dn, $with_attr=true) { $parts = ldap_explode_dn($dn, 0); if (!is_array($parts) || !isset($parts['count'])) return false; if ($with_attr) return $parts[0]; $equal_pos = strpos($parts[0], '='); if ($equal_pos !== false) return substr($parts[0], $equal_pos+1); return $parts[0]; } /** * Retreive parent object DN * @param string $dn * @return string|null|false The parent object DN, null if no parent or false in case of error */ function parentDn($dn) { $parts = ldap_explode_dn($dn, 0); if (!is_array($parts) || !isset($parts['count'])) return false; if ($parts['count'] == 1) return null; return implode(',', array_slice($parts, 2)); } function checkEmail($value,$domain=NULL,$checkDns=true) { $log = LSlog :: get_logger('checkEmail'); $regex = '/^((\"[^\"\f\n\r\t\v\b]+\")|([\w\!\#\$\%\&\'\*\+\-\~\/\^\`\|\{\}]+(\.[\w\!\#\$\%\&\'\*\+\-\~\/\^\`\|\{\}]+)*))@((\[(((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9])))\])|(((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9])))|((([A-Za-z0-9\-])+\.)+[A-Za-z\-]+))$/'; if (!preg_match($regex, $value)) { $log -> debug("'$value': regex fail"); return false; } $nd = explode('@', $value); $nd=$nd[1]; if ($domain) { if(is_array($domain)) { if (!in_array($nd,$domain)) { $log -> debug("'$value': domain '$nd' not authorized. Allowed domains: '".implode("', '", $domain)."'"); return false; } } else { if($nd!=$domain) { $log -> debug("'$value': domain '$nd' not authorized. Allowed domains: '$domain'"); return false; } } } if ($checkDns && function_exists('checkdnsrr')) { if (!(checkdnsrr($nd, 'MX') || checkdnsrr($nd, 'A'))) { $log -> debug("'$value': DNS check fail"); return false; } } $log -> debug("'$value': validated"); return true; } function generatePassword($chars=NULL,$lenght=NULL) { if (!$lenght) { $lenght=8; } if (is_array($chars)) { $retval=''; foreach($chars as $chs) { if (!is_array($chs)) { $chs=array('chars' => $chs); } if (!isset($chs['nb']) || !is_int($chs['nb'])) { $chs['nb']=1; } $retval.=aleaChar($chs['chars'],$chs['nb']); } $add = ($lenght-strlen($retval)); if ($add > 0) { $retval .= aleaChar($chars,$add); } return str_shuffle($retval); } else { return aleaChar($chars,$lenght); } } function aleaChar($chars=NULL,$lenght=1) { if (is_array($chars)) { $nchars=""; foreach($chars as $chs) { if (is_string($chs)) { $nchars.=$chs; } else if (is_string($chs['chars'])) { $nchars.=$chs['chars']; } } if(is_string($chars) && strlen($chars)>0) { $chars=$nchars; } else { $chars=NULL; } } if (!$chars) { $chars='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-'; } $nbChars=strlen($chars); $retval=""; if(is_int($lenght)) { for ($i=0;$i<$lenght;$i++) { $retval.=$chars[rand(0,$nbChars-1)]; } } return $retval; } function compareDn($a,$b) { if (substr_count($a,',') > substr_count($b,',')) return -1; else return 1; } /** * Translate message by using LSlang or Gettext methods * * @param string $msg The message * * @return string The translated message if translation available, the original message otherwise **/ function __($msg) { if (empty($msg)) return $msg; if (isset($GLOBALS['LSlang'][$msg])) { return $GLOBALS['LSlang'][$msg]; } return _($msg); } /** * Non-translate message * * Just-return the input message. This function permit the detection of message * that will be translated only at display time and not at declare time. * * @param string $msg The message * * @return string The message (unchanged) **/ function ___($msg) { return $msg; } // Try to load unidecode library // Note: unidecode lib use mb_ord function only available since PHP 7.2. if (!function_exists('unidecode') && function_exists('mb_ord')) { if (file_exists(LS_LIB_DIR."/unidecode/unidecode.php")) @include(LS_LIB_DIR."/unidecode/unidecode.php"); if (!function_exists('unidecode') && stream_resolve_include_path("unidecode/unidecode.php")) @include("unidecode/unidecode.php"); } /** * Supprime les accents d'une chaine * * @param string $string La chaine originale * * @return string La chaine sans les accents */ function withoutAccents($string){ // Use unidecode lib if available if (function_exists('unidecode')) return unidecode($string); // Otherwise, use historical method $replaceAccent = array( "à" => "a", "á" => "a", "â" => "a", "ã" => "a", "ä" => "a", "ç" => "c", "è" => "e", "é" => "e", "ê" => "e", "ë" => "e", "ì" => "i", "í" => "i", "î" => "i", "ï" => "i", "ñ" => "n", "ò" => "o", "ó" => "o", "ô" => "o", "õ" => "o", "ö" => "o", "ù" => "u", "ú" => "u", "û" => "u", "ü" => "u", "ý" => "y", "ÿ" => "y", "À" => "A", "Á" => "A", "Â" => "A", "Ã" => "A", "Ä" => "A", "Ç" => "C", "È" => "E", "É" => "E", "Ê" => "E", "Ë" => "E", "Ì" => "I", "Í" => "I", "Î" => "I", "Ï" => "I", "Ñ" => "N", "Ò" => "O", "Ó" => "O", "Ô" => "O", "Õ" => "O", "Ö" => "O", "Ù" => "U", "Ú" => "U", "Û" => "U", "Ü" => "U", "Ý" => "Y" ); return strtr($string, $replaceAccent); } /** * Supprime les espaces d'une chaine en les remplacant par un motif ou non * * @param string $str La chaine originale * @param string $to Le motif de remplacement. S'il n'est pas spécifié, les espaces seront simplement supprimés * * @return string La chaine sans les espaces **/ function replaceSpaces($str,$to='') { return strtr($str,array ( ' ' => $to, "\t" => $to ) ); } /** * List files in a directory corresponding to a regex * * @param string $dir The path of the directory * @param string $regex The regex apply on filename * * @return array() List of file name **/ function listFiles($dir,$regex) { $retval=array(); if (is_dir($dir)) { $d = dir($dir); while (false !== ($file = $d->read())) { if (is_file("$dir/$file")) { if (preg_match($regex, $file, $m)) { $retval[]=((is_array($m) && count($m)>1)?$m:$file); } } } } return $retval; } /** * Return current date in LDAP format * * @param mixed $mixed Anything (to permit using as generated function) * * @return string The current date in LDAP format (YYYYMMDDHHMMSSZ) **/ function now($mixed=Null) { return date ('YmdHis').'Z'; } /** * Check if a path is absolute * * @param string $path The path * * @return boolean True if path is absolute, False otherwise */ function isAbsolutePath($path) { return strStartWith($path, '/') || strStartWith($path, './') || strStartWith($path, '../'); } /** * Check if a string start with another specified string * * @param string $string The string to search in * @param string $start_string The starting string to check * * @return boolean True if string start by specified one, False otherwise */ function strStartWith($string, $start_string) { if (strlen($start_string) > strlen($string)) return false; return substr($string, 0, strlen($start_string)) === $start_string; } /** * Dump file content * * @param string $file_path The file path to dump * @param string|null $mime_type The MIME type return as Content-type (optional, default: auto-detected) * @param int $max_age The cache max_age value, as return in Cache-Control HTTP header * (optional, default: 3600) * @param boolean $force_download Set to true to force download (optional, default: false) * @param string|null $filename Specific filename in case of force download (optional, default: orignal filename) * * @return void **/ function dumpFile($file_path, $mime_type=null, $max_age=3600, $force_download=false, $filename=null) { if (is_file($file_path)) { header('Content-Type: '.(is_null($mime_type)?mime_content_type($file_path):$mime_type)); if ($force_download) header("Content-disposition: attachment; filename=\"".($filename?$filename:basename($file_path))."\""); $last_modified_time = filemtime($file_path); $etag = md5_file($file_path); header("Cache-Control: max-age=$max_age, must-revalidate"); header("Last-Modified: ".gmdate("D, d M Y H:i:s", $last_modified_time)." GMT"); header("Etag: $etag"); if ( ( isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && @strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $last_modified_time ) || ( isset($_SERVER['HTTP_IF_NONE_MATCH']) && trim($_SERVER['HTTP_IF_NONE_MATCH']) == $etag ) ) { header("HTTP/1.1 304 Not Modified"); exit(); } header('Pragma: public'); header('Content-Length: ' . filesize($file_path)); readfile($file_path); exit(); } // File not found, Trigger error 404 (via LSurl if defined) if (class_exists('LSurl')) { LSurl :: error_404(); } else { header("HTTP/1.1 404 Not found"); exit(); } } /** * Format a callable object for logging * @param callable $callable The callable object * @return string The callable object string representation */ function format_callable($callable) { if (is_string($callable)) return $callable."()"; if (is_array($callable) && count($callable)==2) if (is_string($callable[0])) return $callable[0]."::".$callable[1]."()"; elseif (is_object($callable[0])) return get_class($callable[0])."->".$callable[1]."()"; else return "Unkown->".$callable[1]."()"; return varDump($callable); } function is_empty($val) { switch(gettype($val)) { case "boolean": case "integer": case "double": case "object": case "resource": return False; case "array": case "string": if ($val == "0") return false; return empty($val); case "NULL": return True; } return empty($val); } function ensureIsArray($value) { if (is_array($value)) return $value; if (is_empty($value)) return array(); return array($value); } function ldapDate2DateTime($value, $naive=False, $format=null) { if (is_null($format)) $format = ($naive?'YmdHis*':'YmdHisO'); $datetime = date_create_from_format($format, $value); if ($datetime instanceof DateTime) return $datetime; return False; } function ldapDate2Timestamp($value, $naive=False, $format=null) { $datetime = ldapDate2DateTime($value, $naive, $format); if ($datetime instanceof DateTime) return $datetime -> format('U'); return False; } function dateTime2LdapDate($datetime, $timezone=null, $format=null) { if ($timezone != 'naive' && $timezone != 'local') { $datetime -> setTimezone(timezone_open(is_null($timezone)?'UTC':$timezone)); } if (is_null($format)) $format = ($timezone == 'naive'?'YmdHis':'YmdHisO'); $datetime_string = $datetime -> format($format); // Replace +0000 or -0000 end by Z $datetime_string = preg_replace('/[\+\-]0000$/', 'Z', $datetime_string); return $datetime_string; } function timestamp2LdapDate($value, $timezone=null, $format=null) { $datetime = date_create("@$value"); if ($datetime instanceof DateTime) return dateTime2LdapDate($datetime, $timezone, $format); return false; } /** * Generate an UUID * @return string */ function generate_uuid() { return sprintf( '%04x%04x-%04x-%04x-%04x-%04x%04x%04x', // 32 bits for "time_low" mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ), // 16 bits for "time_mid" mt_rand( 0, 0xffff ), // 16 bits for "time_hi_and_version", // four most significant bits holds version number 4 mt_rand( 0, 0x0fff ) | 0x4000, // 16 bits, 8 bits for "clk_seq_hi_res", // 8 bits for "clk_seq_low", // two most significant bits holds zero and one for variant DCE1.1 mt_rand( 0, 0x3fff ) | 0x8000, // 48 bits for "node" mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ) ); }