multibyte_string_functions.lib.php 109 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645
  1. <?php
  2. /**
  3. * ==============================================================================
  4. * File: multibyte_string_functions.lib.php
  5. * Main API extension library for Dokeos 1.8.6+ LMS
  6. * A common purpose library for supporting multibyte string aware functions.
  7. * License: GNU/GPL version 2 or later (Free Software Foundation)
  8. * @author: Ivan Tcholakov, ivantcholakov@gmail.com
  9. * October 2008 - initial implementation.
  10. * May 2009 - refactoring and minor corrections have been implemented.
  11. * @package dokeos.library
  12. * ==============================================================================
  13. */
  14. /**
  15. * Notes:
  16. *
  17. * 1. For all the functions from this library witn optional encoding
  18. * parameters, the system's encoding is assumed by default, i.e. the
  19. * value that is returned by api_get_setting('platform_charset') or
  20. * the value of the global variable $charset.
  21. *
  22. * 2. In other aspects, most of the functions in this library try to copy
  23. * behaviour of some core PHP functions and some functions from the
  24. * mbstring extension. Mostly they have similar names prefixed with "api_".
  25. * For your convenience, links have been given to the documentation of the
  26. * original PHP functions. Thus, you may exploit on your previous habits.
  27. *
  28. * 3. Why these function have been introduced? Because they are able to
  29. * support more encodings than the original ones. And which is more
  30. * important - they are UTF-8 aware. So, they should be used for strings
  31. * in natural language. For internal system identificators of file names
  32. * which are supposed to contain only English letters you may use the
  33. * original PHP string functions.
  34. *
  35. * 4. This library requires PHP mbstring extension to be activated.
  36. * When encodings to be used are not supported by mbstring, this library
  37. * is able to exploit the PHP iconv extesion, which in this case should
  38. * be activated too.
  39. *
  40. * 5. For improved sorting of multibyte strings the library uses the intl
  41. * php-extension if it is installed.
  42. */
  43. /**
  44. * ----------------------------------------------------------------------------
  45. * A safe way to calculate binary lenght of a string (as number of bytes)
  46. * ----------------------------------------------------------------------------
  47. */
  48. /**
  49. * Calculates binary lenght of a string, as number of bytes, regardless the php-setting mbstring.func_overload.
  50. * This function should work for all multi-byte related changes of PHP5 configuration.
  51. * @param string $string The input string.
  52. * @return int Returns the length of the input string (or binary data) as number of bytes.
  53. */
  54. function api_byte_count($string) {
  55. static $use_mb_strlen;
  56. if (!isset($use_mb_strlen)) {
  57. $use_mb_strlen = MBSTRING_INSTALLED && ((int) ini_get('mbstring.func_overload') & 2);
  58. }
  59. if ($use_mb_strlen) {
  60. return mb_strlen($string, '8bit');
  61. }
  62. return strlen($string);
  63. // For PHP6 this function probably will contain:
  64. //return strlen((binary)$string);
  65. }
  66. /**
  67. * ----------------------------------------------------------------------------
  68. * Multibyte string conversion functions
  69. * ----------------------------------------------------------------------------
  70. */
  71. /**
  72. * Converts character encoding of a given string.
  73. * @param string $string The string being converted.
  74. * @param string $to_encoding The encoding that $string is being converted to.
  75. * @param string $from_encoding (optional) The encoding that $string is being converted from. If it is omited, the platform character set is assumed.
  76. * @return string Returns the converted string.
  77. * This function is aimed at replacing the function mb_convert_encoding() for human-language strings.
  78. * @link http://php.net/manual/en/function.mb-convert-encoding
  79. */
  80. function api_convert_encoding($string, $to_encoding, $from_encoding = null) {
  81. if (empty($from_encoding)) {
  82. $from_encoding = api_mb_internal_encoding();
  83. }
  84. if (api_equal_encodings($to_encoding, $from_encoding)) {
  85. // When conversion is not needed, the string is returned directly, without validation.
  86. return $string;
  87. }
  88. if (api_mb_supports($to_encoding) && api_mb_supports($from_encoding)) {
  89. return @mb_convert_encoding($string, $to_encoding, $from_encoding);
  90. }
  91. elseif (api_iconv_supports($to_encoding) && api_iconv_supports($from_encoding)) {
  92. return @iconv($from_encoding, $to_encoding, $string);
  93. }
  94. // Here the function gives up.
  95. return $string;
  96. }
  97. /**
  98. * Converts a given string into UTF-8 encoded string.
  99. * @param string $string The string being converted.
  100. * @param string $from_encoding (optional) The encoding that $string is being converted from. If it is omited, the platform character set is assumed.
  101. * @return string Returns the converted string.
  102. * This function is aimed at replacing the function utf8_encode() for human-language strings.
  103. * @link http://php.net/manual/en/function.utf8-encode
  104. */
  105. function api_utf8_encode($string, $from_encoding = null) {
  106. if (empty($from_encoding)) {
  107. $from_encoding = api_mb_internal_encoding();
  108. }
  109. if (api_is_utf8($from_encoding)) {
  110. // When conversion is not needed, the string is returned directly, without validation.
  111. return $string;
  112. }
  113. if (api_mb_supports($from_encoding)) {
  114. return @mb_convert_encoding($string, 'UTF-8', $from_encoding);
  115. }
  116. elseif (api_iconv_supports($from_encoding)) {
  117. return @iconv($from_encoding, 'UTF-8', $string);
  118. }
  119. // Here the function gives up.
  120. return $string;
  121. }
  122. /**
  123. * Converts a given string from UTF-8 encoding to a specified encoding.
  124. * @param string $string The string being converted.
  125. * @param string $to_encoding (optional) The encoding that $string is being converted to. If it is omited, the platform character set is assumed.
  126. * @return string Returns the converted string.
  127. * This function is aimed at replacing the function utf8_decode() for human-language strings.
  128. * @link http://php.net/manual/en/function.utf8-decode
  129. */
  130. function api_utf8_decode($string, $to_encoding = null) {
  131. if (empty($to_encoding)) {
  132. $to_encoding = api_mb_internal_encoding();
  133. }
  134. if (api_is_utf8($to_encoding)) {
  135. // When conversion is not needed, the string is returned directly, without validation.
  136. return $string;
  137. }
  138. if (api_mb_supports($to_encoding)) {
  139. return @mb_convert_encoding($string, $to_encoding, 'UTF-8');
  140. }
  141. elseif (api_iconv_supports($to_encoding)) {
  142. return @iconv('UTF-8', $to_encoding, $string);
  143. }
  144. // Here the function gives up.
  145. return $string;
  146. }
  147. /**
  148. * Converts a given string into the system ecoding (or platform character set).
  149. * When $from encoding is omited on UTF-8 platforms then language dependent encoding
  150. * is guessed/assumed. On non-UTF-8 platforms omited $from encoding is assumed as UTF-8.
  151. * When the parameter $check_utf8_validity is true the function checks string's
  152. * UTF-8 validity and decides whether to try to convert it or not.
  153. * This function is useful for problem detection or making workarounds.
  154. * @param string $string The string being converted.
  155. * @param string $from_encoding (optional) The encoding that $string is being converted from. It is guessed when it is omited.
  156. * @param bool $check_utf8_validity (optional) A flag for UTF-8 validity check as condition for making conversion.
  157. * @return string Returns the converted string.
  158. */
  159. function api_to_system_encoding($string, $from_encoding = null, $check_utf8_validity = false) {
  160. $system_encoding = api_get_system_encoding();
  161. if (empty($from_encoding)) {
  162. if (api_is_utf8($system_encoding)) {
  163. $from_encoding = api_get_non_utf8_encoding();
  164. } else {
  165. $from_encoding = 'UTF-8';
  166. }
  167. }
  168. if (api_equal_encodings($system_encoding, $from_encoding)) {
  169. return $string;
  170. }
  171. if ($check_utf8_validity) {
  172. if (api_is_utf8($system_encoding)) {
  173. if (api_is_valid_utf8($string)) {
  174. return $string;
  175. }
  176. }
  177. elseif (api_is_utf8($from_encoding)) {
  178. if (!api_is_valid_utf8($string)) {
  179. return $string;
  180. }
  181. }
  182. }
  183. return api_convert_encoding($string, $system_encoding, $from_encoding);
  184. }
  185. /**
  186. * Converts all applicable characters to HTML entities.
  187. * @param string $string The input string.
  188. * @param int $quote_style (optional) The quote style - ENT_COMPAT (default), ENT_QUOTES, ENT_NOQUOTES.
  189. * @param string $encoding (optional) The encoding (of the input string) used in conversion. If it is omited, the platform character set is assumed.
  190. * @return string Returns the converted string.
  191. * This function is aimed at replacing the function htmlentities() for human-language strings.
  192. * @link http://php.net/manual/en/function.htmlentities
  193. */
  194. function api_htmlentities($string, $quote_style = ENT_COMPAT, $encoding = null) {
  195. if (empty($encoding)) {
  196. $encoding = api_mb_internal_encoding();
  197. }
  198. if (!api_is_utf8($encoding) && api_html_entity_supports($encoding)) {
  199. return htmlentities($string, $quote_style, $encoding);
  200. }
  201. if (!api_is_encoding_supported($encoding)) {
  202. return $string;
  203. }
  204. $string = api_convert_encoding(api_utf8_encode($string, $encoding), 'HTML-ENTITIES', 'UTF-8');
  205. switch($quote_style) {
  206. case ENT_COMPAT:
  207. $string = str_replace("'", '&quot;', $string);
  208. break;
  209. case ENT_QUOTES:
  210. $string = str_replace("'", '&#039;', str_replace('"', '&quot;', $string));
  211. break;
  212. }
  213. return $string;
  214. }
  215. /**
  216. * Convers HTML entities into normal characters.
  217. * @param string $string The input string.
  218. * @param int $quote_style (optional) The quote style - ENT_COMPAT (default), ENT_QUOTES, ENT_NOQUOTES.
  219. * @param string $encoding (optional) The encoding (of the result) used in conversion. If it is omited, the platform character set is assumed.
  220. * @return string Returns the converted string.
  221. * This function is aimed at replacing the function html_entity_decode() for human-language strings.
  222. * @link http://php.net/html_entity_decode
  223. */
  224. function api_html_entity_decode($string, $quote_style = ENT_COMPAT, $encoding = null) {
  225. if (empty($encoding)) {
  226. $encoding = api_mb_internal_encoding();
  227. }
  228. if (!api_is_utf8($encoding) && api_html_entity_supports($encoding)) {
  229. return html_entity_decode($string, $quote_style, $encoding);
  230. }
  231. if (!api_is_encoding_supported($encoding)) {
  232. return $string;
  233. }
  234. return api_utf8_decode(html_entity_decode(api_convert_encoding($string, 'UTF-8', $encoding), $quote_style, 'UTF-8'), $encoding);
  235. }
  236. /**
  237. * This function encodes (conditionally) a given string to UTF-8 if XmlHttp-request has been detected.
  238. * @param string $string The string being converted.
  239. * @param string $from_encoding (optional) The encoding that $string is being converted from. If it is omited, the platform character set is assumed.
  240. * @return string Returns the converted string.
  241. */
  242. function api_xml_http_response_encode($string, $from_encoding = null) {
  243. if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
  244. return api_convert_encoding($string, 'UTF-8', $from_encoding);
  245. }
  246. return $string;
  247. }
  248. /**
  249. * This function converts a given string to the encoding that filesystem uses for representing file/folder names.
  250. * @param string $string The string being converted.
  251. * @param string $from_encoding (optional) The encoding that $string is being converted from. If it is omited, the platform character set is assumed.
  252. * @return string Returns the converted string.
  253. */
  254. function api_file_system_encode($string, $from_encoding = null) {
  255. if (empty($from_encoding)) {
  256. $from_encoding = api_mb_internal_encoding();
  257. }
  258. return api_convert_encoding($string, api_get_file_system_encoding(), $from_encoding);
  259. }
  260. /**
  261. * This function converts a given string from the encoding that filesystem uses for representing file/folder names.
  262. * @param string $string The string being converted.
  263. * @param string $from_encoding (optional) The encoding that $string is being converted from. If it is omited, the platform character set is assumed.
  264. * @return string Returns the converted string.
  265. */
  266. function api_file_system_decode($string, $to_encoding = null) {
  267. if (empty($to_encoding)) {
  268. $to_encoding = api_mb_internal_encoding();
  269. }
  270. return api_convert_encoding($string, $to_encoding, api_get_file_system_encoding());
  271. }
  272. /**
  273. * ----------------------------------------------------------------------------
  274. * Common multibyte string functions
  275. * ----------------------------------------------------------------------------
  276. */
  277. /**
  278. * Executes a regular expression match with extended multibyte support.
  279. * By default this function uses the platform character set.
  280. * @param string $pattern The regular expression pattern.
  281. * @param string $string The searched string.
  282. * @param array $regs (optional) If specified, by this passed by reference parameter an array containing found match and its substrings is returned.
  283. * @return mixed 1 if match is found, FALSE if not. If $regs has been specified, byte-length of the found match is returned, or FALSE if no match has been found.
  284. * This function is aimed at replacing the functions ereg() and mb_ereg() for human-language strings.
  285. * @link http://php.net/manual/en/function.ereg
  286. * @link http://php.net/manual/en/function.mb-ereg
  287. */
  288. function api_ereg($pattern, $string, & $regs = null) {
  289. $count = func_num_args();
  290. $encoding = api_mb_regex_encoding();
  291. if (api_mb_supports($encoding)) {
  292. if ($count < 3) {
  293. return @mb_ereg($pattern, $string);
  294. } else {
  295. $result = @mb_ereg($pattern, $string, $regs);
  296. return $result;
  297. }
  298. }
  299. elseif (api_iconv_supports($encoding)) {
  300. api_mb_regex_encoding('UTF-8');
  301. if ($count < 3) {
  302. $result = @mb_ereg(api_utf8_encode($pattern, $encoding), api_utf8_encode($string, $encoding));
  303. } else {
  304. $result = @mb_ereg(api_utf8_encode($pattern, $encoding), api_utf8_encode($string, $encoding), $regs);
  305. $regs = _api_array_utf8_decode($regs, $encoding);
  306. }
  307. api_mb_regex_encoding($encoding);
  308. return $result;
  309. } else {
  310. if ($count < 3) {
  311. return ereg($pattern, $string);
  312. } else {
  313. return ereg($pattern, $string, $regs);
  314. }
  315. }
  316. }
  317. /**
  318. * Scans string for matches to pattern, then replaces the matched text with replacement, with extended multibyte support.
  319. * By default this function uses the platform character set.
  320. * @param string $pattern The regular expression pattern.
  321. * @param string $replacement The replacement text.
  322. * @param string $string The searched string.
  323. * @param string $option (optional) Matching condition.
  324. * If i is specified for the matching condition parameter, the case will be ignored.
  325. * If x is specified, white space will be ignored.
  326. * If m is specified, match will be executed in multiline mode and line break will be included in '.'.
  327. * If p is specified, match will be executed in POSIX mode, line break will be considered as normal character.
  328. * If e is specified, replacement string will be evaluated as PHP expression.
  329. * @return mixed The modified string is returned. If no matches are found within the string, then it will be returned unchanged. FALSE will be returned on error.
  330. * This function is aimed at replacing the functions ereg_replace() and mb_ereg_replace() for human-language strings.
  331. * @link http://php.net/manual/en/function.ereg-replace
  332. * @link http://php.net/manual/en/function.mb-ereg-replace
  333. */
  334. function api_ereg_replace($pattern, $replacement, $string, $option = null) {
  335. $encoding = api_mb_regex_encoding();
  336. if (api_mb_supports($encoding)) {
  337. if (is_null($option)) {
  338. return @mb_ereg_replace($pattern, $replacement, $string);
  339. } else {
  340. return @mb_ereg_replace($pattern, $replacement, $string, $option);
  341. }
  342. }
  343. elseif (api_iconv_supports($encoding)) {
  344. api_mb_regex_encoding('UTF-8');
  345. if (is_null($option)) {
  346. $result = api_utf8_decode(@mb_ereg_replace(api_utf8_encode($pattern, $encoding), api_utf8_encode($replacement, $encoding), api_utf8_encode($string, $encoding)), $encoding);
  347. } else {
  348. $result = api_utf8_decode(@mb_ereg_replace(api_utf8_encode($pattern, $encoding), api_utf8_encode($replacement, $encoding), api_utf8_encode($string, $encoding), $option), $encoding);
  349. }
  350. api_mb_regex_encoding($encoding);
  351. return $result;
  352. } else {
  353. return ereg_replace($pattern, $replacement, $string);
  354. }
  355. }
  356. // This is a helper callback function for internal purposes.
  357. function _api_array_utf8_decode($variable, $encoding) {
  358. if (is_array($variable)) {
  359. return array_map('_api_array_utf8_decode', $variable, $encoding);
  360. }
  361. if (is_string($var)) {
  362. return api_utf8_decode($variable, $encoding);
  363. }
  364. return $variable;
  365. }
  366. /**
  367. * Executes a regular expression match, ignoring case, with extended multibyte support.
  368. * By default this function uses the platform character set.
  369. * @param string $pattern The regular expression pattern.
  370. * @param string $string The searched string.
  371. * @param array $regs (optional) If specified, by this passed by reference parameter an array containing found match and its substrings is returned.
  372. * @return mixed 1 if match is found, FALSE if not. If $regs has been specified, byte-length of the found match is returned, or FALSE if no match has been found.
  373. * This function is aimed at replacing the functions eregi() and mb_eregi() for human-language strings.
  374. * @link http://php.net/manual/en/function.eregi
  375. * @link http://php.net/manual/en/function.mb-eregi
  376. */
  377. function api_eregi($pattern, $string, & $regs = null) {
  378. $count = func_num_args();
  379. $encoding = api_mb_regex_encoding();
  380. if (api_mb_supports($encoding)) {
  381. if ($count < 3) {
  382. return @mb_eregi($pattern, $string);
  383. } else {
  384. return @mb_eregi($pattern, $string, $regs);
  385. }
  386. }
  387. elseif (api_iconv_supports($encoding)) {
  388. api_mb_regex_encoding('UTF-8');
  389. if ($count < 3) {
  390. $result = @mb_eregi(api_utf8_encode($pattern, $encoding), api_utf8_encode($string, $encoding));
  391. } else {
  392. $result = @mb_eregi(api_utf8_encode($pattern, $encoding), api_utf8_encode($string, $encoding), $regs);
  393. $regs = _api_array_utf8_decode($regs, $encoding);
  394. }
  395. api_mb_regex_encoding($encoding);
  396. return $result;
  397. } else {
  398. if ($count < 3) {
  399. return eregi($pattern, $string);
  400. } else {
  401. return eregi($pattern, $string, $regs);
  402. }
  403. }
  404. }
  405. /**
  406. * Scans string for matches to pattern, then replaces the matched text with replacement, ignoring case, with extended multibyte support.
  407. * By default this function uses the platform character set.
  408. * @param string $pattern The regular expression pattern.
  409. * @param string $replacement The replacement text.
  410. * @param string $string The searched string.
  411. * @param string $option (optional) Matching condition.
  412. * If i is specified for the matching condition parameter, the case will be ignored.
  413. * If x is specified, white space will be ignored.
  414. * If m is specified, match will be executed in multiline mode and line break will be included in '.'.
  415. * If p is specified, match will be executed in POSIX mode, line break will be considered as normal character.
  416. * If e is specified, replacement string will be evaluated as PHP expression.
  417. * @return mixed The modified string is returned. If no matches are found within the string, then it will be returned unchanged. FALSE will be returned on error.
  418. * This function is aimed at replacing the functions eregi_replace() and mb_eregi_replace() for human-language strings.
  419. * @link http://php.net/manual/en/function.eregi-replace
  420. * @link http://php.net/manual/en/function.mb-eregi-replace
  421. */
  422. function api_eregi_replace($pattern, $replacement, $string, $option = null) {
  423. $encoding = api_mb_regex_encoding();
  424. if (api_mb_supports($encoding)) {
  425. if (is_null($option)) {
  426. return @mb_eregi_replace($pattern, $replacement, $string);
  427. } else {
  428. return @mb_eregi_replace($pattern, $replacement, $string, $option);
  429. }
  430. }
  431. elseif (api_iconv_supports($encoding)) {
  432. api_mb_regex_encoding('UTF-8');
  433. if (is_null($option)) {
  434. $result = api_utf8_decode(@mb_eregi_replace(api_utf8_encode($pattern, $encoding), api_utf8_encode($replacement, $encoding), api_utf8_encode($string, $encoding)), $encoding);
  435. } else {
  436. $result = api_utf8_decode(@mb_eregi_replace(api_utf8_encode($pattern, $encoding), api_utf8_encode($replacement, $encoding), api_utf8_encode($string, $encoding), $option), $encoding);
  437. }
  438. api_mb_regex_encoding($encoding);
  439. return $result;
  440. } else {
  441. return eregi_replace($pattern, $replacement, $string);
  442. }
  443. }
  444. /**
  445. * Splits a multibyte string using regular expression pattern and returns the result as an array.
  446. * By default this function uses the platform character set.
  447. * @param string $pattern The regular expression pattern.
  448. * @param string $string The string being split.
  449. * @param int $limit (optional) If this optional parameter $limit is specified, the string will be split in $limit elements as maximum.
  450. * @return array The result as an array.
  451. * This function is aimed at replacing the functions split() and mb_split() for human-language strings.
  452. * @link http://php.net/manual/en/function.split
  453. * @link http://php.net/manual/en/function.mb-split
  454. */
  455. function api_split($pattern, $string, $limit = null) {
  456. $encoding = api_mb_regex_encoding();
  457. if (api_mb_supports($encoding)) {
  458. if (is_null($limit)) {
  459. return @mb_split($pattern, $string);
  460. } else {
  461. return @mb_split($pattern, $string, $limit);
  462. }
  463. }
  464. elseif (api_iconv_supports($encoding)) {
  465. api_mb_regex_encoding('UTF-8');
  466. if (is_null($limit)) {
  467. $result = @mb_split(api_utf8_encode($pattern, $encoding), api_utf8_encode($string, $encoding));
  468. } else {
  469. $result = @mb_split(api_utf8_encode($pattern, $encoding), api_utf8_encode($string, $encoding), $limit);
  470. }
  471. $result = _api_array_utf8_decode($result, $encoding);
  472. api_mb_regex_encoding($encoding);
  473. return $result;
  474. } else {
  475. if (is_null($limit)) {
  476. return split($pattern, $string);
  477. } else {
  478. return split($pattern, $string, $limit);
  479. }
  480. }
  481. }
  482. /**
  483. * This function returns a string or an array with all occurrences of search in subject (ignoring case) replaced with the given replace value.
  484. * @param mixed $search String or array of strings to be found.
  485. * @param mixed $replace String or array of strings used for replacement.
  486. * @param mixed $subject String or array of strings being searced.
  487. * @param int $count (optional) The number of matched and replaced needles will be returned in count, which is passed by reference.
  488. * @param string $encoding (optional) The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
  489. * @return mixed String or array as a result.
  490. * Notes:
  491. * If $subject is an array, then the search and replace is performed with every entry of subject, the return value is an array.
  492. * If $search and $replace are arrays, then the function takes a value from each array and uses it to do search and replace on subject.
  493. * If $replace has fewer values than search, then an empty string is used for the rest of replacement values.
  494. * If $search is an array and $replace is a string, then this replacement string is used for every value of search.
  495. * This function is aimed at replacing the function str_ireplace() for human-language strings.
  496. * @link http://php.net/manual/en/function.str-ireplace
  497. * TODO: To be revised and to be checked.
  498. */
  499. function api_str_ireplace($search, $replace, $subject, & $count = null, $encoding = null) {
  500. if (empty($encoding)) {
  501. $encoding = api_mb_internal_encoding();
  502. }
  503. if (is_array($subject)) {
  504. foreach ($subject as $key => $val) {
  505. $subject[$key] = api_str_ireplace($search, $replace, $val, $count, $encoding);
  506. }
  507. return $subject;
  508. }
  509. if (is_array($search)) {
  510. foreach (array_keys($search) as $key) {
  511. if (is_array($replace)) {
  512. if (array_key_exists($key, $replace)) {
  513. $subject = api_str_ireplace($search[$key], $replace[$key], $subject, $count, $encoding);
  514. } else {
  515. $subject = api_str_ireplace($search[$key], '', $subject, $count, $encoding);
  516. }
  517. } else {
  518. $subject = api_str_ireplace($search[$key], $replace, $subject, $count, $encoding);
  519. }
  520. }
  521. return $subject;
  522. }
  523. $search = api_strtolower($search, $encoding);
  524. $subject_lower = api_strtolower($subject, $encoding);
  525. $total_matched_strlen = 0;
  526. $i = 0;
  527. while (preg_match(api_add_pcre_unicode_modifier('/(.*?)'.preg_quote($search, '/').'/s', $encoding), $subject_lower, $matches)) {
  528. $matched_strlen = api_strlen($matches[0], $encoding);
  529. $subject_lower = api_substr($subject_lower, $matched_strlen, api_strlen($subject_lower, $encoding), $encoding);
  530. $offset = $total_matched_strlen + api_strlen($matches[1], $encoding) + ($i * (api_strlen($replace, $encoding) - 1));
  531. $subject = api_substr_replace($subject, $replace, $offset, api_strlen($search), $encoding);
  532. $total_matched_strlen += $matched_strlen;
  533. $i++;
  534. }
  535. $count += $i;
  536. return $subject;
  537. }
  538. /**
  539. * Converts a string to an array.
  540. * @param string $string The input string.
  541. * @param int $split_length Maximum character-length of the chunk, one character by default.
  542. * @param string $encoding (optional) The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
  543. * @return array The result array of chunks with the spcified length.
  544. * Notes:
  545. * If the optional split_length parameter is specified, the returned array will be broken down into chunks
  546. * with each being split_length in length, otherwise each chunk will be one character in length.
  547. * FALSE is returned if split_length is less than 1.
  548. * If the split_length length exceeds the length of string, the entire string is returned as the first (and only) array element.
  549. * This function is aimed at replacing the function str_split() for human-language strings.
  550. * @link http://php.net/str_split
  551. */
  552. function api_str_split($string, $split_length = 1, $encoding = null) {
  553. if ($split_length < 1) {
  554. return false;
  555. }
  556. if (empty($encoding)) {
  557. $encoding = api_mb_internal_encoding();
  558. }
  559. $result = array();
  560. if (api_mb_supports($encoding)) {
  561. for ($i = 0, $length = @mb_strlen($string, $encoding); $i < $length; $i += $split_length) {
  562. $result[] = @mb_substr($string, $i, $split_length, $encoding);
  563. }
  564. }
  565. elseif (api_iconv_supports($encoding)) {
  566. for ($i = 0, $length = api_strlen($string, $encoding); $i < $length; $i += $split_length) {
  567. $result[] = api_substr($string, $i, $split_length, $encoding);
  568. }
  569. } else {
  570. for ($i = 0, $length = strlen($string); $i < $length; $i += $split_length) {
  571. $result[] = substr($string, $i, $split_length);
  572. }
  573. }
  574. return $result;
  575. }
  576. /**
  577. * Finds position of first occurrence of a string within another, case insensitive.
  578. * @param string $haystack The string from which to get the position of the first occurrence.
  579. * @param string $needle The string to be found.
  580. * @param int $offset The position in $haystack to start searching from. If it is omitted, searching starts from the beginning.
  581. * @param string $encoding (optional) The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
  582. * @return mixed Returns the numeric position of the first occurrence of $needle in the $haystack, or FALSE if $needle is not found.
  583. * Note: The first character's position is 0, the second character position is 1, and so on.
  584. * This function is aimed at replacing the functions stripos() and mb_stripos() for human-language strings.
  585. * @link http://php.net/manual/en/function.stripos
  586. * @link http://php.net/manual/en/function.mb-stripos
  587. */
  588. function api_stripos($haystack, $needle, $offset = 0, $encoding = null) {
  589. if (empty($encoding)){
  590. $encoding = api_mb_internal_encoding();
  591. }
  592. if (api_mb_supports($encoding)) {
  593. return @mb_stripos($haystack, $needle, $offset, $encoding);
  594. } elseif (api_iconv_supports($encoding)) {
  595. return api_utf8_decode(@mb_stripos(api_utf8_encode($haystack, $encoding), api_utf8_encode($needle, $encoding), $offset, 'UTF-8'), $encoding);
  596. }
  597. return stripos($haystack, $needle, $offset);
  598. }
  599. /**
  600. * Finds first occurrence of a string within another, case insensitive.
  601. * @param string $haystack The string from which to get the first occurrence.
  602. * @param string @needle The string to be found.
  603. * @param bool $part (optional) Determines which portion of $haystack this function returns. The default value is FALSE.
  604. * @param string $encoding (optional) The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
  605. * @return mixed Returns the portion of $haystack, or FALSE if $needle is not found.
  606. * Notes:
  607. * If $part is set to TRUE, the function returns all of $haystack from the beginning to the first occurrence of $needle.
  608. * If $part is set to FALSE, the function returns all of $haystack from the first occurrence of $needle to the end.
  609. * This function is aimed at replacing the functions stristr() and mb_stristr() for human-language strings.
  610. * @link http://php.net/manual/en/function.stristr
  611. * @link http://php.net/manual/en/function.mb-stristr
  612. */
  613. function api_stristr($haystack, $needle, $part = false, $encoding = null) {
  614. if (empty($encoding)) {
  615. $encoding = api_mb_internal_encoding();
  616. }
  617. if (api_mb_supports($encoding)) {
  618. return @mb_stristr($haystack, $needle, $part, $encoding);
  619. }
  620. elseif (api_iconv_supports($encoding)) {
  621. return api_utf8_decode(@mb_stristr(api_utf8_encode($haystack, $encoding), api_utf8_encode($needle, $encoding), $part, 'UTF-8'));
  622. }
  623. return stristr($haystack, $needle, $part);
  624. }
  625. /**
  626. * Returns length of the input string.
  627. * @param string $string The string which length is to be calculated.
  628. * @param string $encoding (optional) The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
  629. * @return int Returns the number of characters within the string. A multi-byte character is counted as 1.
  630. * This function is aimed at replacing the functions strlen() and mb_strlen() for human-language strings.
  631. * @link http://php.net/manual/en/function.strlen
  632. * @link http://php.net/manual/en/function.mb-strlen
  633. * Note: When you use strlen() to test for an empty string, you needn't change it to api_strlen().
  634. * For example, in lines like the following:
  635. * if (strlen($string) > 0)
  636. * if (strlen($string) != 0)
  637. * there is no need the original function strlen() to be changed, it works correctly and faster for these cases.
  638. */
  639. function api_strlen($string, $encoding = null) {
  640. if (empty($encoding)) {
  641. $encoding = api_mb_internal_encoding();
  642. }
  643. if (api_mb_supports($encoding)) {
  644. return @mb_strlen($string, $encoding);
  645. }
  646. elseif (api_iconv_supports($encoding)) {
  647. return @iconv_strlen($string, $encoding);
  648. }
  649. return strlen($string);
  650. }
  651. /**
  652. * Finds position of first occurrence of a string within another.
  653. * @param string $haystack The string from which to get the position of the first occurrence.
  654. * @param string $needle The string to be found.
  655. * @param int $offset (optional) The position in $haystack to start searching from. If it is omitted, searching starts from the beginning.
  656. * @param string $encoding (optional) The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
  657. * @return mixed Returns the numeric position of the first occurrence of $needle in the $haystack, or FALSE if $needle is not found.
  658. * Note: The first character's position is 0, the second character position is 1, and so on.
  659. * This function is aimed at replacing the functions strpos() and mb_strpos() for human-language strings.
  660. * @link http://php.net/manual/en/function.strpos
  661. * @link http://php.net/manual/en/function.mb-strpos
  662. */
  663. function api_strpos($haystack, $needle, $offset = 0, $encoding = null) {
  664. if (empty($encoding)) {
  665. $encoding = api_mb_internal_encoding();
  666. }
  667. if (api_mb_supports($encoding)) {
  668. return @mb_strpos($haystack, $needle, $offset, $encoding);
  669. }
  670. elseif (api_iconv_supports($encoding)) {
  671. return api_utf8_decode(@mb_strpos(api_utf8_encode($haystack, $encoding), api_utf8_encode($needle, $encoding), $offset, 'UTF-8'), $encoding);
  672. }
  673. return strpos($haystack, $needle, $offset);
  674. }
  675. /**
  676. * Finds the last occurrence of a character in a string.
  677. * @param string $haystack The string from which to get the last occurrence.
  678. * @param string $needle The string which first character is to be found.
  679. * @param bool $part (optional) Determines which portion of $haystack this function returns. The default value is FALSE.
  680. * @param string $encoding (optional) The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
  681. * @return mixed Returns the portion of $haystack, or FALSE if the first character from $needle is not found.
  682. * Notes:
  683. * If $part is set to TRUE, the function returns all of $haystack from the beginning to the first occurrence.
  684. * If $part is set to FALSE, the function returns all of $haystack from the first occurrence to the end.
  685. * This function is aimed at replacing the functions strrchr() and mb_strrchr() for human-language strings.
  686. * @link http://php.net/manual/en/function.strrchr
  687. * @link http://php.net/manual/en/function.mb-strrchr
  688. */
  689. function api_strrchr($haystack, $needle, $part = false, $encoding = null) {
  690. if (empty($encoding)) {
  691. $encoding = api_mb_internal_encoding();
  692. }
  693. if (api_mb_supports($encoding)) {
  694. return @mb_strrchr($haystack, $needle, $part, $encoding);
  695. }
  696. elseif (api_iconv_supports($encoding)) {
  697. return api_utf8_decode(@mb_strrchr(api_utf8_encode($haystack, $encoding), api_utf8_encode($needle, $encoding), $part, 'UTF-8'), $encoding);
  698. }
  699. return strrchr($haystack, $needle);
  700. }
  701. /**
  702. * Reverses a string.
  703. * @param string $string The string to be reversed.
  704. * @param string $encoding (optional) The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
  705. * @return string Returns the reversed string.
  706. * This function is aimed at replacing the function strrev() for human-language strings.
  707. * @link http://php.net/manual/en/function.strrev
  708. */
  709. function api_strrev($string, $encoding = null) {
  710. if (empty($string)) {
  711. return '';
  712. }
  713. if (empty($encoding)) {
  714. $encoding = api_mb_internal_encoding();
  715. }
  716. $result = '';
  717. for ($i = api_strlen($string, $encoding) - 1; $i > -1; $i--) {
  718. $result .= api_substr($string, $i, 1, $encoding);
  719. }
  720. return $result;
  721. }
  722. /**
  723. * Finds the position of last occurrence of a string in a string.
  724. * @param string $haystack The string from which to get the position of the last occurrence.
  725. * @param string $needle The string to be found.
  726. * @param int $offset (optional) $offset may be specified to begin searching an arbitrary position. Negative values will stop searching at an arbitrary point prior to the end of the string.
  727. * @param string $encoding (optional) The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
  728. * @return mixed Returns the numeric position of the first occurrence of $needle in the $haystack, or FALSE if $needle is not found.
  729. * Note: The first character's position is 0, the second character position is 1, and so on.
  730. * This function is aimed at replacing the functions strrpos() and mb_strrpos() for human-language strings.
  731. * @link http://php.net/manual/en/function.strrpos
  732. * @link http://php.net/manual/en/function.mb-strrpos
  733. */
  734. function api_strrpos($haystack, $needle, $offset = 0, $encoding = null) {
  735. if (empty($encoding)) {
  736. $encoding = api_mb_internal_encoding();
  737. }
  738. if (api_mb_supports($encoding)) {
  739. return @mb_strrpos($haystack, $needle, $offset, $encoding);
  740. }
  741. elseif (api_iconv_supports($encoding)) {
  742. return api_utf8_decode(@mb_strrpos(api_utf8_encode($haystack, $encoding), api_utf8_encode($needle, $encoding), $offset, 'UTF-8'), $encoding);
  743. }
  744. return strrpos($haystack, $needle, $offset);
  745. }
  746. /**
  747. * Finds first occurrence of a string within another.
  748. * @param string $haystack The string from which to get the first occurrence.
  749. * @param string @needle The string to be found.
  750. * @param bool $part (optional) Determines which portion of $haystack this function returns. The default value is FALSE.
  751. * @param string $encoding (optional) The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
  752. * @return mixed Returns the portion of $haystack, or FALSE if $needle is not found.
  753. * Notes:
  754. * If $part is set to TRUE, the function returns all of $haystack from the beginning to the first occurrence of $needle.
  755. * If $part is set to FALSE, the function returns all of $haystack from the first occurrence of $needle to the end.
  756. * This function is aimed at replacing the functions strstr() and mb_strstr() for human-language strings.
  757. * @link http://php.net/manual/en/function.strstr
  758. * @link http://php.net/manual/en/function.mb-strstr
  759. */
  760. function api_strstr($haystack, $needle, $part = false, $encoding = null) {
  761. if (empty($encoding)) {
  762. $encoding = api_mb_internal_encoding();
  763. }
  764. if (api_mb_supports($encoding)) {
  765. return @mb_strstr($haystack, $needle, $part, $encoding);
  766. }
  767. elseif (api_iconv_supports($encoding)) {
  768. return api_utf8_decode(@mb_strstr(api_utf8_encode($haystack, $encoding), api_utf8_encode($needle, $encoding), $part, 'UTF-8'), $encoding);
  769. }
  770. return strstr($haystack, $needle, $part);
  771. }
  772. /**
  773. * Makes a string lowercase.
  774. * @param string $string The string being lowercased.
  775. * @param string $encoding (optional) The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
  776. * @return string Returns the string with all alphabetic characters converted to lowercase.
  777. * This function is aimed at replacing the functions strtolower() and mb_strtolower() for human-language strings.
  778. * @link http://php.net/manual/en/function.strtolower
  779. * @link http://php.net/manual/en/function.mb-strtolower
  780. */
  781. function api_strtolower($string, $encoding = null) {
  782. if (empty($encoding)) {
  783. $encoding = api_mb_internal_encoding();
  784. }
  785. if (api_mb_supports($encoding)) {
  786. return @mb_strtolower($string, $encoding);
  787. }
  788. elseif (api_iconv_supports($encoding)) {
  789. return api_utf8_decode(@mb_strtolower(api_utf8_encode($string, $encoding), 'UTF-8'), $encoding);
  790. }
  791. return strtolower($string);
  792. }
  793. /**
  794. * Makes a string uppercase.
  795. * @param string $string The string being uppercased.
  796. * @param string $encoding (optional) The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
  797. * @return string Returns the string with all alphabetic characters converted to uppercase.
  798. * This function is aimed at replacing the functions strtoupper() and mb_strtoupper() for human-language strings.
  799. * @link http://php.net/manual/en/function.strtoupper
  800. * @link http://php.net/manual/en/function.mb-strtoupper
  801. */
  802. function api_strtoupper($string, $encoding = null) {
  803. if (empty($encoding)) {
  804. $encoding = api_mb_internal_encoding();
  805. }
  806. if (api_mb_supports($encoding)) {
  807. return @mb_strtoupper($string, $encoding);
  808. }
  809. elseif (api_iconv_supports($encoding)) {
  810. return api_utf8_decode(@mb_strtoupper(api_utf8_encode($string, $encoding), 'UTF-8'), $encoding);
  811. }
  812. return strtoupper($string);
  813. }
  814. /**
  815. * Translates certain characters.
  816. * @param string $string The string being translated.
  817. * @param mixed $from A string that contains the character to be replaced. This parameter can be also an array with pairs of characters 'from' => 'to'.
  818. * @param string $to (optional) A string that contains the replacing characters.
  819. * @param string $encoding (optional) The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
  820. * @return string Returns a copy of $string, translating all occurrences of each character in $from to the corresponding character in $to.
  821. * This function is aimed at replacing the function strtr() for human-language strings.
  822. * @link http://php.net/manual/en/function.strtr
  823. * TODO: To be revised and tested. Probably this function will be not needed.
  824. */
  825. function api_strtr($string, $from, $to = null, $encoding = null) {
  826. if (empty($string)) {
  827. return '';
  828. }
  829. if (is_array($from)) {
  830. if (empty($from)) {
  831. return $string;
  832. }
  833. $encoding = $to;
  834. if (empty($encoding)){
  835. $encoding = api_mb_internal_encoding();
  836. }
  837. $translator = $from;
  838. } else {
  839. if (empty($from) || empty($to)) {
  840. return $string;
  841. }
  842. if (empty($encoding)) {
  843. $encoding = api_mb_internal_encoding();
  844. }
  845. $translator = array();
  846. $arr_from = api_str_split($from, 1, $encoding);
  847. $arr_to = api_str_split($to, 1, $encoding);
  848. $n = count($arr_from);
  849. $n2 = count($arr_to);
  850. if ($n > $n2) $n = $n2;
  851. for ($i = 0; $i < $n; $i++) {
  852. $translator[$arr_from[$i]] = $arr_to[$i];
  853. }
  854. }
  855. $arr_string = api_str_split($string, 1, $encoding);
  856. $n = count($arr_string);
  857. $result = '';
  858. for ($i = 0; $i < $n; $i++) {
  859. if (is_set($translator[$arr_string[$i]])) {
  860. $result .= $translator[$arr_string[$i]];
  861. } else {
  862. $result .= $arr_string[$i];
  863. }
  864. }
  865. return $result;
  866. }
  867. /**
  868. // Gets part of a string.
  869. * @param string $string The input string.
  870. * @param int $start The first position from which the extracted part begins.
  871. * @param int $length The length in character of the extracted part.
  872. * @param string $encoding (optional) The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
  873. * @return string Returns the part of the string specified by the start and length parameters.
  874. * Note: First character's position is 0. Second character position is 1, and so on.
  875. * This function is aimed at replacing the functions substr() and mb_substr() for human-language strings.
  876. * @link http://php.net/manual/en/function.substr
  877. * @link http://php.net/manual/en/function.mb-substr
  878. */
  879. function api_substr($string, $start, $length = null, $encoding = null) {
  880. if (empty($encoding)) {
  881. $encoding = api_mb_internal_encoding();
  882. }
  883. // Passing null as $length would mean 0. This behaviour has been corrected here.
  884. if (is_null($length)) {
  885. $length = api_strlen($string, $encoding);
  886. }
  887. if (api_mb_supports($encoding)) {
  888. return @mb_substr($string, $start, $length, $encoding);
  889. }
  890. elseif (api_iconv_supports($encoding)) {
  891. return api_utf8_decode(@mb_substr(api_utf8_encode($string, $encoding), $start, $length, 'UTF-8'), $encoding);
  892. }
  893. return substr($string, $start, $length);
  894. }
  895. /**
  896. * Replaces text within a portion of a string.
  897. * @param string $string The input string.
  898. * @param string $replacement The replacement string.
  899. * @param int $start The position from which replacing will begin.
  900. * Notes:
  901. * If $start is positive, the replacing will begin at the $start'th offset into the string.
  902. * If $start is negative, the replacing will begin at the $start'th character from the end of the string.
  903. * @param int $length (optional) The position where replacing will end.
  904. * Notes:
  905. * If given and is positive, it represents the length of the portion of the string which is to be replaced.
  906. * If it is negative, it represents the number of characters from the end of string at which to stop replacing.
  907. * If it is not given, then it will default to api_strlen($string); i.e. end the replacing at the end of string.
  908. * If $length is zero, then this function will have the effect of inserting replacement into the string at the given start offset.
  909. * @param string $encoding (optional) The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
  910. * @return string The result string is returned.
  911. * This function is aimed at replacing the function substr_replace() for human-language strings.
  912. * @link http://php.net/manual/function.substr-replace
  913. */
  914. function api_substr_replace($string, $replacement, $start, $length = null, $encoding = null) {
  915. if (empty($encoding)) {
  916. $encoding = api_mb_internal_encoding();
  917. }
  918. if ($length == null) {
  919. return api_substr($string, 0, $start, $encoding) . $replacement;
  920. } else {
  921. if ($length < 0) {
  922. $length = api_strlen($string, $encoding) - $start + $length;
  923. }
  924. return
  925. api_substr($string, 0, $start, $encoding) . $replacement .
  926. api_substr($string, $start + $length, api_strlen($string, $encoding), $encoding);
  927. }
  928. }
  929. /**
  930. * Makes a string's first character uppercase.
  931. * @param string $string The input string.
  932. * @param string $encoding (optional) The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
  933. * @return string Returns a string with the first character capitalized, if that character is alphabetic.
  934. * This function is aimed at replacing the function ucfirst() for human-language strings.
  935. * @link http://php.net/manual/en/function.ucfirst
  936. */
  937. function api_ucfirst($string, $encoding = null) {
  938. if (empty($encoding)) {
  939. $encoding = api_mb_internal_encoding();
  940. }
  941. return api_strtoupper(api_substr($string, 0, 1, $encoding), $encoding) . api_substr($string, 1, api_strlen($string, $encoding), $encoding);
  942. }
  943. /**
  944. * Uppercases the first character of each word in a string.
  945. * @param string $string The input string.
  946. * @param string $encoding (optional) The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
  947. * @return string Returns the modified string.
  948. * This function is aimed at replacing the function ucwords() for human-language strings.
  949. * @link http://php.net/manual/en/function.ucwords
  950. */
  951. function api_ucwords($string, $encoding = null) {
  952. if (empty($encoding)) {
  953. $encoding = api_mb_internal_encoding();
  954. }
  955. if (api_mb_supports($encoding)) {
  956. return @mb_convert_case($string, MB_CASE_TITLE, $encoding);
  957. }
  958. elseif (api_iconv_supports($encoding)) {
  959. return api_utf8_decode(@mb_convert_case(api_utf8_encode($string, $encoding), MB_CASE_TITLE, 'UTF-8'), $encoding);
  960. }
  961. return ucwords($string);
  962. }
  963. /**
  964. * This function adds a unicode modifier (u suffix) to a Perl-compatible regular expression depending on the specified encoding.
  965. * @param string $pcre The Perl-compatible regular expression.
  966. * @param string $encoding (optional) The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
  967. * @return string Returns the same regular expression wit a suffix 'u' if $encoding is 'UTF-8'.
  968. */
  969. function api_add_pcre_unicode_modifier($pcre, $encoding = null) {
  970. if (empty($encoding)){
  971. $encoding = api_get_system_encoding();
  972. }
  973. return api_is_utf8($encoding) ? $pcre.'u' : $pcre;
  974. }
  975. /**
  976. * ----------------------------------------------------------------------------
  977. * String comparison
  978. * ----------------------------------------------------------------------------
  979. */
  980. /**
  981. * Performs string comparison, case insensitive, language sensitive, with extended multibyte support.
  982. * @param string $string1 The first string.
  983. * @param string $string2 The second string.
  984. * @param string $language (optional) The language in which comparison is to be made. If language is omitted, interface language is assumed then.
  985. * @param string $encoding (optional) The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
  986. * @return int Returns < 0 if $string1 is less than $string2; > 0 if $string1 is greater than $string2; and 0 if the strings are equal.
  987. * This function is aimed at replacing the function strcasecmp() for human-language strings.
  988. * @link http://php.net/manual/en/function.strcasecmp
  989. */
  990. function api_strcasecmp($string1, $string2, $language = null, $encoding = null) {
  991. return api_strcmp(api_strtolower($string1, $encoding), api_strtolower($string2, $encoding), $language, $encoding);
  992. }
  993. /**
  994. * Performs string comparison, case sensitive, language sensitive, with extended multibyte support.
  995. * @param string $string1 The first string.
  996. * @param string $string2 The second string.
  997. * @param string $language (optional) The language in which comparison is to be made. If language is omitted, interface language is assumed then.
  998. * @param string $encoding (optional) The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
  999. * @return int Returns < 0 if $string1 is less than $string2; > 0 if $string1 is greater than $string2; and 0 if the strings are equal.
  1000. * This function is aimed at replacing the function strcmp() for human-language strings.
  1001. * @link http://php.net/manual/en/function.strcmp.php
  1002. * @link http://php.net/manual/en/collator.compare.php
  1003. */
  1004. function api_strcmp($string1, $string2, $language = null, $encoding = null) {
  1005. if (INTL_INSTALLED) {
  1006. $collator = _api_get_collator($language);
  1007. if (is_object($collator)) {
  1008. $result = collator_compare($collator, api_utf8_encode($string1, $encoding), api_utf8_encode($string2, $encoding));
  1009. return $result === false ? 0 : $result;
  1010. }
  1011. }
  1012. return strcmp($string1, $string2);
  1013. }
  1014. /**
  1015. * Performs string comparison in so called "natural order", case insensitive, language sensitive, with extended multibyte support.
  1016. * @param string $string1 The first string.
  1017. * @param string $string2 The second string.
  1018. * @param string $language (optional) The language in which comparison is to be made. If language is omitted, interface language is assumed then.
  1019. * @param string $encoding (optional) The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
  1020. * @return int Returns < 0 if $string1 is less than $string2; > 0 if $string1 is greater than $string2; and 0 if the strings are equal.
  1021. * This function is aimed at replacing the function strnatcasecmp() for human-language strings.
  1022. * @link http://php.net/manual/en/function.strnatcasecmp
  1023. */
  1024. function api_strnatcasecmp($string1, $string2, $language = null, $encoding = null) {
  1025. return api_strnatcmp(api_strtolower($string1, $encoding), api_strtolower($string2, $encoding), $language, $encoding);
  1026. }
  1027. /**
  1028. * Performs string comparison in so called "natural order", case sensitive, language sensitive, with extended multibyte support.
  1029. * @param string $string1 The first string.
  1030. * @param string $string2 The second string.
  1031. * @param string $language (optional) The language in which comparison is to be made. If language is omitted, interface language is assumed then.
  1032. * @param string $encoding (optional) The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
  1033. * @return int Returns < 0 if $string1 is less than $string2; > 0 if $string1 is greater than $string2; and 0 if the strings are equal.
  1034. * This function is aimed at replacing the function strnatcmp() for human-language strings.
  1035. * @link http://php.net/manual/en/function.strnatcmp.php
  1036. * @link http://php.net/manual/en/collator.compare.php
  1037. */
  1038. function api_strnatcmp($string1, $string2, $language = null, $encoding = null) {
  1039. if (INTL_INSTALLED) {
  1040. $collator = _api_get_alpha_numerical_collator($language);
  1041. if (is_object($collator)) {
  1042. $result = collator_compare($collator, api_utf8_encode($string1, $encoding), api_utf8_encode($string2, $encoding));
  1043. return $result === false ? 0 : $result;
  1044. }
  1045. }
  1046. return strnatcmp($string1, $string2);
  1047. }
  1048. /**
  1049. * Checks if a value exists in an array, a case insensitive version of in_array() function with extended multibyte support.
  1050. * @param mixed $needle The searched value. If needle is a string, the comparison is done in a case-insensitive manner.
  1051. * @param array $haystack The array.
  1052. * @param bool $strict (optional) If is set to TRUE then the function will also check the types of the $needle in the $haystack. The default value if FALSE.
  1053. * @param string $encoding (optional) The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
  1054. * @return bool Returns TRUE if $needle is found in the array, FALSE otherwise.
  1055. * @link http://php.net/manual/en/function.in-array.php
  1056. */
  1057. function api_in_array_nocase($needle, $haystack, $strict = false, $encoding = null) {
  1058. if (is_array($needle)) {
  1059. foreach ($needle as $item) {
  1060. if (api_in_array_nocase($item, $haystack, $strict, $encoding)) return true;
  1061. }
  1062. return false;
  1063. }
  1064. if (!is_string($needle)) {
  1065. return in_array($needle, $haystack, $strict);
  1066. }
  1067. $needle = api_strtolower($needle, $encoding);
  1068. foreach ($haystack as $item) {
  1069. if ($strict && !is_string($item)) {
  1070. continue;
  1071. }
  1072. if (api_strtolower($item, $encoding) == $needle) {
  1073. return true;
  1074. }
  1075. }
  1076. return false;
  1077. }
  1078. // Returns an instance of Collator class (ICU) created for a specified language, for internal use.
  1079. function _api_get_collator($language = null) {
  1080. static $collator = array();
  1081. if (!isset($collator[$language])) {
  1082. $locale = api_get_locale_from_language($language);
  1083. $collator[$language] = collator_create($locale);
  1084. if (is_object($collator[$language])) {
  1085. collator_set_attribute($collator[$language], Collator::CASE_FIRST, Collator::UPPER_FIRST);
  1086. }
  1087. }
  1088. return $collator[$language];
  1089. }
  1090. // Returns an instance of Collator class (ICU) created for a specified language, for internal use.
  1091. // This collator treats substrings of digits as numbers.
  1092. function _api_get_alpha_numerical_collator($language = null) {
  1093. static $collator = array();
  1094. if (!isset($collator[$language])) {
  1095. $locale = api_get_locale_from_language($language);
  1096. $collator[$language] = collator_create($locale);
  1097. if (is_object($collator[$language])) {
  1098. collator_set_attribute($collator[$language], Collator::CASE_FIRST, Collator::UPPER_FIRST);
  1099. collator_set_attribute($collator[$language], Collator::NUMERIC_COLLATION, Collator::ON);
  1100. }
  1101. }
  1102. return $collator[$language];
  1103. }
  1104. /**
  1105. * ----------------------------------------------------------------------------
  1106. * Sorting arrays
  1107. * ----------------------------------------------------------------------------
  1108. */
  1109. /**
  1110. * Sorts an array with maintaining index association, elements will be arranged from the lowest to the highest.
  1111. * @param array $array The input array.
  1112. * @param int $sort_flag (optional) Shows how elements of the array to be compared.
  1113. * @param string $language (optional) The language in which comparison is to be made. If language is omitted, interface language is assumed then.
  1114. * @param string $encoding (optional) The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
  1115. * @return bool Returns TRUE on success, FALSE on error.
  1116. * Note: $sort_flag may have the following values:
  1117. * SORT_REGULAR - internal PHP-rules for comparison will be applied, without preliminary changing types;
  1118. * SORT_NUMERIC - items will be compared as numbers;
  1119. * SORT_STRING - items will be compared as strings. If intl extension is enabled, then comparison will be language-sensitive using internally a created ICU locale;
  1120. * SORT_LOCALE_STRING - items will be compared as strings depending on the current POSIX locale. If intl extension is enabled, then comparison will be language-sensitive using internally a created ICU locale.
  1121. * This function is aimed at replacing the function asort() for sorting human-language strings.
  1122. * @link http://php.net/manual/en/function.asort.php
  1123. * @link http://php.net/manual/en/collator.asort.php
  1124. */
  1125. function api_asort(&$array, $sort_flag = SORT_REGULAR, $language = null, $encoding = null) {
  1126. if (INTL_INSTALLED) {
  1127. if (empty($encoding)) {
  1128. $encoding = api_mb_internal_encoding();
  1129. }
  1130. $collator = _api_get_collator($language);
  1131. if (is_object($collator)) {
  1132. if (api_is_utf8($encoding)) {
  1133. $sort_flag = ($sort_flag == SORT_LOCALE_STRING) ? SORT_STRING : $sort_flag;
  1134. return collator_asort($collator, $array, _api_get_collator_sort_flag($sort_flag));
  1135. }
  1136. elseif ($sort_flag == SORT_STRING || $sort_flag == SORT_LOCALE_STRING) {
  1137. global $_api_collator, $_api_encoding;
  1138. $_api_collator = $collator;
  1139. $_api_encoding = $encoding;
  1140. return uasort($array, '_api_cmp');
  1141. }
  1142. }
  1143. }
  1144. return asort($array, $sort_flag);
  1145. }
  1146. /**
  1147. * Sorts an array with maintaining index association, elements will be arranged from the highest to the lowest (in reverse order).
  1148. * @param array $array The input array.
  1149. * @param int $sort_flag (optional) Shows how elements of the array to be compared.
  1150. * @param string $language (optional) The language in which comparison is to be made. If language is omitted, interface language is assumed then.
  1151. * @param string $encoding (optional) The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
  1152. * @return bool Returns TRUE on success, FALSE on error.
  1153. * Note: $sort_flag may have the following values:
  1154. * SORT_REGULAR - internal PHP-rules for comparison will be applied, without preliminary changing types;
  1155. * SORT_NUMERIC - items will be compared as numbers;
  1156. * SORT_STRING - items will be compared as strings. If intl extension is enabled, then comparison will be language-sensitive using internally a created ICU locale;
  1157. * SORT_LOCALE_STRING - items will be compared as strings depending on the current POSIX locale. If intl extension is enabled, then comparison will be language-sensitive using internally a created ICU locale.
  1158. * This function is aimed at replacing the function arsort() for sorting human-language strings.
  1159. * @link http://php.net/manual/en/function.arsort.php
  1160. */
  1161. function api_arsort(&$array, $sort_flag = SORT_REGULAR, $language = null, $encoding = null) {
  1162. if (INTL_INSTALLED) {
  1163. if (empty($encoding)) {
  1164. $encoding = api_mb_internal_encoding();
  1165. }
  1166. $collator = _api_get_collator($language);
  1167. if (is_object($collator)) {
  1168. if ($sort_flag == SORT_STRING || $sort_flag == SORT_LOCALE_STRING) {
  1169. global $_api_collator, $_api_encoding;
  1170. $_api_collator = $collator;
  1171. $_api_encoding = $encoding;
  1172. return uasort($array, '_api_rcmp');
  1173. }
  1174. }
  1175. }
  1176. return arsort($array, $sort_flag);
  1177. }
  1178. /**
  1179. * Sorts an array using natural order algorithm.
  1180. * @param array $array The input array.
  1181. * @param string $language (optional) The language in which comparison is to be made. If language is omitted, interface language is assumed then.
  1182. * @param string $encoding (optional) The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
  1183. * @return bool Returns TRUE on success, FALSE on error.
  1184. * This function is aimed at replacing the function natsort() for sorting human-language strings.
  1185. * @link http://php.net/manual/en/function.natsort.php
  1186. */
  1187. function api_natsort(&$array, $language = null, $encoding = null) {
  1188. if (INTL_INSTALLED) {
  1189. if (empty($encoding)) {
  1190. $encoding = api_mb_internal_encoding();
  1191. }
  1192. $collator = _api_get_alpha_numerical_collator($language);
  1193. if (is_object($collator)) {
  1194. global $_api_collator, $_api_encoding;
  1195. $_api_collator = $collator;
  1196. $_api_encoding = $encoding;
  1197. return uasort($array, '_api_cmp');
  1198. }
  1199. }
  1200. return natsort($array);
  1201. }
  1202. /**
  1203. * Sorts an array using natural order algorithm in reverse order.
  1204. * @param array $array The input array.
  1205. * @param string $language (optional) The language in which comparison is to be made. If language is omitted, interface language is assumed then.
  1206. * @param string $encoding (optional) The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
  1207. * @return bool Returns TRUE on success, FALSE on error.
  1208. */
  1209. function api_natrsort(&$array, $language = null, $encoding = null) {
  1210. if (INTL_INSTALLED) {
  1211. if (empty($encoding)) {
  1212. $encoding = api_mb_internal_encoding();
  1213. }
  1214. $collator = _api_get_alpha_numerical_collator($language);
  1215. if (is_object($collator)) {
  1216. global $_api_collator, $_api_encoding;
  1217. $_api_collator = $collator;
  1218. $_api_encoding = $encoding;
  1219. return uasort($array, '_api_rcmp');
  1220. }
  1221. }
  1222. return uasort($array, '_api_strnatrcmp');
  1223. }
  1224. /**
  1225. * Sorts an array using natural order algorithm, case-insensitive.
  1226. * @param array $array The input array.
  1227. * @param string $language (optional) The language in which comparison is to be made. If language is omitted, interface language is assumed then.
  1228. * @param string $encoding (optional) The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
  1229. * @return bool Returns TRUE on success, FALSE on error.
  1230. * This function is aimed at replacing the function natcasesort() for sorting human-language strings.
  1231. * @link http://php.net/manual/en/function.natcasesort.php
  1232. */
  1233. function api_natcasesort(&$array, $language = null, $encoding = null) {
  1234. if (INTL_INSTALLED) {
  1235. if (empty($encoding)) {
  1236. $encoding = api_mb_internal_encoding();
  1237. }
  1238. $collator = _api_get_alpha_numerical_collator($language);
  1239. if (is_object($collator)) {
  1240. global $_api_collator, $_api_encoding;
  1241. $_api_collator = $collator;
  1242. $_api_encoding = $encoding;
  1243. return uasort($array, '_api_casecmp');
  1244. }
  1245. }
  1246. return natcasesort($array);
  1247. }
  1248. /**
  1249. * Sorts an array using natural order algorithm, case-insensitive, reverse order.
  1250. * @param array $array The input array.
  1251. * @param string $language (optional) The language in which comparison is to be made. If language is omitted, interface language is assumed then.
  1252. * @param string $encoding (optional) The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
  1253. * @return bool Returns TRUE on success, FALSE on error.
  1254. */
  1255. function api_natcasersort(&$array, $language = null, $encoding = null) {
  1256. if (INTL_INSTALLED) {
  1257. if (empty($encoding)) {
  1258. $encoding = api_mb_internal_encoding();
  1259. }
  1260. $collator = _api_get_alpha_numerical_collator($language);
  1261. if (is_object($collator)) {
  1262. global $_api_collator, $_api_encoding;
  1263. $_api_collator = $collator;
  1264. $_api_encoding = $encoding;
  1265. return uasort($array, '_api_casercmp');
  1266. }
  1267. }
  1268. return uasort($array, '_api_strnatcasercmp');
  1269. }
  1270. /**
  1271. * Sorts an array by keys, elements will be arranged from the lowest key to the highest key.
  1272. * @param array $array The input array.
  1273. * @param int $sort_flag (optional) Shows how keys of the array to be compared.
  1274. * @param string $language (optional) The language in which comparison is to be made. If language is omitted, interface language is assumed then.
  1275. * @param string $encoding (optional) The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
  1276. * @return bool Returns TRUE on success, FALSE on error.
  1277. * Note: $sort_flag may have the following values:
  1278. * SORT_REGULAR - internal PHP-rules for comparison will be applied, without preliminary changing types;
  1279. * SORT_NUMERIC - keys will be compared as numbers;
  1280. * SORT_STRING - keys will be compared as strings. If intl extension is enabled, then comparison will be language-sensitive using internally a created ICU locale;
  1281. * SORT_LOCALE_STRING - keys will be compared as strings depending on the current POSIX locale. If intl extension is enabled, then comparison will be language-sensitive using internally a created ICU locale.
  1282. * This function is aimed at replacing the function ksort() for sorting human-language key strings.
  1283. * @link http://php.net/manual/en/function.ksort.php
  1284. */
  1285. function api_ksort(&$array, $sort_flag = SORT_REGULAR, $language = null, $encoding = null) {
  1286. if (INTL_INSTALLED) {
  1287. if (empty($encoding)) {
  1288. $encoding = api_mb_internal_encoding();
  1289. }
  1290. $collator = _api_get_collator($language);
  1291. if (is_object($collator)) {
  1292. if ($sort_flag == SORT_STRING || $sort_flag == SORT_LOCALE_STRING) {
  1293. global $_api_collator, $_api_encoding;
  1294. $_api_collator = $collator;
  1295. $_api_encoding = $encoding;
  1296. return uksort($array, '_api_cmp');
  1297. }
  1298. }
  1299. }
  1300. return ksort($array, $sort_flag);
  1301. }
  1302. /**
  1303. * Sorts an array by keys, elements will be arranged from the highest key to the lowest key (in reverse order).
  1304. * @param array $array The input array.
  1305. * @param int $sort_flag (optional) Shows how keys of the array to be compared.
  1306. * @param string $language (optional) The language in which comparison is to be made. If language is omitted, interface language is assumed then.
  1307. * @param string $encoding (optional) The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
  1308. * @return bool Returns TRUE on success, FALSE on error.
  1309. * Note: $sort_flag may have the following values:
  1310. * SORT_REGULAR - internal PHP-rules for comparison will be applied, without preliminary changing types;
  1311. * SORT_NUMERIC - keys will be compared as numbers;
  1312. * SORT_STRING - keys will be compared as strings. If intl extension is enabled, then comparison will be language-sensitive using internally a created ICU locale;
  1313. * SORT_LOCALE_STRING - keys will be compared as strings depending on the current POSIX locale. If intl extension is enabled, then comparison will be language-sensitive using internally a created ICU locale.
  1314. * This function is aimed at replacing the function krsort() for sorting human-language key strings.
  1315. * @link http://php.net/manual/en/function.krsort.php
  1316. */
  1317. function api_krsort(&$array, $sort_flag = SORT_REGULAR, $language = null, $encoding = null) {
  1318. if (INTL_INSTALLED) {
  1319. if (empty($encoding)) {
  1320. $encoding = api_mb_internal_encoding();
  1321. }
  1322. $collator = _api_get_collator($language);
  1323. if (is_object($collator)) {
  1324. if ($sort_flag == SORT_STRING || $sort_flag == SORT_LOCALE_STRING) {
  1325. global $_api_collator, $_api_encoding;
  1326. $_api_collator = $collator;
  1327. $_api_encoding = $encoding;
  1328. return uksort($array, '_api_rcmp');
  1329. }
  1330. }
  1331. }
  1332. return krsort($array, $sort_flag);
  1333. }
  1334. /**
  1335. * Sorts an array by keys using natural order algorithm.
  1336. * @param array $array The input array.
  1337. * @param string $language (optional) The language in which comparison is to be made. If language is omitted, interface language is assumed then.
  1338. * @param string $encoding (optional) The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
  1339. * @return bool Returns TRUE on success, FALSE on error.
  1340. */
  1341. function api_knatsort(&$array, $language = null, $encoding = null) {
  1342. if (INTL_INSTALLED) {
  1343. if (empty($encoding)) {
  1344. $encoding = api_mb_internal_encoding();
  1345. }
  1346. $collator = _api_get_alpha_numerical_collator($language);
  1347. if (is_object($collator)) {
  1348. global $_api_collator, $_api_encoding;
  1349. $_api_collator = $collator;
  1350. $_api_encoding = $encoding;
  1351. return uksort($array, '_api_cmp');
  1352. }
  1353. }
  1354. return uksort($array, 'strnatcmp');
  1355. }
  1356. /**
  1357. * Sorts an array by keys using natural order algorithm in reverse order.
  1358. * @param array $array The input array.
  1359. * @param string $language (optional) The language in which comparison is to be made. If language is omitted, interface language is assumed then.
  1360. * @param string $encoding (optional) The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
  1361. * @return bool Returns TRUE on success, FALSE on error.
  1362. */
  1363. function api_knatrsort(&$array, $language = null, $encoding = null) {
  1364. if (INTL_INSTALLED) {
  1365. if (empty($encoding)) {
  1366. $encoding = api_mb_internal_encoding();
  1367. }
  1368. $collator = _api_get_alpha_numerical_collator($language);
  1369. if (is_object($collator)) {
  1370. global $_api_collator, $_api_encoding;
  1371. $_api_collator = $collator;
  1372. $_api_encoding = $encoding;
  1373. return uksort($array, '_api_rcmp');
  1374. }
  1375. }
  1376. return uksort($array, '_api_strnatrcmp');
  1377. }
  1378. /**
  1379. * Sorts an array by keys using natural order algorithm, case insensitive.
  1380. * @param array $array The input array.
  1381. * @param string $language (optional) The language in which comparison is to be made. If language is omitted, interface language is assumed then.
  1382. * @param string $encoding (optional) The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
  1383. * @return bool Returns TRUE on success, FALSE on error.
  1384. */
  1385. function api_knatcasesort(&$array, $language = null, $encoding = null) {
  1386. if (INTL_INSTALLED) {
  1387. if (empty($encoding)) {
  1388. $encoding = api_mb_internal_encoding();
  1389. }
  1390. $collator = _api_get_alpha_numerical_collator($language);
  1391. if (is_object($collator)) {
  1392. global $_api_collator, $_api_encoding;
  1393. $_api_collator = $collator;
  1394. $_api_encoding = $encoding;
  1395. return uksort($array, '_api_casecmp');
  1396. }
  1397. }
  1398. return uksort($array, 'strnatcasecmp');
  1399. }
  1400. /**
  1401. * Sorts an array by keys using natural order algorithm, case insensitive, reverse order.
  1402. * @param array $array The input array.
  1403. * @param string $language (optional) The language in which comparison is to be made. If language is omitted, interface language is assumed then.
  1404. * @param string $encoding (optional) The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
  1405. * @return bool Returns TRUE on success, FALSE on error.
  1406. */
  1407. function api_knatcasersort(&$array, $language = null, $encoding = null) {
  1408. if (INTL_INSTALLED) {
  1409. if (empty($encoding)) {
  1410. $encoding = api_mb_internal_encoding();
  1411. }
  1412. $collator = _api_get_alpha_numerical_collator($language);
  1413. if (is_object($collator)) {
  1414. global $_api_collator, $_api_encoding;
  1415. $_api_collator = $collator;
  1416. $_api_encoding = $encoding;
  1417. return uksort($array, '_api_casercmp');
  1418. }
  1419. }
  1420. return uksort($array, '_api_strnatcasercmp');
  1421. }
  1422. /**
  1423. * Sorts an array, elements will be arranged from the lowest to the highest.
  1424. * @param array $array The input array.
  1425. * @param int $sort_flag (optional) Shows how elements of the array to be compared.
  1426. * @param string $language (optional) The language in which comparison is to be made. If language is omitted, interface language is assumed then.
  1427. * @param string $encoding (optional) The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
  1428. * @return bool Returns TRUE on success, FALSE on error.
  1429. * Note: $sort_flag may have the following values:
  1430. * SORT_REGULAR - internal PHP-rules for comparison will be applied, without preliminary changing types;
  1431. * SORT_NUMERIC - items will be compared as numbers;
  1432. * SORT_STRING - items will be compared as strings. If intl extension is enabled, then comparison will be language-sensitive using internally a created ICU locale;
  1433. * SORT_LOCALE_STRING - items will be compared as strings depending on the current POSIX locale. If intl extension is enabled, then comparison will be language-sensitive using internally a created ICU locale.
  1434. * This function is aimed at replacing the function sort() for sorting human-language strings.
  1435. * @link http://php.net/manual/en/function.sort.php
  1436. * @link http://php.net/manual/en/collator.sort.php
  1437. */
  1438. function api_sort(&$array, $sort_flag = SORT_REGULAR, $language = null, $encoding = null) {
  1439. if (INTL_INSTALLED) {
  1440. if (empty($encoding)) {
  1441. $encoding = api_mb_internal_encoding();
  1442. }
  1443. $collator = _api_get_collator($language);
  1444. if (is_object($collator)) {
  1445. if (api_is_utf8($encoding)) {
  1446. $sort_flag = ($sort_flag == SORT_LOCALE_STRING) ? SORT_STRING : $sort_flag;
  1447. return collator_sort($collator, $array, _api_get_collator_sort_flag($sort_flag));
  1448. }
  1449. elseif ($sort_flag == SORT_STRING || $sort_flag == SORT_LOCALE_STRING) {
  1450. global $_api_collator, $_api_encoding;
  1451. $_api_collator = $collator;
  1452. $_api_encoding = $encoding;
  1453. return usort($array, '_api_cmp');
  1454. }
  1455. }
  1456. }
  1457. return sort($array, $sort_flag);
  1458. }
  1459. /**
  1460. * Sorts an array, elements will be arranged from the highest to the lowest (in reverse order).
  1461. * @param array $array The input array.
  1462. * @param int $sort_flag (optional) Shows how elements of the array to be compared.
  1463. * @param string $language (optional) The language in which comparison is to be made. If language is omitted, interface language is assumed then.
  1464. * @param string $encoding (optional) The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
  1465. * @return bool Returns TRUE on success, FALSE on error.
  1466. * Note: $sort_flag may have the following values:
  1467. * SORT_REGULAR - internal PHP-rules for comparison will be applied, without preliminary changing types;
  1468. * SORT_NUMERIC - items will be compared as numbers;
  1469. * SORT_STRING - items will be compared as strings. If intl extension is enabled, then comparison will be language-sensitive using internally a created ICU locale;
  1470. * SORT_LOCALE_STRING - items will be compared as strings depending on the current POSIX locale. If intl extension is enabled, then comparison will be language-sensitive using internally a created ICU locale.
  1471. * This function is aimed at replacing the function rsort() for sorting human-language strings.
  1472. * @link http://php.net/manual/en/function.rsort.php
  1473. */
  1474. function api_rsort(&$array, $sort_flag = SORT_REGULAR, $language = null, $encoding = null) {
  1475. if (INTL_INSTALLED) {
  1476. if (empty($encoding)) {
  1477. $encoding = api_mb_internal_encoding();
  1478. }
  1479. $collator = _api_get_collator($language);
  1480. if (is_object($collator)) {
  1481. if ($sort_flag == SORT_STRING || $sort_flag == SORT_LOCALE_STRING) {
  1482. global $_api_collator, $_api_encoding;
  1483. $_api_collator = $collator;
  1484. $_api_encoding = $encoding;
  1485. return usort($array, '_api_rcmp');
  1486. }
  1487. }
  1488. }
  1489. return rsort($array, $sort_flag);
  1490. }
  1491. // Global variables used by the sorting functions, for internal use.
  1492. $_api_collator = null;
  1493. $_api_encoding = null;
  1494. // A string comparison function that serves sorting functions, for internal use.
  1495. function _api_cmp($string1, $string2) {
  1496. global $_api_collator, $_api_encoding;
  1497. $result = collator_compare($_api_collator, api_utf8_encode($string1, $_api_encoding), api_utf8_encode($string2, $_api_encoding));
  1498. return $result === false ? 0 : $result;
  1499. }
  1500. // A reverse string comparison function that serves sorting functions, for internal use.
  1501. function _api_rcmp($string1, $string2) {
  1502. global $_api_collator, $_api_encoding;
  1503. $result = collator_compare($_api_collator, api_utf8_encode($string2, $_api_encoding), api_utf8_encode($string1, $_api_encoding));
  1504. return $result === false ? 0 : $result;
  1505. }
  1506. // A case-insensitive string comparison function that serves sorting functions, for internal use.
  1507. function _api_casecmp($string1, $string2) {
  1508. global $_api_collator, $_api_encoding;
  1509. $result = collator_compare($_api_collator, api_strtolower(api_utf8_encode($string1, $_api_encoding), 'UTF-8'), api_strtolower(api_utf8_encode($string2, $_api_encoding), 'UTF-8'));
  1510. return $result === false ? 0 : $result;
  1511. }
  1512. // A reverse case-insensitive string comparison function that serves sorting functions, for internal use.
  1513. function _api_casercmp($string1, $string2) {
  1514. global $_api_collator, $_api_encoding;
  1515. $result = collator_compare($_api_collator, api_strtolower(api_utf8_encode($string2, $_api_encoding), 'UTF-8'), api_strtolower(api_utf8_encode($string1, $_api_encoding), 'UTF-8'));
  1516. return $result === false ? 0 : $result;
  1517. }
  1518. // A reverse function from strnatcmp(), for internal use.
  1519. function _api_strnatrcmp($string1, $string2) {
  1520. return strnatcmp($string2, $string1);
  1521. }
  1522. // A reverse function from strnatcasecmp(), for internal use.
  1523. function _api_strnatcasercmp($string1, $string2) {
  1524. return strnatcasecmp($string2, $string1);
  1525. }
  1526. // A fuction that translates sorting flag constants from php core to correspondent constants from intl extension, for internal use.
  1527. function _api_get_collator_sort_flag($sort_flag = SORT_REGULAR) {
  1528. switch ($sort_flag) {
  1529. case SORT_STRING:
  1530. case SORT_SORT_LOCALE_STRING:
  1531. return Collator::SORT_STRING;
  1532. case SORT_NUMERIC:
  1533. return Collator::SORT_NUMERIC;
  1534. }
  1535. return Collator::SORT_REGULAR;
  1536. }
  1537. //----------------------------------------------------------------------------
  1538. // Transliteration, converting ANSI and UTF-8 strings to ASCII strings
  1539. //----------------------------------------------------------------------------
  1540. /**
  1541. * Transliterates a string to a plain ASCII string.
  1542. *
  1543. * Example:
  1544. * echo api_transliterate(api_html_entity_decode(
  1545. * '&#1060;&#1105;&#1076;&#1086;&#1088; '.
  1546. * '&#1052;&#1080;&#1093;&#1072;&#1081;&#1083;&#1086;&#1074;&#1080;&#1095; '.
  1547. * '&#1044;&#1086;&#1089;&#1090;&#1086;&#1077;&#1074;&#1082;&#1080;&#1081;',
  1548. * ENT_QUOTES, 'UTF-8'), 'UTF-8');
  1549. * The output should be: Fyodor Mihaylovich Dostoevkiy
  1550. *
  1551. * @param string $string The input string.
  1552. * @param string $unknown (optional) Replacement character for unknown characters and illegal UTF-8 sequences.
  1553. * @param string $from_encoding (optional) The encoding of the input string. If it is omited, the platform character set is assumed.
  1554. * @return string Plain ASCII output.
  1555. *
  1556. * Based on Drupal's module "Transliteration", version 6.x-2.1, 09-JUN-2009:
  1557. * @author Stefan M. Kudwien (smk-ka)
  1558. * @author Daniel F. Kudwien (sun)
  1559. * @link http://drupal.org/project/transliteration
  1560. *
  1561. * See also MediaWiki's UtfNormal.php and CPAN's Text::Unidecode library
  1562. * @link http://www.mediawiki.org
  1563. * @link http://search.cpan.org/~sburke/Text-Unidecode-0.04/lib/Text/Unidecode.pm).
  1564. *
  1565. * Adaptation for the Dokeos 1.8.6.1, 12-JUN-2009:
  1566. * @author Ivan Tcholakov
  1567. */
  1568. function api_transliterate($string, $unknown = '?', $from_encoding = null) {
  1569. static $map = array();
  1570. $string = api_utf8_encode($string, $from_encoding);
  1571. // Screen out some characters that eg won't be allowed in XML.
  1572. $string = preg_replace('/[\x00-\x08\x0b\x0c\x0e-\x1f]/', $unknown, $string);
  1573. // ASCII is always valid NFC!
  1574. // If we're only ever given plain ASCII, we can avoid the overhead
  1575. // of initializing the decomposition tables by skipping out early.
  1576. if (!preg_match('/[\x80-\xff]/', $string)) {
  1577. return $string;
  1578. }
  1579. static $tail_bytes;
  1580. if (!isset($tail_bytes)) {
  1581. // Each UTF-8 head byte is followed by a certain
  1582. // number of tail bytes.
  1583. $tail_bytes = array();
  1584. for ($n = 0; $n < 256; $n++) {
  1585. if ($n < 0xc0) {
  1586. $remaining = 0;
  1587. }
  1588. elseif ($n < 0xe0) {
  1589. $remaining = 1;
  1590. }
  1591. elseif ($n < 0xf0) {
  1592. $remaining = 2;
  1593. }
  1594. elseif ($n < 0xf8) {
  1595. $remaining = 3;
  1596. }
  1597. elseif ($n < 0xfc) {
  1598. $remaining = 4;
  1599. }
  1600. elseif ($n < 0xfe) {
  1601. $remaining = 5;
  1602. } else {
  1603. $remaining = 0;
  1604. }
  1605. $tail_bytes[chr($n)] = $remaining;
  1606. }
  1607. }
  1608. // Chop the text into pure-ASCII and non-ASCII areas;
  1609. // large ASCII parts can be handled much more quickly.
  1610. // Don't chop up Unicode areas for punctuation, though,
  1611. // that wastes energy.
  1612. preg_match_all('/[\x00-\x7f]+|[\x80-\xff][\x00-\x40\x5b-\x5f\x7b-\xff]*/', $string, $matches);
  1613. $result = '';
  1614. foreach ($matches[0] as $str) {
  1615. if ($str{0} < "\x80") {
  1616. // ASCII chunk: guaranteed to be valid UTF-8
  1617. // and in normal form C, so skip over it.
  1618. $result .= $str;
  1619. continue;
  1620. }
  1621. // We'll have to examine the chunk byte by byte to ensure
  1622. // that it consists of valid UTF-8 sequences, and to see
  1623. // if any of them might not be normalized.
  1624. //
  1625. // Since PHP is not the fastest language on earth, some of
  1626. // this code is a little ugly with inner loop optimizations.
  1627. $head = '';
  1628. $chunk = api_byte_count($str);
  1629. // Counting down is faster. I'm *so* sorry.
  1630. $len = $chunk + 1;
  1631. for ($i = -1; --$len; ) {
  1632. $c = $str{++$i};
  1633. if ($remaining = $tail_bytes[$c]) {
  1634. // UTF-8 head byte!
  1635. $sequence = $head = $c;
  1636. do {
  1637. // Look for the defined number of tail bytes...
  1638. if (--$len && ($c = $str{++$i}) >= "\x80" && $c < "\xc0") {
  1639. // Legal tail bytes are nice.
  1640. $sequence .= $c;
  1641. } else {
  1642. if ($len == 0) {
  1643. // Premature end of string!
  1644. // Drop a replacement character into output to
  1645. // represent the invalid UTF-8 sequence.
  1646. $result .= $unknown;
  1647. break 2;
  1648. } else {
  1649. // Illegal tail byte; abandon the sequence.
  1650. $result .= $unknown;
  1651. // Back up and reprocess this byte; it may itself
  1652. // be a legal ASCII or UTF-8 sequence head.
  1653. --$i;
  1654. ++$len;
  1655. continue 2;
  1656. }
  1657. }
  1658. } while (--$remaining);
  1659. $n = ord($head);
  1660. if ($n <= 0xdf) {
  1661. $ord = ($n - 192) * 64 + (ord($sequence{1}) - 128);
  1662. }
  1663. else if ($n <= 0xef) {
  1664. $ord = ($n - 224) * 4096 + (ord($sequence{1}) - 128) * 64 + (ord($sequence{2}) - 128);
  1665. }
  1666. else if ($n <= 0xf7) {
  1667. $ord = ($n - 240) * 262144 + (ord($sequence{1}) - 128) * 4096 + (ord($sequence{2}) - 128) * 64 + (ord($sequence{3}) - 128);
  1668. }
  1669. else if ($n <= 0xfb) {
  1670. $ord = ($n - 248) * 16777216 + (ord($sequence{1}) - 128) * 262144 + (ord($sequence{2}) - 128) * 4096 + (ord($sequence{3}) - 128) * 64 + (ord($sequence{4}) - 128);
  1671. }
  1672. else if ($n <= 0xfd) {
  1673. $ord = ($n - 252) * 1073741824 + (ord($sequence{1}) - 128) * 16777216 + (ord($sequence{2}) - 128) * 262144 + (ord($sequence{3}) - 128) * 4096 + (ord($sequence{4}) - 128) * 64 + (ord($sequence{5}) - 128);
  1674. }
  1675. // Lookup and replace a character from the transliteration database.
  1676. $bank = $ord >> 8;
  1677. // Check if we need to load a new bank
  1678. if (!isset($map[$bank])) {
  1679. if (api_get_path(LIBRARY_PATH) == '/lib/') {
  1680. // Include the bank when we are running the installer script.
  1681. $file = 'transliteration_database/' . sprintf('x%02x', $bank) . '.php';
  1682. } else {
  1683. // Include the bank when the system has been already installed, this is the usual way.
  1684. $file = api_get_path(LIBRARY_PATH).'transliteration_database/' . sprintf('x%02x', $bank) . '.php';
  1685. }
  1686. if (file_exists($file)) {
  1687. $map[$bank] = include ($file);
  1688. } else {
  1689. $map[$bank] = array('en' => array());
  1690. }
  1691. }
  1692. $ord = $ord & 255;
  1693. $result .= isset($map[$bank]['en'][$ord]) ? $map[$bank]['en'][$ord] : $unknown;
  1694. $head = '';
  1695. }
  1696. elseif ($c < "\x80") {
  1697. // ASCII byte.
  1698. $result .= $c;
  1699. $head = '';
  1700. }
  1701. elseif ($c < "\xc0") {
  1702. // Illegal tail bytes.
  1703. if ($head == '') {
  1704. $result .= $unknown;
  1705. }
  1706. } else {
  1707. // Miscellaneous freaks.
  1708. $result .= $unknown;
  1709. $head = '';
  1710. }
  1711. }
  1712. }
  1713. return $result;
  1714. }
  1715. /**
  1716. * ----------------------------------------------------------------------------
  1717. * Encoding management functions
  1718. * ----------------------------------------------------------------------------
  1719. */
  1720. /**
  1721. * Returns the most-probably used non-UTF-8 encoding for the given language.
  1722. * @param string $language (optional) The specified language, the default value is the user intrface language.
  1723. * @return string The correspondent encoding to the specified language.
  1724. */
  1725. function api_get_non_utf8_encoding($language = null) {
  1726. if (empty($language)) {
  1727. $language = api_get_interface_language();
  1728. }
  1729. $language = api_refine_language_id($language);
  1730. $encodings = & api_non_utf8_encodings();
  1731. if (is_array($encodings[$language])) {
  1732. if (!empty($encodings[$language][0])) {
  1733. return $encodings[$language][0];
  1734. } else {
  1735. return 'ISO-8859-15';
  1736. }
  1737. } else {
  1738. return 'ISO-8859-15';
  1739. }
  1740. }
  1741. /**
  1742. * Returns a table with non-UTF-8 encodings for all system languages.
  1743. * @return array Returns an array in the form array('language1' => array('encoding1', encoding2', ...), ...)
  1744. * Note: The function api_get_non_utf8_encoding() returns the first encoding from this array that is correspondent to the given language.
  1745. */
  1746. function & api_non_utf8_encodings() {
  1747. // The following list may have some inconsistencies.
  1748. // Place the most used for your language encoding at the first place.
  1749. // If you are adding an encoding, check whether it is supported either by
  1750. // mbstring library, either by iconv library.
  1751. // If you modify this list, please, follow the given syntax exactly.
  1752. // The language names must be stripped of any suffixes, such as _unicode, _corporate, _org, etc.
  1753. static $encodings =
  1754. '
  1755. arabic: WINDOWS-1256, ISO-8859-6;
  1756. asturian: ISO-8859-15, WINDOWS-1252, ISO-8859-1;
  1757. bosnian: WINDOWS-1250;
  1758. brazilian: ISO-8859-15, WINDOWS-1252, ISO-8859-1;
  1759. bulgarian: WINDOWS-1251;
  1760. catalan: ISO-8859-15, WINDOWS-1252, ISO-8859-1;
  1761. croatian: WINDOWS-1250;
  1762. czech: WINDOWS-1250, ISO-8859-2;
  1763. danish: ISO-8859-15, WINDOWS-1252, ISO-8859-1;
  1764. dari: WINDOWS-1256;
  1765. dutch: ISO-8859-15, WINDOWS-1252, ISO-8859-1;
  1766. english: ISO-8859-15, WINDOWS-1252, ISO-8859-1;
  1767. euskera: ISO-8859-15, WINDOWS-1252, ISO-8859-1;
  1768. esperanto: ISO-8859-15, WINDOWS-1252, ISO-8859-1;
  1769. finnish: ISO-8859-15, WINDOWS-1252, ISO-8859-1;
  1770. french: ISO-8859-15, WINDOWS-1252, ISO-8859-1;
  1771. friulian: ISO-8859-15, WINDOWS-1252, ISO-8859-1;
  1772. galician: ISO-8859-15, WINDOWS-1252, ISO-8859-1;
  1773. georgian: GEORGIAN-ACADEMY, GEORGIAN-PS;
  1774. german: ISO-8859-15, WINDOWS-1252, ISO-8859-1;
  1775. greek: WINDOWS-1253, ISO-8859-7;
  1776. hebrew: ISO-8859-8, WINDOWS-1255;
  1777. hungarian: WINDOWS-1250, ISO-8859-2;
  1778. indonesian: ISO-8859-15, WINDOWS-1252, ISO-8859-1;
  1779. italian: ISO-8859-15, WINDOWS-1252, ISO-8859-1;
  1780. japanese: EUC-JP, ISO-2022-JP, Shift-JIS;
  1781. korean: EUC-KR, ISO-2022-KR, CP949;
  1782. latvian: WINDOWS-1257, ISO-8859-13;
  1783. lithuanian: WINDOWS-1257, ISO-8859-13;
  1784. macedonian: WINDOWS-1251;
  1785. malay: ISO-8859-15, WINDOWS-1252, ISO-8859-1;
  1786. norwegian: ISO-8859-15, WINDOWS-1252, ISO-8859-1;
  1787. occitan: ISO-8859-15, WINDOWS-1252, ISO-8859-1;
  1788. pashto: WINDOWS-1256;
  1789. persian: WINDOWS-1256;
  1790. polish: WINDOWS-1250, ISO-8859-2;
  1791. portuguese: ISO-8859-15, WINDOWS-1252, ISO-8859-1;
  1792. quechua_cusco: ISO-8859-15, WINDOWS-1252, ISO-8859-1;
  1793. romanian: WINDOWS-1250, ISO-8859-2;
  1794. russian: KOI8-R, WINDOWS-1251;
  1795. serbian: ISO-8859-15, WINDOWS-1252, ISO-8859-1, WINDOWS-1251;
  1796. simpl_chinese: GB2312, WINDOWS-936;
  1797. slovak: WINDOWS-1250, ISO-8859-2;
  1798. slovenian: WINDOWS-1250, ISO-8859-2;
  1799. spanish: ISO-8859-15, WINDOWS-1252, ISO-8859-1;
  1800. swahili: ISO-8859-1;
  1801. swedish: ISO-8859-15, WINDOWS-1252, ISO-8859-1;
  1802. thai: WINDOWS-874, ISO-8859-11;
  1803. trad_chinese: BIG-5, EUC-TW;
  1804. turkce: WINDOWS-1254, ISO-8859-9;
  1805. ukrainian: KOI8-U;
  1806. vietnamese: WINDOWS-1258, VISCII, TCVN;
  1807. yoruba: ISO-8859-15, WINDOWS-1252, ISO-8859-1;
  1808. ';
  1809. if (!is_array($encodings)) {
  1810. $table = explode(';', str_replace(' ', '', $encodings));
  1811. $encodings = array();
  1812. foreach ($table as & $row) {
  1813. $row = trim($row);
  1814. if (!empty($row)) {
  1815. $row = explode(':', $row);
  1816. $encodings[$row[0]] = explode(',', strtoupper($row[1]));
  1817. }
  1818. }
  1819. }
  1820. return $encodings;
  1821. }
  1822. /**
  1823. * This function unifies the encoding identificators, so they could be compared.
  1824. * @param string $encoding The specified encoding.
  1825. * @return string Returns the encoding identificator modified in suitable for comparison way.
  1826. */
  1827. function api_refine_encoding_id($encoding) {
  1828. return strtoupper($encoding);
  1829. }
  1830. /**
  1831. * This function checks whether two $encoding are equal (same, equvalent).
  1832. * @param string $encoding1 The first encoding
  1833. * @param string $encoding2 The second encoding
  1834. * @return bool Returns TRUE if the encodings are equal, FALSE otherwise.
  1835. */
  1836. function api_equal_encodings($encoding1, $encoding2) {
  1837. // We have to deal with aliases. This function alone does not solve
  1838. // the problem entirely. And there is no time for this kind of research.
  1839. // At the momemnt, the quick proposition could be:
  1840. return strcmp(api_refine_encoding_id($encoding1), api_refine_encoding_id($encoding2)) == 0 ? true : false;
  1841. }
  1842. /**
  1843. * This function checks whether a given encoding is UTF-8.
  1844. * @param string $encoding The tested encoding.
  1845. * @return bool Returns TRUE if the given encoding id means UTF-8, otherwise returns false.
  1846. */
  1847. function api_is_utf8($encoding) {
  1848. static $result = array();
  1849. if (!isset($result[$encoding])) {
  1850. $result[$encoding] = api_equal_encodings($encoding, 'UTF-8');
  1851. }
  1852. return $result[$encoding];
  1853. }
  1854. /**
  1855. * This function checks whether a given encoding represents (is an alias of) ISO Latin 1 character set.
  1856. * @param string $encoding The tested encoding.
  1857. * @return bool Returns TRUE if the given encoding id means Latin 1 character set, otherwise returns false.
  1858. */
  1859. function api_is_latin1($encoding) {
  1860. static $latin1_encodings = array('ISO-8859-15', 'ISO-8859-1', 'WINDOWS-1252', 'CP1252', 'ISO8859-15', 'ISO8859-1', 'WIN-1252', '1252');
  1861. return in_array(api_refine_encoding_id($encoding), $latin1_encodings);
  1862. }
  1863. /**
  1864. * This function returns the encoding, currently used by the system.
  1865. * @return string The system's encoding.
  1866. * Note: The value of api_get_setting('platform_charset') is tried to be returned first,
  1867. * on the second place the global variable $charset is tried to be returned. If for some
  1868. * reason both attempts fail, 'ISO-8859-15' will be returned.
  1869. */
  1870. function api_get_system_encoding() {
  1871. $system_encoding = api_get_setting('platform_charset');
  1872. if (!empty($system_encoding)) {
  1873. return $system_encoding;
  1874. }
  1875. global $charset;
  1876. return empty($charset) ? 'ISO-8859-15' : $charset;
  1877. }
  1878. /**
  1879. * This function returns the encoding, currently used by the file system.
  1880. * @return string The file system's encoding, it depends on the locale that OS currently uses.
  1881. * @link http://php.net/manual/en/function.setlocale.php
  1882. * Note: For Linux systems, to see all installed locales type in a terminal locale -a
  1883. */
  1884. function api_get_file_system_encoding() {
  1885. static $file_system_encoding;
  1886. if (!isset($file_system_encoding)) {
  1887. $locale = setlocale(LC_CTYPE, '0');
  1888. $seek_pos = strpos($locale, '.');
  1889. if ($seek_pos !== false) {
  1890. $file_system_encoding = substr($locale, $seek_pos + 1);
  1891. if (IS_WINDOWS_OS) {
  1892. $file_system_encoding = 'CP'.$file_system_encoding;
  1893. }
  1894. }
  1895. // Dealing with some aliases.
  1896. $file_system_encoding = str_ireplace('utf8', 'UTF-8', $file_system_encoding);
  1897. $file_system_encoding = preg_replace('/^CP65001$/', 'UTF-8', $file_system_encoding);
  1898. $file_system_encoding = preg_replace('/^CP(125[0-9])$/', 'WINDOWS-\1', $file_system_encoding);
  1899. $file_system_encoding = str_replace('WINDOWS-1252', 'ISO-8859-15', $file_system_encoding);
  1900. if (empty($file_system_encoding)) {
  1901. if (IS_WINDOWS_OS) {
  1902. // Not expected for Windows, this assignment is here just in case.
  1903. $file_system_encoding = api_get_system_encoding();
  1904. } else {
  1905. // For Ububntu and other UTF-8 enabled Linux systems this fits with the default settings.
  1906. $file_system_encoding = 'UTF-8';
  1907. }
  1908. }
  1909. }
  1910. return $file_system_encoding;
  1911. }
  1912. /**
  1913. * Sets all internal default encodings of the multi-byte functions to the given value.
  1914. * @param string $encoding The specified default encoding.
  1915. * @return void
  1916. * Note: This function should be called once the initialization. Please, avoid further manipulation of the internal default encodings.
  1917. */
  1918. function api_set_default_encoding($encoding) {
  1919. api_mb_internal_encoding($encoding);
  1920. api_mb_regex_encoding($encoding);
  1921. api_iconv_set_encoding('iconv_internal_encoding', $encoding);
  1922. }
  1923. /**
  1924. * Sets/Gets internal character encoding of the common string functions within the PHP mbstring extension.
  1925. * @param string $encoding (optional) When this parameter is given, the function sets the internal encoding.
  1926. * @return string When $encoding parameter is not given, the function returns the internal encoding.
  1927. * Note: This function is used in the global initialization script for setting the internal encoding to the platform's character set.
  1928. * @link http://php.net/manual/en/function.mb-internal-encoding
  1929. */
  1930. function api_mb_internal_encoding($encoding = null) {
  1931. static $mb_internal_encoding = null;
  1932. if (empty($encoding)) {
  1933. if (is_null($mb_internal_encoding)) {
  1934. $mb_internal_encoding = @mb_internal_encoding();
  1935. }
  1936. return $mb_internal_encoding;
  1937. }
  1938. $mb_internal_encoding = $encoding;
  1939. if (api_mb_supports($encoding)) {
  1940. return @mb_internal_encoding($encoding);
  1941. }
  1942. return false;
  1943. }
  1944. /**
  1945. * Sets/Gets internal character encoding of the regular expression functions (ereg-like) within the PHP mbstring extension.
  1946. * @param string $encoding (optional) When this parameter is given, the function sets the internal encoding.
  1947. * @return string When $encoding parameter is not given, the function returns the internal encoding.
  1948. * Note: This function is used in the global initialization script for setting the internal encoding to the platform's character set.
  1949. * @link http://php.net/manual/en/function.mb-regex-encoding
  1950. */
  1951. function api_mb_regex_encoding($encoding = null) {
  1952. static $mb_regex_encoding = null;
  1953. if (empty($encoding)) {
  1954. if (is_null($mb_regex_encoding)) {
  1955. $mb_regex_encoding = @mb_regex_encoding();
  1956. }
  1957. return $mb_regex_encoding;
  1958. }
  1959. $mb_regex_encoding = $encoding;
  1960. if (api_mb_supports($encoding)) {
  1961. return @mb_regex_encoding($encoding);
  1962. }
  1963. return false;
  1964. }
  1965. /**
  1966. * Retrieves specified internal encoding configuration variable within the PHP iconv extension.
  1967. * @param string $type The parameter $type could be: 'iconv_internal_encoding', 'iconv_input_encoding', or 'iconv_output_encoding'.
  1968. * @return mixed The function returns the requested encoding or FALSE on error.
  1969. * @link http://php.net/manual/en/function.iconv-get-encoding
  1970. */
  1971. function api_iconv_get_encoding($type) {
  1972. return api_iconv_set_encoding($type);
  1973. }
  1974. /**
  1975. * Sets specified internal encoding configuration variables within the PHP iconv extension.
  1976. * @param string $type The parameter $type could be: 'iconv_internal_encoding', 'iconv_input_encoding', or 'iconv_output_encoding'.
  1977. * @param string $encoding (optional) The desired encoding to be set.
  1978. * @return bool Returns TRUE on success, FALSE on error.
  1979. * Note: This function is used in the global initialization script for setting these three internal encodings to the platform's character set.
  1980. * @link http://php.net/manual/en/function.iconv-set-encoding
  1981. */
  1982. // Sets current setting for character encoding conversion.
  1983. // The parameter $type could be: 'iconv_internal_encoding', 'iconv_input_encoding', or 'iconv_output_encoding'.
  1984. function api_iconv_set_encoding($type, $encoding = null) {
  1985. static $iconv_internal_encoding = null;
  1986. static $iconv_input_encoding = null;
  1987. static $iconv_output_encoding = null;
  1988. if (!ICONV_INSTALLED) {
  1989. return false;
  1990. }
  1991. switch ($type) {
  1992. case 'iconv_internal_encoding':
  1993. if (empty($encoding)) {
  1994. if (is_null($iconv_internal_encoding)) {
  1995. $iconv_internal_encoding = @iconv_get_encoding($type);
  1996. }
  1997. return $iconv_internal_encoding;
  1998. }
  1999. if (api_iconv_supports($encoding)) {
  2000. if(@iconv_set_encoding($type, $encoding)) {
  2001. $iconv_internal_encoding = $encoding;
  2002. return true;
  2003. } else {
  2004. return false;
  2005. }
  2006. } else {
  2007. return false;
  2008. }
  2009. break;
  2010. case 'iconv_input_encoding':
  2011. if (empty($encoding)) {
  2012. if (is_null($iconv_input_encoding)) {
  2013. $iconv_input_encoding = @iconv_get_encoding($type);
  2014. }
  2015. return $iconv_input_encoding;
  2016. }
  2017. if (api_iconv_supports($encoding)) {
  2018. if(@iconv_set_encoding($type, $encoding)) {
  2019. $iconv_input_encoding = $encoding;
  2020. return true;
  2021. } else {
  2022. return false;
  2023. }
  2024. } else {
  2025. return false;
  2026. }
  2027. break;
  2028. case 'iconv_output_encoding':
  2029. if (empty($encoding)) {
  2030. if (is_null($iconv_output_encoding)) {
  2031. $iconv_output_encoding = @iconv_get_encoding($type);
  2032. }
  2033. return $iconv_output_encoding;
  2034. }
  2035. if (api_iconv_supports($encoding)) {
  2036. if(@iconv_set_encoding($type, $encoding)) {
  2037. $iconv_output_encoding = $encoding;
  2038. return true;
  2039. } else {
  2040. return false;
  2041. }
  2042. } else {
  2043. return false;
  2044. }
  2045. break;
  2046. default:
  2047. return false;
  2048. }
  2049. }
  2050. /**
  2051. * Checks whether a specified encoding is supported by this API.
  2052. * @param string $encoding The specified encoding.
  2053. * @return bool Returns TRUE when the specified encoding is supported, FALSE othewise.
  2054. */
  2055. function api_is_encoding_supported($encoding) {
  2056. return api_mb_supports($encoding) || api_iconv_supports($encoding);
  2057. }
  2058. /**
  2059. * Checks whether the specified encoding is supported by the PHP mbstring extension.
  2060. * @param string $encoding The specified encoding.
  2061. * @return bool Returns TRUE when the specified encoding is supported, FALSE othewise.
  2062. */
  2063. function api_mb_supports($encoding) {
  2064. static $supported = array();
  2065. $encoding = api_refine_encoding_id($encoding);
  2066. if (!isset($supported[$encoding])) {
  2067. $mb_encodings = mb_list_encodings();
  2068. $mb_encodings = array_map('api_refine_encoding_id', $mb_encodings);
  2069. $supported[$encoding] = in_array($encoding, $mb_encodings);
  2070. }
  2071. return $supported[$encoding] ? true : false;
  2072. }
  2073. /**
  2074. * Checks whether the specified encoding is supported by the PHP iconv extension.
  2075. * @param string $encoding The specified encoding.
  2076. * @return bool Returns TRUE when the specified encoding is supported, FALSE othewise.
  2077. */
  2078. function api_iconv_supports($encoding) {
  2079. static $supported = array();
  2080. $encoding = api_refine_encoding_id($encoding);
  2081. if (!isset($supported[$encoding])) {
  2082. if (ICONV_INSTALLED) {
  2083. $test_string = '';
  2084. for ($i = 32; $i < 128; $i++) {
  2085. $test_string .= chr($i);
  2086. }
  2087. $supported[$encoding] = (@iconv_strlen($test_string, $encoding)) ? true : false;
  2088. } else {
  2089. $supported[$encoding] = false;
  2090. }
  2091. }
  2092. return $supported[$encoding];
  2093. }
  2094. /**
  2095. * Checks whether the specified encoding is supported by the html-entitiy related functions.
  2096. * @param string $encoding The specified encoding.
  2097. * @return bool Returns TRUE when the specified encoding is supported, FALSE othewise.
  2098. */
  2099. function api_html_entity_supports($encoding) {
  2100. static $supported = array();
  2101. $encoding = api_refine_encoding_id($encoding);
  2102. if (!isset($supported[$encoding])) {
  2103. // See http://php.net/manual/en/function.htmlentities.php
  2104. $html_entity_encodings = array(explode(',',
  2105. '
  2106. ISO-8859-1, ISO8859-1,
  2107. ISO-8859-15, ISO8859-15,
  2108. UTF-8,
  2109. cp866, ibm866, 866,
  2110. cp1251, Windows-1251, win-1251, 1251,
  2111. cp1252, Windows-1252, 1252,
  2112. KOI8-R, koi8-ru, koi8r,
  2113. BIG5, 950,
  2114. GB2312, 936,
  2115. BIG5-HKSCS,
  2116. Shift_JIS, SJIS, 932,
  2117. EUC-JP, EUCJP
  2118. '));
  2119. $html_entity_encodings = array_map('trim', $html_entity_encodings);
  2120. $html_entity_encodings = array_map('api_refine_encoding_id', $html_entity_encodings);
  2121. $supported[$encoding] = in_array($encoding, $html_entity_encodings);
  2122. }
  2123. return $supported[$encoding] ? true : false;
  2124. }
  2125. /**
  2126. * ----------------------------------------------------------------------------
  2127. * String validation functions concerning some encodings
  2128. * ----------------------------------------------------------------------------
  2129. */
  2130. /**
  2131. * Checks a string for UTF-8 validity.
  2132. * @param string $string The string to be tested/validated.
  2133. * @return bool Returns TRUE when the tested string is valid UTF-8 one, FALSE othewise.
  2134. * @link http://en.wikipedia.org/wiki/UTF-8
  2135. */
  2136. function api_is_valid_utf8($string) {
  2137. //return @mb_detect_encoding($string, 'UTF-8', true) == 'UTF-8' ? true : false;
  2138. // Ivan Tcholakov, 05-OCT-2008: I do not trust mb_detect_encoding(). I have
  2139. // found a string with a single cyrillic letter (single byte), that is
  2140. // wrongly detected as UTF-8. Possibly, there would be problems with other
  2141. // languages too. An alternative implementation will be used.
  2142. //$len = strlen($string); // mbstring.func_overload might change behaviour of the function strlen().
  2143. // Ivan Tcholakov, 11-JUN-2009: Let us calculate for sure the length in bytes.
  2144. static $use_mb_strlen;
  2145. if (!isset($use_mb_strlen)) {
  2146. $use_mb_strlen = MBSTRING_INSTALLED && ((int) ini_get('mbstring.func_overload') & 2);
  2147. }
  2148. if ($use_mb_strlen) {
  2149. $len = mb_strlen($string, '8bit');
  2150. } else {
  2151. $len = strlen($string);
  2152. }
  2153. // For PHP6 all this fragment probably will contain:
  2154. //$len = strlen((binary)$string);
  2155. $i = 0;
  2156. while ($i < $len) {
  2157. $byte1 = ord($string[$i++]); // Here the current character begins. Its size is
  2158. // determined by the senior bits in the first byte.
  2159. if (($byte1 & 0x80) == 0x00) { // 0xxxxxxx
  2160. // &
  2161. // 10000000
  2162. // --------
  2163. // 00000000
  2164. // This is s valid character and it contains a single byte.
  2165. }
  2166. elseif (($byte1 & 0xE0) == 0xC0) { // 110xxxxx 10xxxxxx
  2167. // & &
  2168. // 11100000 11000000
  2169. // -------- --------
  2170. // 11000000 10000000
  2171. // The character contains two bytes.
  2172. if ($i == $len)
  2173. return false; // Here the string ends unexpectedly.
  2174. if (!((ord($string[$i++]) & 0xC0) == 0x80))
  2175. return false; // Invalid second byte, invalid string.
  2176. }
  2177. elseif(($byte1 & 0xF0) == 0xE0) { // 1110xxxx 10xxxxxx 10xxxxxx
  2178. // & & &
  2179. // 11110000 11000000 11000000
  2180. // -------- -------- --------
  2181. // 11100000 10000000 10000000
  2182. // This is a character of three bytes.
  2183. if ($i == $len) {
  2184. return false; // Unexpected end of the string.
  2185. }
  2186. if (!((ord($string[$i++]) & 0xC0) == 0x80)) {
  2187. return false; // Invalid second byte.
  2188. }
  2189. if ($i == $len) {
  2190. return false; // Unexpected end of the string.
  2191. }
  2192. if (!((ord($string[$i++]) & 0xC0) == 0x80)) {
  2193. return false; // Invalid third byte, invalid string.
  2194. }
  2195. }
  2196. elseif(($byte1 & 0xF8) == 0xF0) { // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
  2197. // & & & &
  2198. // 11111000 11000000 11000000 11000000
  2199. // -------- -------- -------- --------
  2200. // 11110000 10000000 10000000 10000000
  2201. // This is a character of four bytes.
  2202. if ($i == $len) {
  2203. return false;
  2204. }
  2205. if (!((ord($string[$i++]) & 0xC0) == 0x80)) {
  2206. return false;
  2207. }
  2208. if ($i == $len) {
  2209. return false;
  2210. }
  2211. if (!((ord($string[$i++]) & 0xC0) == 0x80)) {
  2212. return false;
  2213. }
  2214. if ($i == $len) {
  2215. return false;
  2216. }
  2217. if (!((ord($string[$i++]) & 0xC0) == 0x80)) {
  2218. return false;
  2219. }
  2220. }
  2221. elseif(($byte1 & 0xFC) == 0xF8) { // 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
  2222. // & & & & &
  2223. // 11111100 11000000 11000000 11000000 11000000
  2224. // -------- -------- -------- -------- --------
  2225. // 11111000 10000000 10000000 10000000 10000000
  2226. // This is a character of five bytes.
  2227. if ($i == $len) {
  2228. return false;
  2229. }
  2230. if (!((ord($string[$i++]) & 0xC0) == 0x80)) {
  2231. return false;
  2232. }
  2233. if ($i == $len) {
  2234. return false;
  2235. }
  2236. if (!((ord($string[$i++]) & 0xC0) == 0x80)) {
  2237. return false;
  2238. }
  2239. if ($i == $len) {
  2240. return false;
  2241. }
  2242. if (!((ord($string[$i++]) & 0xC0) == 0x80)) {
  2243. return false;
  2244. }
  2245. if ($i == $len) {
  2246. return false;
  2247. }
  2248. if (!((ord($string[$i++]) & 0xC0) == 0x80)) {
  2249. return false;
  2250. }
  2251. }
  2252. elseif(($byte1 & 0xFE) == 0xFC) { // 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
  2253. // & & & & & &
  2254. // 11111110 11000000 11000000 11000000 11000000 11000000
  2255. // -------- -------- -------- -------- -------- --------
  2256. // 11111100 10000000 10000000 10000000 10000000 10000000
  2257. // This is a character of six bytes.
  2258. if ($i == $len) {
  2259. return false;
  2260. }
  2261. if (!((ord($string[$i++]) & 0xC0) == 0x80)) {
  2262. return false;
  2263. }
  2264. if ($i == $len) {
  2265. return false;
  2266. }
  2267. if (!((ord($string[$i++]) & 0xC0) == 0x80)) {
  2268. return false;
  2269. }
  2270. if ($i == $len) {
  2271. return false;
  2272. }
  2273. if (!((ord($string[$i++]) & 0xC0) == 0x80)) {
  2274. return false;
  2275. }
  2276. if ($i == $len) {
  2277. return false;
  2278. }
  2279. if (!((ord($string[$i++]) & 0xC0) == 0x80)) {
  2280. return false;
  2281. }
  2282. if ($i == $len) {
  2283. return false;
  2284. }
  2285. if (!((ord($string[$i++]) & 0xC0) == 0x80)) {
  2286. return false;
  2287. }
  2288. }
  2289. else {
  2290. return false; // In any other case the character is invalid.
  2291. }
  2292. // Here the current character is valid, it
  2293. // matches to some of the cases above.
  2294. // The next character is to be examinated.
  2295. }
  2296. return true; // Empty strings are valid too.
  2297. }
  2298. /**
  2299. * Checks whether a string contains 7-bit ASCII characters only.
  2300. * @param string $string The string to be tested/validated.
  2301. * @return bool Returns TRUE when the tested string contains 7-bit ASCII characters only, FALSE othewise.
  2302. */
  2303. function api_is_valid_ascii($string) {
  2304. return @mb_detect_encoding($string, 'ASCII', true) == 'ASCII' ? true : false;
  2305. }
  2306. /**
  2307. * ----------------------------------------------------------------------------
  2308. * Language management functions
  2309. * ----------------------------------------------------------------------------
  2310. */
  2311. /**
  2312. * Returns a purified language id, without possible suffixes that will disturb language identification in certain cases.
  2313. * @param string $language The input language identificator, for example 'french_unicode'.
  2314. * @param string The same purified or filtered language identificator, for example 'french'.
  2315. */
  2316. function api_refine_language_id($language) {
  2317. static $search = array('_unicode', '_latin', '_corporate', '_org', '_KM');
  2318. return strtolower(str_replace($search, '', $language));
  2319. }
  2320. /**
  2321. * This function check whether a given language can use Latin 1 encoding.
  2322. * @param string $language The checked language.
  2323. * @return bool TRUE if the given language can use Latin 1 encoding (ISO-8859-15, ISO-8859-1, WINDOWS-1252, ...), FALSE otherwise.
  2324. */
  2325. function api_is_latin1_compatible($language) {
  2326. static $latin1_languages;
  2327. if (!isset($latin1_languages)) {
  2328. $latin1_languages = api_get_latin1_compatible_languages();
  2329. }
  2330. $language = api_refine_language_id($language);
  2331. return in_array($language, $latin1_languages);
  2332. }
  2333. /**
  2334. * This function returns an array of those languages that can use Latin 1 encoding.
  2335. * @return array The array of languages that can use Latin 1 encoding (ISO-8859-15, ISO-8859-1, WINDOWS-1252, ...).
  2336. * Note: The returned language identificators are purified, without suffixes.
  2337. */
  2338. function api_get_latin1_compatible_languages() {
  2339. static $latin1_languages;
  2340. if (!isset($latin1_languages)) {
  2341. $latin1_languages = array();
  2342. $encodings = & api_non_utf8_encodings();
  2343. foreach ($encodings as $key => $value) {
  2344. if (api_is_latin1($value[0])) {
  2345. $latin1_languages[] = $key;
  2346. }
  2347. }
  2348. }
  2349. return $latin1_languages;
  2350. }
  2351. /**
  2352. * ----------------------------------------------------------------------------
  2353. * ICU locales (accessible through intl extension).
  2354. * ----------------------------------------------------------------------------
  2355. */
  2356. /**
  2357. * Returns isocode (see api_get_language_isocode()) which is purified accordingly to
  2358. * be used by the php intl extension (ICU library).
  2359. * @param string $language (optional) This is the name of the folder containing translations for the corresponding language.
  2360. * If $language is omitted, interface language is assumed then.
  2361. * @return string The found language locale id or null on error. Examples: bg, en, pt_BR, ...
  2362. */
  2363. function api_get_locale_from_language($language = null) {
  2364. static $locale = array();
  2365. if (!isset($locale[$language])) {
  2366. $locale[$language] = Database::get_language_isocode($language);
  2367. if (!is_null($locale[$language])) {
  2368. $locale[$language] = str_replace('-', '_', $locale[$language]);
  2369. }
  2370. }
  2371. return $locale[$language];
  2372. }
  2373. /**
  2374. * Sets/gets the default internal value of the locale id (for the intl extension, ICU).
  2375. * @param string $locale (optional) The locale id to be set. When it is omitted, the function returns (gets, reads) the default internal value.
  2376. * @return mixed When the function sets the default value, it returns TRUE on success or FALSE on error. Otherwise the function returns as string the current default value.
  2377. */
  2378. function api_set_default_locale($locale = null) {
  2379. static $default_locale = 'en';
  2380. if (!empty($language)) {
  2381. $default_locale = $locale;
  2382. if (INTL_INSTALLED) {
  2383. return @locale_set_default($locale);
  2384. }
  2385. return true;
  2386. } else {
  2387. if (INTL_INSTALLED) {
  2388. $default_locale = @locale_get_default();
  2389. }
  2390. }
  2391. return $default_locale;
  2392. }
  2393. /**
  2394. * Gets the default internal value of the locale id (for the intl extension, ICU).
  2395. * @return string Returns as string the current default value.
  2396. */
  2397. function api_get_default_locale() {
  2398. return api_set_default_locale();
  2399. }
  2400. //----------------------------------------------------------------------------
  2401. // Multibyte string functions designed to upgrade the PHP5 mbstring extension
  2402. //----------------------------------------------------------------------------
  2403. // ---------- Multibyte string functions implemented in PHP 5.2.0+ -----------
  2404. // This is a multibyte replacement of strchr().
  2405. // This function exists in PHP 5 >= 5.2.0
  2406. // See http://php.net/manual/en/function.mb-strrchr
  2407. if (MBSTRING_INSTALLED && !function_exists('mb_strchr')) {
  2408. function mb_strchr($haystack, $needle, $part = false, $encoding = null) {
  2409. if (empty($encoding)) {
  2410. $encoding = mb_internal_encoding();
  2411. }
  2412. return mb_strstr($haystack, $needle, $part, $encoding);
  2413. }
  2414. }
  2415. // This is a multibyte replacement of stripos().
  2416. // This function exists in PHP 5 >= 5.2.0
  2417. // See http://php.net/manual/en/function.mb-stripos
  2418. if (MBSTRING_INSTALLED && !function_exists('mb_stripos')) {
  2419. function mb_stripos($haystack, $needle, $offset = 0, $encoding = null) {
  2420. if (empty($encoding)) {
  2421. $encoding = mb_internal_encoding();
  2422. }
  2423. return mb_strpos(mb_strtolower($haystack, $encoding), mb_strtolower($needle, $encoding), $offset, $encoding);
  2424. }
  2425. }
  2426. // This is a multibyte replacement of stristr().
  2427. // This function exists in PHP 5 >= 5.2.0
  2428. // See http://php.net/manual/en/function.mb-stristr
  2429. if (MBSTRING_INSTALLED && !function_exists('mb_stristr')) {
  2430. function mb_stristr($haystack, $needle, $part = false, $encoding = null) {
  2431. if (empty($encoding)) {
  2432. $encoding = mb_internal_encoding();
  2433. }
  2434. $pos = mb_strpos(mb_strtolower($haystack, $encoding), mb_strtolower($needle, $encoding), 0, $encoding);
  2435. if ($pos === false) {
  2436. return false;
  2437. }
  2438. elseif($part == true) {
  2439. return mb_substr($haystack, 0, $pos + 1, $encoding);
  2440. } else {
  2441. return mb_substr($haystack, $pos, mb_strlen($haystack, $encoding), $encoding);
  2442. }
  2443. }
  2444. }
  2445. // This is a multibyte replacement of strrchr().
  2446. // This function exists in PHP 5 >= 5.2.0
  2447. // See http://php.net/manual/en/function.mb-strrchr
  2448. if (MBSTRING_INSTALLED && !function_exists('mb_strrchr')) {
  2449. function mb_strrchr($haystack, $needle, $part = false, $encoding = null) {
  2450. if (empty($encoding)) {
  2451. $encoding = mb_internal_encoding();
  2452. }
  2453. $needle = mb_substr($needle, 0, 1, $encoding);
  2454. $pos = mb_strrpos($haystack, $needle, mb_strlen($haystack, $encoding) - 1, $encoding);
  2455. if ($pos === false) {
  2456. return false;
  2457. } elseif($part == true) {
  2458. return mb_substr($haystack, 0, $pos + 1, $encoding);
  2459. } else {
  2460. return mb_substr($haystack, $pos, mb_strlen($haystack, $encoding), $encoding);
  2461. }
  2462. }
  2463. }
  2464. // This is a multibyte replacement of strstr().
  2465. // This function exists in PHP 5 >= 5.2.0
  2466. // See http://php.net/manual/en/function.mb-strstr
  2467. if (MBSTRING_INSTALLED && !function_exists('mb_strstr')) {
  2468. function mb_strstr($haystack, $needle, $part = false, $encoding = null) {
  2469. if (empty($encoding)) {
  2470. $encoding = mb_internal_encoding();
  2471. }
  2472. $pos = mb_strpos($haystack, $needle, 0, $encoding);
  2473. if ($pos === false) {
  2474. return false;
  2475. } elseif($part == true) {
  2476. return mb_substr($haystack, 0, $pos + 1, $encoding);
  2477. } else {
  2478. return mb_substr($haystack, $pos, mb_strlen($haystack, $encoding), $encoding);
  2479. }
  2480. }
  2481. }
  2482. ?>