0) { $asCleaningFunc = array_fill(1, count($oData), $sCleaningFunc); $asKeys = array_map(array('self', 'cleanData'), array_keys($oData), $asCleaningFunc); $asValues = array_map(array('self', 'cleanData'), $oData, $asCleaningFunc); return array_combine($asKeys, $asValues); } } public static function fixGlobalVars($argv) { //Add CLI arguments if(defined('STDIN')) mb_parse_str(implode('&', array_slice($argv, 1)), $_GET); $_REQUEST = array_merge($_GET, $_REQUEST); } public static function array_map_encapsulate($oData, $sChar) { if(is_array($oData)) { $asChar = array_fill(1, count($oData), $sChar); return array_combine(array_keys($oData), array_map(array('self', 'array_map_encapsulate'), $oData, $asChar)); } else { return $sChar.$oData.$sChar; } } public static function capitalizeWords($acText, $sCharList = '') { //Use ucwords if no delimiters are given if($sCharList=='') { return Toolbox::mb_ucwords($acText); } // Go through all characters $capitalizeNext = true; $max = mb_strlen($acText); for ($i = 0; $i < $max; $i++) { if(mb_strpos($sCharList, $acText[$i]) !== false) { $capitalizeNext = true; } elseif($capitalizeNext) { $capitalizeNext = false; $acText[$i] = mb_strtoupper($acText[$i]); } } return $acText; } public static function jsonExport($asData) { header('Content-type: application/json'); //return htmlspecialchars(json_encode($asData), ENT_NOQUOTES); return self::jsonConvert($asData); } public static function jsonConvert($asData) { return json_encode($asData); } public static function curl($sUrl, $bHeader=false, $asPostData=array(), $sReturnType='text', $sCookie='', $sCreds='') { $oCurl = curl_init(); curl_setopt($oCurl, CURLOPT_URL, $sUrl); curl_setopt($oCurl, CURLOPT_VERBOSE, false); curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($oCurl, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($oCurl, CURLOPT_HEADER, $bHeader); if($bHeader) curl_setopt($oCurl, CURLOPT_FOLLOWLOCATION, true); if(!empty($asPostData)) { curl_setopt($oCurl, CURLOPT_POST, 1); curl_setopt($oCurl, CURLOPT_POSTFIELDS, $asPostData); } curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, true); curl_setopt($oCurl, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']); if($sCookie!='') curl_setopt($oCurl, CURLOPT_COOKIE, $sCookie); if($sCreds!='') curl_setopt($oCurl, CURLOPT_USERPWD, $sCreds); $sContent = curl_exec($oCurl); $sCurlErrorId = curl_errno($oCurl); $sHttpCode = curl_getinfo($oCurl, CURLINFO_HTTP_CODE); $bSuccess = ($sCurlErrorId==0 && $sHttpCode==200); $sDesc = ''; if(!$bSuccess) $sDesc = ($sCurlErrorId==0)?('HTTP Error Code '.$sHttpCode):($sCurlErrorId.': '.curl_strerror($sCurlErrorId)); curl_close($oCurl); switch($sReturnType) { case 'json': $oContent = json_decode($sContent, true); break; default: $oContent = $sContent; } return array('result'=>$bSuccess, 'desc'=>$sDesc, 'content'=>$oContent); } public static function getMimeType($sPath, $bSubTypeOnly=false) { $sMimetype = ''; //Retrieving file Content Type if(file_exists($sPath)) //Local { $oFileInfo = new \finfo(FILEINFO_MIME); $sMimetype = $oFileInfo->file($sPath); } else //Remote { //get_headers($sUrl, 1) $oCurl = curl_init($sPath); curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, true); curl_setopt($oCurl, CURLOPT_FOLLOWLOCATION, true); curl_setopt($oCurl, CURLOPT_HEADER, true); //curl_setopt($oCurl, CURLOPT_NOBODY, true); curl_setopt($oCurl, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']); curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, false); curl_exec($oCurl); $sMimetype = curl_getinfo($oCurl, CURLINFO_CONTENT_TYPE); curl_close($oCurl); } //Only sub type (after /) if($bSubTypeOnly) { preg_match('`\/(?P\w+)(\;|$)`ui', mb_strtolower($sMimetype), $asMatch); if(array_key_exists('type', $asMatch)) $sMimetype = $asMatch['type']; } return $sMimetype; } public static function isAnimatedGif($sFilePath) { if(!($oFile = @fopen($sFilePath, 'rb'))) return false; $iCount = 0; while (!feof($oFile) && $iCount < 2) { $sChunk = fread($oFile, 1024 * 100); //read 100kb at a time $iCount += preg_match_all('#\x00\x21\xF9\x04.{4}\x00(\x2C|\x21)#s', $sChunk, $asMatches); } fclose($oFile); return $iCount > 1; } public static function createThumbnail($sInPath, $iMaxWidth, $iMaxHeight=0, $sOutPath='', $bDeleteIn=false, $asImageExts=array('jpg', 'jpeg', 'gif', 'png'), $bCrop=false, $bCopyExif=false) { $asResult = array('error'=>''); //Look up the file type to choose the image creator $sImageExt = self::getMimeType($sInPath, true); $sImageExt = ($sImageExt=='jpg')?'jpeg':$sImageExt; //New Destination folder $asInInfo = pathinfo($sInPath); $asOutInfo = pathinfo($sOutPath); if($sOutPath=='') $sOutPath = $sInPath; elseif(mb_substr($sOutPath, -1)=='/') $sOutPath .= mb_strtolower($asInInfo['basename']); //folder only, keep original name elseif(!array_key_exists('extension', $asOutInfo)) $sOutPath .= '.'.$sImageExt; //folder + filename, but getting ext from file info //New sizes if(!in_array($sImageExt, $asImageExts) && !empty($asImageExts)) $asResult['error'] = 'Wrong file type: '.$sImageExt; elseif($iMaxWidth==0 && $iMaxHeight==0) $asResult['error'] = 'At least one dimension must be resized (width and/or height)'; else { //Recalculate max width/height in case of rotated picture $sRotate = 0; $asExif = @exif_read_data($sInPath); if($asExif && array_key_exists('Orientation', $asExif)) { switch($asExif['Orientation']) { case 3: $sRotate = 180; break; //Flip over case 6: $sRotate = -90; break; //Clockwise case 8: $sRotate = 90; break; //Trigo } } list($iWidth, $iHeight) = getimagesize($sInPath); if(abs($sRotate) == 90) { $iTempWidth = $iWidth; $iWidth = $iHeight; $iHeight = $iTempWidth; } //Limit on only 1 parameter if($iMaxWidth==0) $iMaxWidth = $iWidth * $iMaxHeight / $iHeight; elseif($iMaxHeight==0) $iMaxHeight = $iHeight * $iMaxWidth / $iWidth; if($iWidth > $iMaxWidth || $iHeight > $iMaxHeight) { $dResizeDeltaWidth = $iWidth - $iMaxWidth; $dResizeDeltaHeight = $iHeight - $iMaxHeight; $iPosLeft = $iPosTop = 0; $iThumbWidth = $iMaxWidth; $iThumbHeight = $iMaxHeight; //Max up the lowest value between height and width and crop the other if($bCrop) { if($dResizeDeltaWidth > $dResizeDeltaHeight) //Crop width { $iResizedHeight = $iMaxHeight; $iResizedWidth = ($iResizedHeight / $iHeight) * $iWidth; $iPosLeft = ($iResizedWidth - $iMaxWidth)/2*(-1); } else { $iResizedWidth = $iMaxWidth; $iResizedHeight = ($iResizedWidth / $iWidth) * $iHeight; $iPosTop = ($iResizedHeight - $iMaxHeight)/2*(-1); } } else //Just resize { if($dResizeDeltaWidth > $dResizeDeltaHeight) { $iResizedWidth = $iMaxWidth; $iResizedHeight = ($iResizedWidth / $iWidth) * $iHeight; } else { $iResizedHeight = $iMaxHeight; $iResizedWidth = ($iResizedHeight / $iHeight) * $iWidth; } $iThumbWidth = $iResizedWidth; $iThumbHeight = $iResizedHeight; } if($sImageExt=='gif' && self::isAnimatedGif($sInPath)) { $sContent = file_get_contents($sInPath); $sBigGifPath = uniqid().$sOutPath.'.big'; $sCoalescePath = uniqid().$sOutPath.'.coalesce'; if(file_put_contents($sBigGifPath, $sContent)===false) $asResult['error'] = 'Unable to create temporary thumbnail : '.$sBigGifPath; system('convert '.$sBigGifPath.' -coalesce '.$sCoalescePath); system('convert -size '.$iWidth.'x'.$iHeight.' '.$sCoalescePath.' -resize '.$iResizedWidth.'x'.$iResizedHeight.' '.$sOutPath); unlink($sBigGifPath); unlink($sCoalescePath); } else { //create image from source $oSource = call_user_func('imagecreatefrom'.$sImageExt, $sInPath); //Fix rotation if($sRotate) $oSource = imagerotate($oSource, $sRotate, 0); //Resize $oThumb = imagecreatetruecolor($iThumbWidth, $iThumbHeight); imagecopyresampled($oThumb, $oSource, $iPosLeft, $iPosTop, 0, 0, $iResizedWidth, $iResizedHeight, $iWidth, $iHeight); //Save if(file_exists($sOutPath)) unlink($sOutPath); if(!call_user_func_array('image'.$sImageExt, array($oThumb, $sOutPath))) { $asResult['error'] = 'Unable to create thumbnail : '.$sOutPath; } imagedestroy($oThumb); } } elseif($sInPath != $sOutPath) { $iResizedWidth = $iWidth; $iResizedHeight = $iHeight; if(!copy($sInPath, $sOutPath)) $asResult['error'] = 'Copy failed from '.$sInPath.' to '.$sOutPath; } $asResult['width'] = $iResizedWidth; $asResult['height'] = $iResizedHeight; $asResult['out'] = $sOutPath; } if($bCopyExif && $asResult['error'] == '') self::copyExif($sInPath, $sOutPath); if($bDeleteIn && $asResult['error'] == '' && $sInPath != $sOutPath) unlink($sInPath); return $asResult; } public static function copyExif($srcfile, $destfile) { // Function transfers EXIF (APP1) and IPTC (APP13) from $srcfile and adds it to $destfile // JPEG file has format 0xFFD8 + [APP0] + [APP1] + ... [APP15] + where [APPi] are optional // Segment APPi (where i=0x0 to 0xF) has format 0xFFEi + 0xMM + 0xLL + (where 0xMM is // most significant 8 bits of (strlen() + 2) and 0xLL is the least significant 8 bits // of (strlen() + 2) if (file_exists($srcfile) && file_exists($destfile)) { $srcsize = @getimagesize($srcfile, $imageinfo); // Prepare EXIF data bytes from source file $exifdata = (is_array($imageinfo) && key_exists("APP1", $imageinfo)) ? $imageinfo['APP1'] : null; if ($exifdata) { $exiflength = strlen($exifdata) + 2; if ($exiflength > 0xFFFF) return false; // Construct EXIF segment $exifdata = chr(0xFF) . chr(0xE1) . chr(($exiflength >> 8) & 0xFF) . chr($exiflength & 0xFF) . $exifdata; } // Prepare IPTC data bytes from source file $iptcdata = (is_array($imageinfo) && key_exists("APP13", $imageinfo)) ? $imageinfo['APP13'] : null; if ($iptcdata) { $iptclength = strlen($iptcdata) + 2; if ($iptclength > 0xFFFF) return false; // Construct IPTC segment $iptcdata = chr(0xFF) . chr(0xED) . chr(($iptclength >> 8) & 0xFF) . chr($iptclength & 0xFF) . $iptcdata; } $destfilecontent = @file_get_contents($destfile); if (!$destfilecontent) return false; if (strlen($destfilecontent) > 0) { $destfilecontent = substr($destfilecontent, 2); $portiontoadd = chr(0xFF) . chr(0xD8); // Variable accumulates new & original IPTC application segments $exifadded = !$exifdata; $iptcadded = !$iptcdata; while ((substr($destfilecontent, 0, 2) & 0xFFF0) === 0xFFE0) { $segmentlen = (substr($destfilecontent, 2, 2) & 0xFFFF); $iptcsegmentnumber = (substr($destfilecontent, 1, 1) & 0x0F); // Last 4 bits of second byte is IPTC segment # if ($segmentlen <= 2) return false; $thisexistingsegment = substr($destfilecontent, 0, $segmentlen + 2); if ((1 <= $iptcsegmentnumber) && (!$exifadded)) { $portiontoadd .= $exifdata; $exifadded = true; if (1 === $iptcsegmentnumber) $thisexistingsegment = ''; } if ((13 <= $iptcsegmentnumber) && (!$iptcadded)) { $portiontoadd .= $iptcdata; $iptcadded = true; if (13 === $iptcsegmentnumber) $thisexistingsegment = ''; } $portiontoadd .= $thisexistingsegment; $destfilecontent = substr($destfilecontent, $segmentlen + 2); } if (!$exifadded) $portiontoadd .= $exifdata; // Add EXIF data if not added already if (!$iptcadded) $portiontoadd .= $iptcdata; // Add IPTC data if not added already $outputfile = fopen($destfile, 'w'); if ($outputfile) return fwrite($outputfile, $portiontoadd . $destfilecontent); else return false; } else { return false; } } else { return false; } } public static function utf8_compliant($sText) { if(strlen($sText) == 0) return true; return (preg_match('/^.{1}/us', $sText, $ar) == 1); } public static function mb_ucwords($sText) { return mb_convert_case($sText, MB_CASE_TITLE, "UTF-8"); } public static function mb_ucfirst($sText) { $sLength = mb_strlen($sText); $sFirstChar = mb_substr($sText, 0, 1); $sThen = mb_substr($sText, 1, $sLength - 1); return mb_strtoupper($sFirstChar).$sThen; } public static function file_get_contents_utf8($oFile) { $sContent = file_get_contents($oFile); return mb_convert_encoding($sContent, 'UTF-8', mb_detect_encoding($sContent, 'UTF-8, ISO-8859-1', true)); } public static function rgbToHex($R, $G, $B) { $R = dechex($R); if(strlen($R)<2) $R='0'.$R; $G = dechex($G); if(strlen($G)<2) $G='0'.$G; $B = dechex($B); if(strlen($B)<2) $B='0'.$B; return $R.$G.$B; } public static function setCookie($sCookieName, $sCookieValue, $iDays) { $iTimeLimit = time()+60*60*24*$iDays; setcookie($sCookieName, $sCookieValue, $iTimeLimit); } public static function fixEOL($sText) { //Normalize line endings //Convert all line-endings to UNIX format $sText = str_replace("\r\n", "\n", $sText); //Windows $sText = str_replace("\r", "\n", $sText); //Mac // Don't allow out-of-control blank lines $sText = preg_replace("/\n{2,}/", "\n\n", $sText); return $sText; } public static function getUserLanguage($available_languages, $sDefaultLang='') { $http_accept_language = isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])?$_SERVER['HTTP_ACCEPT_LANGUAGE']:''; //Format: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4 preg_match_all("/([[:alpha:]]{1,8})(-([[:alpha:]|-]{1,8}))?(\s*;\s*q\s*=\s*(1\.0{0,3}|0\.\d{0,3}))?\s*(,|$)/i", $http_accept_language, $hits, PREG_SET_ORDER); $bestlang = $sDefaultLang; $bestqval = 0; foreach($hits as $arr) { $langprefix = strtolower($arr[1]); if(!empty($arr[3])) { $langrange = strtolower($arr[3]); $language = $langprefix.'-'.$langrange; } else $language = $langprefix; //Q Value $qvalue = 1.0; if(!empty($arr[5])) $qvalue = floatval($arr[5]); //find q-maximal language if(in_array($language, $available_languages) && $qvalue > $bestqval) { $bestlang = $language; $bestqval = $qvalue; } //if no direct hit, try the prefix only but decrease q-value by 10% (as http_negotiate_language does) elseif(in_array($langprefix, $available_languages) && ($qvalue * 0.9) > $bestqval) { $bestlang = $langprefix; $bestqval = $qvalue * 0.9; } } return $bestlang; } /** * Return relative time description * FIXME shitty implementation of i18n * @param int $oTime Time (strtotime) * @param string $sLang Language (en/fr) * @return string Relative Time */ public static function getDateTimeDesc($oTime, $sLang='en') { $iTimeStamp = is_numeric($oTime)?$oTime:strtotime($oTime); $sCurTimeStamp = time(); switch ($sLang) { case 'en': $asWeekDays = array('monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'satursday', 'sunday'); $asMonths = array('january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december'); break; case 'fr': $asWeekDays = array('lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche'); $asMonths = array('janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'); break; } $sSep = '|'; $sFormat = 'Y'.$sSep.'n'.$sSep.'W'.$sSep.'N'.$sSep.'j'.$sSep.'G'; list($sYear, $sMonth, $sWeek, $sWeekDay, $sDay, $sHour) = explode($sSep, date($sFormat, $iTimeStamp)); list($sCurYear, $sCurMonth, $sCurWeek, $sCurWeekDay, $sCurDay, $sCurHour) = explode($sSep, date($sFormat, $sCurTimeStamp)); $sDesc = ''; switch ($sLang) { case 'en': if($iTimeStamp>$sCurTimeStamp) $sDesc = 'in the future'; elseif($sCurTimeStamp-$iTimeStamp<60) $sDesc = 'a few seconds ago'; elseif($sCurTimeStamp-$iTimeStamp<60*10) $sDesc = 'a few minutes ago'; elseif($sCurTimeStamp-$iTimeStamp<60*20) $sDesc = '15 minutes ago'; elseif($sCurTimeStamp-$iTimeStamp<60*50) $sDesc = 'half an hour ago'; elseif($sCurTimeStamp-$iTimeStamp<60*60*2) $sDesc = 'an hour ago'; elseif($sCurTimeStamp-$iTimeStamp<60*60*24 && $sDay==$sCurDay) $sDesc = 'at '.date('gA', $iTimeStamp); elseif($sCurTimeStamp-$iTimeStamp<60*60*24) $sDesc = 'yesterday'; elseif($sCurTimeStamp-$iTimeStamp<60*60*24*7 && $sWeek==$sCurWeek) $sDesc = $asWeekDays[$sWeekDay-1]; elseif($sCurTimeStamp-$iTimeStamp<60*60*24*7) $sDesc = 'last '.$asWeekDays[$sWeekDay-1]; elseif($sCurTimeStamp-$iTimeStamp<60*60*24*9) $sDesc = 'a week ago'; elseif($sCurTimeStamp-$iTimeStamp<60*60*24*12) $sDesc = '10 days ago'; elseif($sCurTimeStamp-$iTimeStamp<60*60*24*16) $sDesc = '2 weeks ago'; elseif($sCurTimeStamp-$iTimeStamp<60*60*24*23) $sDesc = '3 weeks ago'; elseif($sCurTimeStamp-$iTimeStamp<60*60*24*31 && $sMonth==$sCurMonth) $sDesc = 'on '.$asMonths[$sMonth-1].', '.$sDay; elseif($sCurTimeStamp-$iTimeStamp<60*60*24*30*2 && $sMonth==($sCurMonth-1)) $sDesc = 'last month'; elseif($sCurTimeStamp-$iTimeStamp<60*60*24*365 && $sYear==$sCurYear) $sDesc = 'in '.$asMonths[$sMonth-1]; elseif($sCurTimeStamp-$iTimeStamp<60*60*24*365) $sDesc = 'in '.$asMonths[$sMonth-1].' '.$sYear; elseif($sYear==($sCurYear-1)) $sDesc = 'last year'; else $sDesc = 'in '.$sYear; break; case 'fr': if($iTimeStamp>$sCurTimeStamp) $sDesc = 'dans le futur'; elseif($sCurTimeStamp-$iTimeStamp<60) $sDesc = 'il y a quelques secondes'; elseif($sCurTimeStamp-$iTimeStamp<60*10) $sDesc = 'il y a quelques minutes'; elseif($sCurTimeStamp-$iTimeStamp<60*20) $sDesc = 'il y a un quart d\'heure'; elseif($sCurTimeStamp-$iTimeStamp<60*50) $sDesc = 'il y a une demi-heure'; elseif($sCurTimeStamp-$iTimeStamp<60*60*2) $sDesc = 'il y a une heure'; elseif($sCurTimeStamp-$iTimeStamp<60*60*24 && $sDay==$sCurDay) $sDesc = 'à '.$sHour.'h'; elseif($sCurTimeStamp-$iTimeStamp<60*60*24) $sDesc = 'hier'; elseif($sCurTimeStamp-$iTimeStamp<60*60*24*7 && $sWeek==$sCurWeek) $sDesc = $asWeekDays[$sWeekDay-1]; elseif($sCurTimeStamp-$iTimeStamp<60*60*24*7) $sDesc = $asWeekDays[$sWeekDay-1].' dernier'; elseif($sCurTimeStamp-$iTimeStamp<60*60*24*9) $sDesc = 'il y a une semaine'; elseif($sCurTimeStamp-$iTimeStamp<60*60*24*12) $sDesc = 'il y a 10 jours'; elseif($sCurTimeStamp-$iTimeStamp<60*60*24*16) $sDesc = 'il y a 2 semaines'; elseif($sCurTimeStamp-$iTimeStamp<60*60*24*23) $sDesc = 'il y a 3 semaines'; elseif($sCurTimeStamp-$iTimeStamp<60*60*24*31 && $sMonth==$sCurMonth) $sDesc = 'le '.$sDay.' '.$asMonths[$sMonth-1]; elseif($sCurTimeStamp-$iTimeStamp<60*60*24*30*2 && $sMonth==($sCurMonth-1)) $sDesc = 'le mois dernier'; elseif($sCurTimeStamp-$iTimeStamp<60*60*24*365 && $sYear==$sCurYear) $sDesc = 'en '.$asMonths[$sMonth-1]; elseif($sCurTimeStamp-$iTimeStamp<60*60*24*365) $sDesc = 'en '.$asMonths[$sMonth-1].' '.$sYear; elseif($sYear==($sCurYear-1)) $sDesc = 'l\'année dernière'; else $sDesc = 'en '.$sYear; break; } //return self::mb_ucfirst($sDesc); return $sDesc; } /** * Worpress function to remove accents * https://core.trac.wordpress.org/browser/trunk/src/wp-includes/formatting.php * @param String $string * @return String */ public static function remove_accents($string) { if(!preg_match('/[\x80-\xff]/', $string)) return $string; $chars = array( // Decompositions for Latin-1 Supplement chr(194).chr(170) => 'a', chr(194).chr(186) => 'o', chr(195).chr(128) => 'A', chr(195).chr(129) => 'A', chr(195).chr(130) => 'A', chr(195).chr(131) => 'A', chr(195).chr(132) => 'A', chr(195).chr(133) => 'A', chr(195).chr(134) => 'AE',chr(195).chr(135) => 'C', chr(195).chr(136) => 'E', chr(195).chr(137) => 'E', chr(195).chr(138) => 'E', chr(195).chr(139) => 'E', chr(195).chr(140) => 'I', chr(195).chr(141) => 'I', chr(195).chr(142) => 'I', chr(195).chr(143) => 'I', chr(195).chr(144) => 'D', chr(195).chr(145) => 'N', chr(195).chr(146) => 'O', chr(195).chr(147) => 'O', chr(195).chr(148) => 'O', chr(195).chr(149) => 'O', chr(195).chr(150) => 'O', chr(195).chr(153) => 'U', chr(195).chr(154) => 'U', chr(195).chr(155) => 'U', chr(195).chr(156) => 'U', chr(195).chr(157) => 'Y', chr(195).chr(158) => 'TH',chr(195).chr(159) => 's', chr(195).chr(160) => 'a', chr(195).chr(161) => 'a', chr(195).chr(162) => 'a', chr(195).chr(163) => 'a', chr(195).chr(164) => 'a', chr(195).chr(165) => 'a', chr(195).chr(166) => 'ae',chr(195).chr(167) => 'c', chr(195).chr(168) => 'e', chr(195).chr(169) => 'e', chr(195).chr(170) => 'e', chr(195).chr(171) => 'e', chr(195).chr(172) => 'i', chr(195).chr(173) => 'i', chr(195).chr(174) => 'i', chr(195).chr(175) => 'i', chr(195).chr(176) => 'd', chr(195).chr(177) => 'n', chr(195).chr(178) => 'o', chr(195).chr(179) => 'o', chr(195).chr(180) => 'o', chr(195).chr(181) => 'o', chr(195).chr(182) => 'o', chr(195).chr(184) => 'o', chr(195).chr(185) => 'u', chr(195).chr(186) => 'u', chr(195).chr(187) => 'u', chr(195).chr(188) => 'u', chr(195).chr(189) => 'y', chr(195).chr(190) => 'th', chr(195).chr(191) => 'y', chr(195).chr(152) => 'O', // Decompositions for Latin Extended-A chr(196).chr(128) => 'A', chr(196).chr(129) => 'a', chr(196).chr(130) => 'A', chr(196).chr(131) => 'a', chr(196).chr(132) => 'A', chr(196).chr(133) => 'a', chr(196).chr(134) => 'C', chr(196).chr(135) => 'c', chr(196).chr(136) => 'C', chr(196).chr(137) => 'c', chr(196).chr(138) => 'C', chr(196).chr(139) => 'c', chr(196).chr(140) => 'C', chr(196).chr(141) => 'c', chr(196).chr(142) => 'D', chr(196).chr(143) => 'd', chr(196).chr(144) => 'D', chr(196).chr(145) => 'd', chr(196).chr(146) => 'E', chr(196).chr(147) => 'e', chr(196).chr(148) => 'E', chr(196).chr(149) => 'e', chr(196).chr(150) => 'E', chr(196).chr(151) => 'e', chr(196).chr(152) => 'E', chr(196).chr(153) => 'e', chr(196).chr(154) => 'E', chr(196).chr(155) => 'e', chr(196).chr(156) => 'G', chr(196).chr(157) => 'g', chr(196).chr(158) => 'G', chr(196).chr(159) => 'g', chr(196).chr(160) => 'G', chr(196).chr(161) => 'g', chr(196).chr(162) => 'G', chr(196).chr(163) => 'g', chr(196).chr(164) => 'H', chr(196).chr(165) => 'h', chr(196).chr(166) => 'H', chr(196).chr(167) => 'h', chr(196).chr(168) => 'I', chr(196).chr(169) => 'i', chr(196).chr(170) => 'I', chr(196).chr(171) => 'i', chr(196).chr(172) => 'I', chr(196).chr(173) => 'i', chr(196).chr(174) => 'I', chr(196).chr(175) => 'i', chr(196).chr(176) => 'I', chr(196).chr(177) => 'i', chr(196).chr(178) => 'IJ',chr(196).chr(179) => 'ij', chr(196).chr(180) => 'J', chr(196).chr(181) => 'j', chr(196).chr(182) => 'K', chr(196).chr(183) => 'k', chr(196).chr(184) => 'k', chr(196).chr(185) => 'L', chr(196).chr(186) => 'l', chr(196).chr(187) => 'L', chr(196).chr(188) => 'l', chr(196).chr(189) => 'L', chr(196).chr(190) => 'l', chr(196).chr(191) => 'L', chr(197).chr(128) => 'l', chr(197).chr(129) => 'L', chr(197).chr(130) => 'l', chr(197).chr(131) => 'N', chr(197).chr(132) => 'n', chr(197).chr(133) => 'N', chr(197).chr(134) => 'n', chr(197).chr(135) => 'N', chr(197).chr(136) => 'n', chr(197).chr(137) => 'N', chr(197).chr(138) => 'n', chr(197).chr(139) => 'N', chr(197).chr(140) => 'O', chr(197).chr(141) => 'o', chr(197).chr(142) => 'O', chr(197).chr(143) => 'o', chr(197).chr(144) => 'O', chr(197).chr(145) => 'o', chr(197).chr(146) => 'OE',chr(197).chr(147) => 'oe', chr(197).chr(148) => 'R',chr(197).chr(149) => 'r', chr(197).chr(150) => 'R',chr(197).chr(151) => 'r', chr(197).chr(152) => 'R',chr(197).chr(153) => 'r', chr(197).chr(154) => 'S',chr(197).chr(155) => 's', chr(197).chr(156) => 'S',chr(197).chr(157) => 's', chr(197).chr(158) => 'S',chr(197).chr(159) => 's', chr(197).chr(160) => 'S', chr(197).chr(161) => 's', chr(197).chr(162) => 'T', chr(197).chr(163) => 't', chr(197).chr(164) => 'T', chr(197).chr(165) => 't', chr(197).chr(166) => 'T', chr(197).chr(167) => 't', chr(197).chr(168) => 'U', chr(197).chr(169) => 'u', chr(197).chr(170) => 'U', chr(197).chr(171) => 'u', chr(197).chr(172) => 'U', chr(197).chr(173) => 'u', chr(197).chr(174) => 'U', chr(197).chr(175) => 'u', chr(197).chr(176) => 'U', chr(197).chr(177) => 'u', chr(197).chr(178) => 'U', chr(197).chr(179) => 'u', chr(197).chr(180) => 'W', chr(197).chr(181) => 'w', chr(197).chr(182) => 'Y', chr(197).chr(183) => 'y', chr(197).chr(184) => 'Y', chr(197).chr(185) => 'Z', chr(197).chr(186) => 'z', chr(197).chr(187) => 'Z', chr(197).chr(188) => 'z', chr(197).chr(189) => 'Z', chr(197).chr(190) => 'z', chr(197).chr(191) => 's', // Decompositions for Latin Extended-B chr(200).chr(152) => 'S', chr(200).chr(153) => 's', chr(200).chr(154) => 'T', chr(200).chr(155) => 't', // Euro Sign chr(226).chr(130).chr(172) => 'E', // GBP (Pound) Sign chr(194).chr(163) => '', // Vowels with diacritic (Vietnamese) // unmarked chr(198).chr(160) => 'O', chr(198).chr(161) => 'o', chr(198).chr(175) => 'U', chr(198).chr(176) => 'u', // grave accent chr(225).chr(186).chr(166) => 'A', chr(225).chr(186).chr(167) => 'a', chr(225).chr(186).chr(176) => 'A', chr(225).chr(186).chr(177) => 'a', chr(225).chr(187).chr(128) => 'E', chr(225).chr(187).chr(129) => 'e', chr(225).chr(187).chr(146) => 'O', chr(225).chr(187).chr(147) => 'o', chr(225).chr(187).chr(156) => 'O', chr(225).chr(187).chr(157) => 'o', chr(225).chr(187).chr(170) => 'U', chr(225).chr(187).chr(171) => 'u', chr(225).chr(187).chr(178) => 'Y', chr(225).chr(187).chr(179) => 'y', // hook chr(225).chr(186).chr(162) => 'A', chr(225).chr(186).chr(163) => 'a', chr(225).chr(186).chr(168) => 'A', chr(225).chr(186).chr(169) => 'a', chr(225).chr(186).chr(178) => 'A', chr(225).chr(186).chr(179) => 'a', chr(225).chr(186).chr(186) => 'E', chr(225).chr(186).chr(187) => 'e', chr(225).chr(187).chr(130) => 'E', chr(225).chr(187).chr(131) => 'e', chr(225).chr(187).chr(136) => 'I', chr(225).chr(187).chr(137) => 'i', chr(225).chr(187).chr(142) => 'O', chr(225).chr(187).chr(143) => 'o', chr(225).chr(187).chr(148) => 'O', chr(225).chr(187).chr(149) => 'o', chr(225).chr(187).chr(158) => 'O', chr(225).chr(187).chr(159) => 'o', chr(225).chr(187).chr(166) => 'U', chr(225).chr(187).chr(167) => 'u', chr(225).chr(187).chr(172) => 'U', chr(225).chr(187).chr(173) => 'u', chr(225).chr(187).chr(182) => 'Y', chr(225).chr(187).chr(183) => 'y', // tilde chr(225).chr(186).chr(170) => 'A', chr(225).chr(186).chr(171) => 'a', chr(225).chr(186).chr(180) => 'A', chr(225).chr(186).chr(181) => 'a', chr(225).chr(186).chr(188) => 'E', chr(225).chr(186).chr(189) => 'e', chr(225).chr(187).chr(132) => 'E', chr(225).chr(187).chr(133) => 'e', chr(225).chr(187).chr(150) => 'O', chr(225).chr(187).chr(151) => 'o', chr(225).chr(187).chr(160) => 'O', chr(225).chr(187).chr(161) => 'o', chr(225).chr(187).chr(174) => 'U', chr(225).chr(187).chr(175) => 'u', chr(225).chr(187).chr(184) => 'Y', chr(225).chr(187).chr(185) => 'y', // acute accent chr(225).chr(186).chr(164) => 'A', chr(225).chr(186).chr(165) => 'a', chr(225).chr(186).chr(174) => 'A', chr(225).chr(186).chr(175) => 'a', chr(225).chr(186).chr(190) => 'E', chr(225).chr(186).chr(191) => 'e', chr(225).chr(187).chr(144) => 'O', chr(225).chr(187).chr(145) => 'o', chr(225).chr(187).chr(154) => 'O', chr(225).chr(187).chr(155) => 'o', chr(225).chr(187).chr(168) => 'U', chr(225).chr(187).chr(169) => 'u', // dot below chr(225).chr(186).chr(160) => 'A', chr(225).chr(186).chr(161) => 'a', chr(225).chr(186).chr(172) => 'A', chr(225).chr(186).chr(173) => 'a', chr(225).chr(186).chr(182) => 'A', chr(225).chr(186).chr(183) => 'a', chr(225).chr(186).chr(184) => 'E', chr(225).chr(186).chr(185) => 'e', chr(225).chr(187).chr(134) => 'E', chr(225).chr(187).chr(135) => 'e', chr(225).chr(187).chr(138) => 'I', chr(225).chr(187).chr(139) => 'i', chr(225).chr(187).chr(140) => 'O', chr(225).chr(187).chr(141) => 'o', chr(225).chr(187).chr(152) => 'O', chr(225).chr(187).chr(153) => 'o', chr(225).chr(187).chr(162) => 'O', chr(225).chr(187).chr(163) => 'o', chr(225).chr(187).chr(164) => 'U', chr(225).chr(187).chr(165) => 'u', chr(225).chr(187).chr(176) => 'U', chr(225).chr(187).chr(177) => 'u', chr(225).chr(187).chr(180) => 'Y', chr(225).chr(187).chr(181) => 'y', // Vowels with diacritic (Chinese, Hanyu Pinyin) chr(201).chr(145) => 'a', // macron chr(199).chr(149) => 'U', chr(199).chr(150) => 'u', // acute accent chr(199).chr(151) => 'U', chr(199).chr(152) => 'u', // caron chr(199).chr(141) => 'A', chr(199).chr(142) => 'a', chr(199).chr(143) => 'I', chr(199).chr(144) => 'i', chr(199).chr(145) => 'O', chr(199).chr(146) => 'o', chr(199).chr(147) => 'U', chr(199).chr(148) => 'u', chr(199).chr(153) => 'U', chr(199).chr(154) => 'u', // grave accent chr(199).chr(155) => 'U', chr(199).chr(156) => 'u', ); /* // Used for locale-specific rules $locale = get_locale(); if ( 'de_DE' == $locale ) { $chars[ chr(195).chr(132) ] = 'Ae'; $chars[ chr(195).chr(164) ] = 'ae'; $chars[ chr(195).chr(150) ] = 'Oe'; $chars[ chr(195).chr(182) ] = 'oe'; $chars[ chr(195).chr(156) ] = 'Ue'; $chars[ chr(195).chr(188) ] = 'ue'; $chars[ chr(195).chr(159) ] = 'ss'; } elseif ( 'da_DK' === $locale ) { $chars[ chr(195).chr(134) ] = 'Ae'; $chars[ chr(195).chr(166) ] = 'ae'; $chars[ chr(195).chr(152) ] = 'Oe'; $chars[ chr(195).chr(184) ] = 'oe'; $chars[ chr(195).chr(133) ] = 'Aa'; $chars[ chr(195).chr(165) ] = 'aa'; } */ $string = strtr($string, $chars); return $string; } } ?>