multibyte_string_functions.lib.php 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365
  1. <?php
  2. // File: multibyte_string_functions.lib.php
  3. // Main API extension for Dokeos 1.8.6 LMS
  4. // A common purpose library for supporting multibyte string aware functions.
  5. // This library requires PHP mbstring extension to be activated.
  6. // When encodings to be used are not supported by mbstring, this library
  7. // is able to exploit the PHP iconv extesion, which in this case should
  8. // activated too.
  9. // License: GNU/GPL version 2 or later (Free Software Foundation)
  10. // Author: Ivan Tcholakov, ivantcholakov@gmail.com
  11. // October 2008.
  12. // May 2009 - refactoring and minor fixes have been implemented.
  13. //----------------------------------------------------------------------------
  14. // Multibyte string conversion functions
  15. //----------------------------------------------------------------------------
  16. // Converts character encoding of a given string.
  17. // See http://php.net/manual/en/function.mb-convert-encoding
  18. function api_convert_encoding($string, $to_encoding, $from_encoding) {
  19. if (api_equal_encodings($to_encoding, $from_encoding)) {
  20. return $string;
  21. }
  22. if (api_mb_supports($to_encoding) && api_mb_supports($from_encoding)) {
  23. return @mb_convert_encoding($string, $to_encoding, $from_encoding);
  24. }
  25. elseif (api_iconv_supports($to_encoding) && api_iconv_supports($from_encoding)) {
  26. return @iconv($from_encoding, $to_encoding, $string);
  27. }
  28. return $string;
  29. }
  30. // Converts a given string into UTF-8 encoded string.
  31. // See http://php.net/manual/en/function.utf8-encode
  32. function api_utf8_encode($string, $from_encoding = null) {
  33. if (empty($from_encoding)) {
  34. $from_encoding = api_mb_internal_encoding();
  35. }
  36. if (api_is_utf8($from_encoding)) {
  37. return $string;
  38. }
  39. if (api_mb_supports($from_encoding)) {
  40. return @mb_convert_encoding($string, 'UTF-8', $from_encoding);
  41. }
  42. elseif (api_iconv_supports($from_encoding)) {
  43. return @iconv($from_encoding, 'UTF-8', $string);
  44. }
  45. return $string;
  46. }
  47. // Converts a given string, from UTF-8 encoding to a specified encoding.
  48. // See http://php.net/manual/en/function.utf8-decode
  49. function api_utf8_decode($string, $to_encoding = null) {
  50. if (empty($to_encoding)) {
  51. $to_encoding = api_mb_internal_encoding();
  52. }
  53. if (api_is_utf8($to_encoding)){
  54. return $string;
  55. }
  56. if (api_mb_supports($to_encoding)) {
  57. return @mb_convert_encoding($string, $to_encoding, 'UTF-8');
  58. }
  59. elseif (api_iconv_supports($to_encoding)) {
  60. return @iconv('UTF-8', $to_encoding, $string);
  61. }
  62. return $string;
  63. }
  64. // Encodes a given string into the system ecoding if this conversion has been detected as necessary.
  65. function api_to_system_encoding($string, $from_encoding = null, $check_utf8_validity = false) {
  66. $charset = api_get_system_encoding();
  67. if (empty($from_encoding)) {
  68. if (api_is_utf8($charset)) {
  69. $from_encoding = api_get_non_utf8_encoding();
  70. } else {
  71. $from_encoding = 'UTF-8';
  72. }
  73. }
  74. if (api_equal_encodings($charset, $from_encoding)) {
  75. return $string;
  76. }
  77. if ($check_utf8_validity) {
  78. if (api_is_utf8($charset)) {
  79. if (api_is_valid_utf8($string)) {
  80. return $string;
  81. }
  82. }
  83. elseif (api_is_utf8($from_encoding)) {
  84. if (!api_is_valid_utf8($string)) {
  85. return $string;
  86. }
  87. }
  88. }
  89. return api_convert_encoding($string, $charset, $from_encoding);
  90. }
  91. // Converts all applicable characters to HTML entities.
  92. // See http://php.net/manual/en/function.htmlentities
  93. function api_htmlentities($string, $quote_style = ENT_COMPAT, $encoding = 'ISO-8859-15') {
  94. if (!api_is_utf8($encoding) && api_html_entity_supports($encoding)) {
  95. return htmlentities($string, $quote_style, $encoding);
  96. }
  97. if (!api_is_encoding_supported($encoding)) {
  98. return $string;
  99. }
  100. $string = api_convert_encoding(api_utf8_encode($string, $encoding), 'HTML-ENTITIES', 'UTF-8');
  101. switch($quote_style) {
  102. case ENT_COMPAT:
  103. $string = str_replace("'", '&quot;', $string);
  104. break;
  105. case ENT_QUOTES:
  106. $string = str_replace("'", '&#039;', str_replace('"', '&quot;', $string));
  107. break;
  108. }
  109. return $string;
  110. }
  111. // Decodes HTML entities into normal characters.
  112. // See http://php.net/html_entity_decode
  113. function api_html_entity_decode($string, $quote_style = ENT_COMPAT, $encoding = 'ISO-8859-15') {
  114. if (!api_is_utf8($encoding) && api_html_entity_supports($encoding)) {
  115. return html_entity_decode($string, $quote_style, $encoding);
  116. }
  117. if (!api_is_encoding_supported($encoding)) {
  118. return $string;
  119. }
  120. return api_utf8_decode(html_entity_decode(api_convert_encoding($string, 'UTF-8', $encoding), $quote_style, 'UTF-8'), $encoding);
  121. }
  122. //----------------------------------------------------------------------------
  123. // Common multibyte string functions
  124. //----------------------------------------------------------------------------
  125. // Regular expression match with multibyte support.
  126. // See http://php.net/manual/en/function.mb-ereg
  127. function api_ereg($pattern, $string, & $regs = null) {
  128. $count = func_num_args();
  129. $encoding = api_mb_regex_encoding();
  130. if (api_mb_supports($encoding)) {
  131. if ($count < 3) {
  132. return @mb_ereg($pattern, $string);
  133. } else {
  134. $result = @mb_ereg($pattern, $string, $regs);
  135. return $result;
  136. }
  137. }
  138. elseif (api_iconv_supports($encoding)) {
  139. api_mb_regex_encoding('UTF-8');
  140. if ($count < 3) {
  141. $result = @mb_ereg(api_utf8_encode($pattern, $encoding), api_utf8_encode($string, $encoding));
  142. } else {
  143. $result = @mb_ereg(api_utf8_encode($pattern, $encoding), api_utf8_encode($string, $encoding), $regs);
  144. $regs = api_array_utf8_decode($regs, $encoding);
  145. }
  146. api_mb_regex_encoding($encoding);
  147. return $result;
  148. } else {
  149. if ($count < 3) {
  150. return ereg($pattern, $string);
  151. } else {
  152. return ereg($pattern, $string, $regs);
  153. }
  154. }
  155. }
  156. // Replace regular expression with multibyte support.
  157. // See http://php.net/manual/en/function.mb-ereg-replace
  158. function api_ereg_replace($pattern, $replacement, $string, $option = null) {
  159. $encoding = api_mb_regex_encoding();
  160. if (api_mb_supports($encoding)) {
  161. if (is_null($option)) {
  162. return @mb_ereg_replace($pattern, $replacement, $string);
  163. } else {
  164. return @mb_ereg_replace($pattern, $replacement, $string, $option);
  165. }
  166. }
  167. elseif (api_iconv_supports($encoding)) {
  168. api_mb_regex_encoding('UTF-8');
  169. if (is_null($option)) {
  170. $result = api_utf8_decode(@mb_ereg_replace(api_utf8_encode($pattern, $encoding), api_utf8_encode($replacement, $encoding), api_utf8_encode($string, $encoding)), $encoding);
  171. } else {
  172. $result = api_utf8_decode(@mb_ereg_replace(api_utf8_encode($pattern, $encoding), api_utf8_encode($replacement, $encoding), api_utf8_encode($string, $encoding), $option), $encoding);
  173. }
  174. api_mb_regex_encoding($encoding);
  175. return $result;
  176. } else {
  177. return ereg_replace($pattern, $replacement, $string);
  178. }
  179. }
  180. // This is a helper callback function for internal purposes.
  181. function api_array_utf8_decode($variable, $encoding) {
  182. if (is_array($variable)) {
  183. return array_map('api_array_utf8_decode', $variable, $encoding);
  184. }
  185. if (is_string($var)) {
  186. return api_utf8_decode($variable, $encoding);
  187. }
  188. return $variable;
  189. }
  190. // Regular expression match ignoring case with multibyte support.
  191. // See http://php.net/manual/en/function.mb-eregi
  192. function api_eregi($pattern, $string, & $regs = null) {
  193. $count = func_num_args();
  194. $encoding = api_mb_regex_encoding();
  195. if (api_mb_supports($encoding)) {
  196. if ($count < 3) {
  197. return @mb_eregi($pattern, $string);
  198. } else {
  199. return @mb_eregi($pattern, $string, $regs);
  200. }
  201. }
  202. elseif (api_iconv_supports($encoding)) {
  203. api_mb_regex_encoding('UTF-8');
  204. if ($count < 3) {
  205. $result = @mb_eregi(api_utf8_encode($pattern, $encoding), api_utf8_encode($string, $encoding));
  206. } else {
  207. $result = @mb_eregi(api_utf8_encode($pattern, $encoding), api_utf8_encode($string, $encoding), $regs);
  208. $regs = api_array_utf8_decode($regs, $encoding);
  209. }
  210. api_mb_regex_encoding($encoding);
  211. return $result;
  212. } else {
  213. if ($count < 3) {
  214. return eregi($pattern, $string);
  215. } else {
  216. return eregi($pattern, $string, $regs);
  217. }
  218. }
  219. }
  220. // Replace regular expression with multibyte support ignoring case.
  221. // See http://php.net/manual/en/function.mb-eregi-replace
  222. function api_eregi_replace($pattern, $replacement, $string, $option = null) {
  223. $encoding = api_mb_regex_encoding();
  224. if (api_mb_supports($encoding)) {
  225. if (is_null($option)) {
  226. return @mb_eregi_replace($pattern, $replacement, $string);
  227. } else {
  228. return @mb_eregi_replace($pattern, $replacement, $string, $option);
  229. }
  230. }
  231. elseif (api_iconv_supports($encoding)) {
  232. api_mb_regex_encoding('UTF-8');
  233. if (is_null($option)) {
  234. $result = api_utf8_decode(@mb_eregi_replace(api_utf8_encode($pattern, $encoding), api_utf8_encode($replacement, $encoding), api_utf8_encode($string, $encoding)), $encoding);
  235. } else {
  236. $result = api_utf8_decode(@mb_eregi_replace(api_utf8_encode($pattern, $encoding), api_utf8_encode($replacement, $encoding), api_utf8_encode($string, $encoding), $option), $encoding);
  237. }
  238. api_mb_regex_encoding($encoding);
  239. return $result;
  240. } else {
  241. return eregi_replace($pattern, $replacement, $string);
  242. }
  243. }
  244. // This function returns a selected by position character of a string.
  245. function api_get_character($string, $position, $encoding = null) {
  246. if (empty($encoding)) {
  247. $encoding = api_mb_internal_encoding();
  248. }
  249. return api_substr($string, $position, 1, $encoding);
  250. }
  251. // This function returns an array containing all characters of a string.
  252. function api_get_characters($string, $encoding = null) {
  253. if (empty($encoding)) {
  254. $encoding = api_mb_internal_encoding();
  255. }
  256. return api_str_split($string, 1, $encoding);
  257. }
  258. // Makes a string's first character lowercase.
  259. // See http://php.net/manual/en/function.lcfirst
  260. function api_lcfirst($string, $encoding = null) {
  261. if (empty($encoding)) {
  262. $encoding = api_mb_internal_encoding();
  263. }
  264. return api_strtolower(api_substr($string, 0, 1, $encoding), $encoding) . api_substr($string, 1, api_strlen($string, $encoding), $encoding);
  265. }
  266. // Puts a prefix into a string.
  267. // The input variables could be arrays too.
  268. function api_prefix($string, $prefix) {
  269. if (is_array($string)) {
  270. if (is_array($prefix)) {
  271. return array_map('api_prefix', $string, $prefix);
  272. } else {
  273. return array_map('api_prefix', $string, array_fill(0 , count($string) , $prefix));
  274. }
  275. }
  276. if (is_array($prefix)) {
  277. $prefix = implode('', $prefix);
  278. }
  279. return $prefix.$string;
  280. }
  281. // Splits string into array by regular expression.
  282. // See http://php.net/manual/en/function.mb-split
  283. function api_split($pattern, $string, $limit = null) {
  284. $encoding = api_mb_regex_encoding();
  285. if (api_mb_supports($encoding)) {
  286. if (is_null($limit)) {
  287. return @mb_split($pattern, $string);
  288. } else {
  289. return @mb_split($pattern, $string, $limit);
  290. }
  291. }
  292. elseif (api_iconv_supports($encoding)) {
  293. api_mb_regex_encoding('UTF-8');
  294. if (is_null($limit)) {
  295. $result = @mb_split(api_utf8_encode($pattern, $encoding), api_utf8_encode($string, $encoding));
  296. } else {
  297. $result = @mb_split(api_utf8_encode($pattern, $encoding), api_utf8_encode($string, $encoding), $limit);
  298. }
  299. $result = api_array_utf8_decode($result, $encoding);
  300. api_mb_regex_encoding($encoding);
  301. return $result;
  302. } else {
  303. if (is_null($limit)) {
  304. return split($pattern, $string);
  305. } else {
  306. return split($pattern, $string, $limit);
  307. }
  308. }
  309. }
  310. // This is a multibyte replacement of str_ireplace().
  311. // See http://php.net/manual/en/function.str-ireplace
  312. // TODO: To be revised an to be checked.
  313. function api_str_ireplace($search, $replace, $subject, & $count = null, $encoding = null) {
  314. if (empty($encoding)) {
  315. $encoding = api_mb_internal_encoding();
  316. }
  317. if (is_array($subject)) {
  318. foreach ($subject as $key => $val) {
  319. $subject[$key] = api_str_ireplace($search, $replace, $val, $count, $encoding);
  320. }
  321. return $subject;
  322. }
  323. if (is_array($search)) {
  324. foreach (array_keys($search) as $key) {
  325. if (is_array($replace)) {
  326. if (array_key_exists($key, $replace)) {
  327. $subject = api_str_ireplace($search[$key], $replace[$key], $subject, $count, $encoding);
  328. } else {
  329. $subject = api_str_ireplace($search[$key], '', $subject, $count, $encoding);
  330. }
  331. } else {
  332. $subject = api_str_ireplace($search[$key], $replace, $subject, $count, $encoding);
  333. }
  334. }
  335. return $subject;
  336. }
  337. $search = api_strtolower($search, $encoding);
  338. $subject_lower = api_strtolower($subject, $encoding);
  339. $total_matched_strlen = 0;
  340. $i = 0;
  341. while (preg_match(api_add_pcre_unicode_modifier('/(.*?)'.preg_quote($search, '/').'/s', $encoding), $subject_lower, $matches)) {
  342. $matched_strlen = api_strlen($matches[0], $encoding);
  343. $subject_lower = api_substr($subject_lower, $matched_strlen, api_strlen($subject_lower, $encoding), $encoding);
  344. $offset = $total_matched_strlen + api_strlen($matches[1], $encoding) + ($i * (api_strlen($replace, $encoding) - 1));
  345. $subject = api_substr_replace($subject, $replace, $offset, api_strlen($search), $encoding);
  346. $total_matched_strlen += $matched_strlen;
  347. $i++;
  348. }
  349. $count += $i;
  350. return $subject;
  351. }
  352. // This is a multibyte replacement of str_split().
  353. // See http://php.net/str_split
  354. function api_str_split($string, $split_length = 1, $encoding = null) {
  355. if ($split_length < 1) {
  356. return false;
  357. }
  358. if (empty($encoding)) {
  359. $encoding = api_mb_internal_encoding();
  360. }
  361. $result = array();
  362. if (api_mb_supports($encoding)) {
  363. for ($i = 0, $length = @mb_strlen($string, $encoding); $i < $length; $i += $split_length) {
  364. $result[] = @mb_substr($string, $i, $split_length, $encoding);
  365. }
  366. }
  367. elseif (api_iconv_supports($encoding)) {
  368. for ($i = 0, $length = api_strlen($string, $encoding); $i < $length; $i += $split_length) {
  369. $result[] = api_substr($string, $i, $split_length, $encoding);
  370. }
  371. } else {
  372. for ($i = 0, $length = strlen($string); $i < $length; $i += $split_length) {
  373. $result[] = substr($string, $i, $split_length);
  374. }
  375. }
  376. return $result;
  377. }
  378. // This is a multibyte replacement of strcasecmp().
  379. // See http://php.net/manual/en/function.strcasecmp
  380. function api_strcasecmp($str1, $str2, $encoding = null) {
  381. if (empty($encoding)) {
  382. $encoding = api_mb_internal_encoding();
  383. }
  384. return strcmp(api_strtolower($str1, $encoding), api_strtolower($str2, $encoding));
  385. }
  386. // This is a multibyte replacement of stripos().
  387. // See http://php.net/manual/en/function.mb-stripos
  388. function api_stripos($haystack, $needle, $offset = 0, $encoding = null) {
  389. if (empty($encoding)){
  390. $encoding = api_mb_internal_encoding();
  391. }
  392. if (api_mb_supports($encoding)) {
  393. return @mb_stripos($haystack, $needle, $offset, $encoding);
  394. } elseif (api_iconv_supports($encoding)) {
  395. return api_utf8_decode(@mb_stripos(api_utf8_encode($haystack, $encoding), api_utf8_encode($needle, $encoding), $offset, 'UTF-8'), $encoding);
  396. }
  397. return stripos($haystack, $needle, $offset);
  398. }
  399. // This is a multibyte replacement of stristr().
  400. // See http://php.net/manual/en/function.mb-stristr
  401. function api_stristr($haystack, $needle, $part = false, $encoding = null) {
  402. if (empty($encoding)) {
  403. $encoding = api_mb_internal_encoding();
  404. }
  405. if (api_mb_supports($encoding)) {
  406. return @mb_stristr($haystack, $needle, $part, $encoding);
  407. }
  408. elseif (api_iconv_supports($encoding)) {
  409. return api_utf8_decode(@mb_stristr(api_utf8_encode($haystack, $encoding), api_utf8_encode($needle, $encoding), $part, 'UTF-8'));
  410. }
  411. return stristr($haystack, $needle, $part);
  412. }
  413. // Returns length of the input string.
  414. // See http://php.net/manual/en/function.mb-strlen
  415. function api_strlen($string, $encoding = null) {
  416. if (empty($encoding)) {
  417. $encoding = api_mb_internal_encoding();
  418. }
  419. if (api_mb_supports($encoding)) {
  420. return @mb_strlen($string, $encoding);
  421. }
  422. elseif (api_iconv_supports($encoding)) {
  423. return @iconv_strlen($string, $encoding);
  424. }
  425. return strlen($string);
  426. }
  427. // This is a multibyte replacement of strpos().
  428. // See http://php.net/manual/en/function.mb-strpos
  429. function api_strpos($haystack, $needle, $offset = 0, $encoding = null) {
  430. if (empty($encoding)) {
  431. $encoding = api_mb_internal_encoding();
  432. }
  433. if (api_mb_supports($encoding)) {
  434. return @mb_strpos($haystack, $needle, $offset, $encoding);
  435. }
  436. elseif (api_iconv_supports($encoding)) {
  437. return api_utf8_decode(@mb_strpos(api_utf8_encode($haystack, $encoding), api_utf8_encode($needle, $encoding), $offset, 'UTF-8'), $encoding);
  438. }
  439. return strpos($haystack, $needle, $offset);
  440. }
  441. // This is a multibyte replacement of strrchr().
  442. // See http://php.net/manual/en/function.mb-strrchr
  443. function api_strrchr($haystack, $needle, $part = false, $encoding = null) {
  444. if (empty($encoding)) {
  445. $encoding = api_mb_internal_encoding();
  446. }
  447. if (api_mb_supports($encoding)) {
  448. return @mb_strrchr($haystack, $needle, $part, $encoding);
  449. }
  450. elseif (api_iconv_supports($encoding)) {
  451. return api_utf8_decode(@mb_strrchr(api_utf8_encode($haystack, $encoding), api_utf8_encode($needle, $encoding), $part, 'UTF-8'), $encoding);
  452. }
  453. return strrchr($haystack, $needle);
  454. }
  455. // This is a multibyte replacement of strrev().
  456. // See http://php.net/manual/en/function.strrev
  457. function api_strrev($string, $encoding = null) {
  458. if (empty($string)) {
  459. return '';
  460. }
  461. if (empty($encoding)) {
  462. $encoding = api_mb_internal_encoding();
  463. }
  464. $result = '';
  465. for ($i = api_strlen($string, $encoding) - 1; $i > -1; $i--) {
  466. $result .= api_substr($string, $i, 1, $encoding);
  467. }
  468. return $result;
  469. }
  470. // This is a multibyte replacement of strrpos().
  471. // See http://php.net/manual/en/function.mb-strrpos
  472. function api_strrpos($haystack, $needle, $offset = 0, $encoding = null) {
  473. if (empty($encoding)) {
  474. $encoding = api_mb_internal_encoding();
  475. }
  476. if (api_mb_supports($encoding)) {
  477. return @mb_strrpos($haystack, $needle, $offset, $encoding);
  478. }
  479. elseif (api_iconv_supports($encoding)) {
  480. return api_utf8_decode(@mb_strrpos(api_utf8_encode($haystack, $encoding), api_utf8_encode($needle, $encoding), $offset, 'UTF-8'), $encoding);
  481. }
  482. return strrpos($haystack, $needle, $offset);
  483. }
  484. // This is a multibyte replacement of strstr().
  485. // See http://php.net/manual/en/function.mb-strstr
  486. function api_strstr($haystack, $needle, $part = false, $encoding = null) {
  487. if (empty($encoding)) {
  488. $encoding = api_mb_internal_encoding();
  489. }
  490. if (api_mb_supports($encoding)) {
  491. return @mb_strstr($haystack, $needle, $part, $encoding);
  492. }
  493. elseif (api_iconv_supports($encoding)) {
  494. return api_utf8_decode(@mb_strstr(api_utf8_encode($haystack, $encoding), api_utf8_encode($needle, $encoding), $part, 'UTF-8'), $encoding);
  495. }
  496. return strstr($haystack, $needle, $part);
  497. }
  498. // Makes a string lowercase.
  499. // See http://php.net/manual/en/function.mb-strtolower
  500. function api_strtolower($string, $encoding = null) {
  501. if (empty($encoding)) {
  502. $encoding = api_mb_internal_encoding();
  503. }
  504. if (api_mb_supports($encoding)) {
  505. return @mb_strtolower($string, $encoding);
  506. }
  507. elseif (api_iconv_supports($encoding)) {
  508. return api_utf8_decode(@mb_strtolower(api_utf8_encode($string, $encoding), 'UTF-8'), $encoding);
  509. }
  510. return strtolower($string);
  511. }
  512. // Makes a string uppercase.
  513. // See http://php.net/manual/en/function.mb-strtoupper
  514. function api_strtoupper($string, $encoding = null) {
  515. if (empty($encoding)) {
  516. $encoding = api_mb_internal_encoding();
  517. }
  518. if (api_mb_supports($encoding)) {
  519. return @mb_strtoupper($string, $encoding);
  520. }
  521. elseif (api_iconv_supports($encoding)) {
  522. return api_utf8_decode(@mb_strtoupper(api_utf8_encode($string, $encoding), 'UTF-8'), $encoding);
  523. }
  524. return strtoupper($string);
  525. }
  526. // Translates certain characters.
  527. // See http://php.net/manual/en/function.strtr
  528. // TODO: To be revised and tested.
  529. // It would be good tihs function to be removed. I hesitate to do it right now.
  530. function api_strtr($string, $from, $to = null, $encoding = null) {
  531. if (empty($string)) {
  532. return '';
  533. }
  534. if (is_array($from)) {
  535. if (empty($from)) {
  536. return $string;
  537. }
  538. $encoding = $to;
  539. if (empty($encoding)){
  540. $encoding = api_mb_internal_encoding();
  541. }
  542. $translator = $from;
  543. } else {
  544. if (empty($from) || empty($to)) {
  545. return $string;
  546. }
  547. if (empty($encoding)) {
  548. $encoding = api_mb_internal_encoding();
  549. }
  550. $translator = array();
  551. $arr_from = api_get_characters($from, $encoding);
  552. $arr_to = api_get_characters($to, $encoding);
  553. $n = count($arr_from);
  554. $n2 = count($arr_to);
  555. if ($n > $n2) $n = $n2;
  556. for ($i = 0; $i < $n; $i++) {
  557. $translator[$arr_from[$i]] = $arr_to[$i];
  558. }
  559. }
  560. $arr_string = api_get_characters($string, $encoding);
  561. $n = count($arr_string);
  562. $result = '';
  563. for ($i = 0; $i < $n; $i++) {
  564. if (is_set($translator[$arr_string[$i]])) {
  565. $result .= $translator[$arr_string[$i]];
  566. } else {
  567. $result .= $arr_string[$i];
  568. }
  569. }
  570. return $result;
  571. }
  572. // Performs a multi-byte safe substr() operation based on number of characters.
  573. // See http://bg.php.net/manual/en/function.mb-substr
  574. function api_substr($string, $start, $length = null, $encoding = null) {
  575. if (empty($encoding)) {
  576. $encoding = api_mb_internal_encoding();
  577. }
  578. // Passing null as $length will mean 0. This behaviour have to be corrected.
  579. if (is_null($length)) {
  580. $length = api_strlen($string, $encoding);
  581. }
  582. if (api_mb_supports($encoding)) {
  583. return @mb_substr($string, $start, $length, $encoding);
  584. }
  585. elseif (api_iconv_supports($encoding)) {
  586. return api_utf8_decode(@mb_substr(api_utf8_encode($string, $encoding), $start, $length, 'UTF-8'), $encoding);
  587. }
  588. return substr($string, $start, $length);
  589. }
  590. // Puts a suffix into a string.
  591. // The input variables could be arrays too.
  592. function api_suffix($string, $suffix) {
  593. if (is_array($string)) {
  594. if (is_array($suffix)) {
  595. return array_map('api_suffix', $string, $suffix);
  596. } else {
  597. return array_map('api_suffix', $string, array_fill(0 , count($string) , $suffix));
  598. }
  599. }
  600. if (is_array($suffix)) {
  601. $suffix = implode('', $suffix);
  602. }
  603. return $string.$suffix;
  604. }
  605. // This is a multibyte replacement of substr_replace().
  606. // See http://php.net/manual/function.substr-replace
  607. function api_substr_replace($string, $replacement, $start, $length = null, $encoding = null) {
  608. if (empty($encoding)) {
  609. $encoding = api_mb_internal_encoding();
  610. }
  611. if ($length == null) {
  612. return api_substr($string, 0, $start, $encoding) . $replacement;
  613. } else {
  614. if ($length < 0) {
  615. $length = api_strlen($string, $encoding) - $start + $length;
  616. }
  617. return
  618. api_substr($string, 0, $start, $encoding) .$replacement .
  619. api_substr($string, $start + $length, api_strlen($string, $encoding), $encoding);
  620. }
  621. }
  622. // Returns a string with the first character capitalized, if that character is alphabetic.
  623. // See http://php.net/manual/en/function.ucfirst
  624. function api_ucfirst($string, $encoding = null) {
  625. if (empty($encoding)) {
  626. $encoding = api_mb_internal_encoding();
  627. }
  628. return api_strtoupper(api_substr($string, 0, 1, $encoding), $encoding) . api_substr($string, 1, api_strlen($string, $encoding), $encoding);
  629. }
  630. // Uppercases the first character of each word in a string.
  631. // See http://php.net/manual/en/function.ucwords
  632. function api_ucwords($string, $encoding = null) {
  633. if (empty($encoding)) {
  634. $encoding = api_mb_internal_encoding();
  635. }
  636. if (api_mb_supports($encoding)) {
  637. return @mb_convert_case($string, MB_CASE_TITLE, $encoding);
  638. }
  639. elseif (api_iconv_supports($encoding)) {
  640. return api_utf8_decode(@mb_convert_case(api_utf8_encode($string, $encoding), MB_CASE_TITLE, 'UTF-8'), $encoding);
  641. }
  642. return ucwords($string);
  643. }
  644. // This function adds a unicode modifier to a
  645. // Perl-compatible regular expression when it is necessary.
  646. function api_add_pcre_unicode_modifier($pcre, $encoding = null) {
  647. if (empty($encoding)){
  648. $encoding = api_get_system_encoding();
  649. }
  650. return api_is_utf8($encoding) ? $pcre.'u' : $pcre;
  651. }
  652. //----------------------------------------------------------------------------
  653. // Encoding management functions
  654. //----------------------------------------------------------------------------
  655. // Returns the most-probably used non-UTF-8 encoding for the given language.
  656. // The $language parameter must be cleaned by api_refine_language_id() if it
  657. // is necessary.
  658. // If the returned value is not as you expect, you may do the following:
  659. // In the table $encodings below, correct the order of the encodings for your
  660. // language, or if it is necessary - insert at the first place a new encoding.
  661. function api_get_non_utf8_encoding($language = null) {
  662. if (empty($language)) {
  663. $language = api_refine_language_id(api_get_interface_language());
  664. }
  665. $encodings = & api_non_utf8_encodings();
  666. if (is_array($encodings[$language])) {
  667. if (!empty($encodings[$language][0])) {
  668. return $encodings[$language][0];
  669. } else {
  670. return 'ISO-8859-15';
  671. }
  672. } else {
  673. return 'ISO-8859-15';
  674. }
  675. }
  676. // Returns a two-dimensional array of non-UTF-8 encodings for all system languages.
  677. function & api_non_utf8_encodings() {
  678. // The following list may have some inconsistencies.
  679. // Place the most used for your language encoding at the first place.
  680. // If you are adding an encoding, check whether it is supported either by
  681. // mbstring library, either by iconv library.
  682. // If you modify this list, please, follow the given syntax exactly.
  683. // The language names must be stripped of any suffixes, such as _unicode, _corporate, _org, etc.
  684. static $encodings =
  685. '
  686. arabic: WINDOWS-1256, ISO-8859-6;
  687. bosnian: WINDOWS-1250;
  688. brazilian: ISO-8859-15, WINDOWS-1252, ISO-8859-1;
  689. bulgarian: WINDOWS-1251;
  690. catalan: ISO-8859-15, WINDOWS-1252, ISO-8859-1;
  691. croatian: WINDOWS-1250;
  692. czech: WINDOWS-1250, ISO-8859-2;
  693. danish: ISO-8859-15, WINDOWS-1252, ISO-8859-1;
  694. dutch: ISO-8859-15, WINDOWS-1252, ISO-8859-1;
  695. english: ISO-8859-15, WINDOWS-1252, ISO-8859-1;
  696. esperanto: ISO-8859-15, WINDOWS-1252, ISO-8859-1;
  697. finnish: ISO-8859-15, WINDOWS-1252, ISO-8859-1;
  698. french: ISO-8859-15, WINDOWS-1252, ISO-8859-1;
  699. galician: ISO-8859-15, WINDOWS-1252, ISO-8859-1;
  700. german: ISO-8859-15, WINDOWS-1252, ISO-8859-1;
  701. greek: ISO-8859-7, WINDOWS-1253;
  702. hebrew: ISO-8859-8, WINDOWS-1255;
  703. hungarian: ISO-8859-2;
  704. indonesian: ISO-8859-15, WINDOWS-1252, ISO-8859-1;
  705. italian: ISO-8859-15, WINDOWS-1252, ISO-8859-1;
  706. japanese: EUC-JP, ISO-2022-JP;
  707. korean: EUC-KR, CP949, ISO-2022-KR;
  708. malay: ISO-8859-15, WINDOWS-1252, ISO-8859-1;
  709. norwegian: ISO-8859-15, WINDOWS-1252, ISO-8859-1;
  710. persian: WINDOWS-1252;
  711. polish: ISO-8859-15, WINDOWS-1252, ISO-8859-1;
  712. portuguese: ISO-8859-15, WINDOWS-1252, ISO-8859-1;
  713. russian: WINDOWS-1251, KOI8-R;
  714. serbian: ISO-8859-15, WINDOWS-1252, ISO-8859-1;
  715. simpl_chinese: GB2312, WINDOWS-936;
  716. slovak: WINDOWS-1250;
  717. slovenian: WINDOWS-1250;
  718. spanish: ISO-8859-15, WINDOWS-1252, ISO-8859-1;
  719. swahili: ISO-8859-1;
  720. swedish: ISO-8859-15, WINDOWS-1252, ISO-8859-1;
  721. thai: ISO-8859-11, WINDOWS-874;
  722. trad_chinese: BIG-5, EUC-TW;
  723. turkce: ISO-8859-9, WINDOWS-1254;
  724. ukrainian: KOI8-U;
  725. vietnamese: WINDOWS-1258;
  726. ';
  727. if (!is_array($encodings)) {
  728. $table = explode(';', str_replace(' ', '', $encodings));
  729. $encodings = array();
  730. foreach ($table as & $row) {
  731. $row = trim($row);
  732. if (!empty($row)) {
  733. $row = explode(':', $row);
  734. $encodings[$row[0]] = explode(',', strtoupper($row[1]));
  735. }
  736. }
  737. }
  738. return $encodings;
  739. }
  740. // This function unifies internally the encoding identificators.
  741. // It is to be adjusted in case of id comparison problems.
  742. function api_refine_encoding_id($encoding) {
  743. return strtoupper($encoding);
  744. }
  745. // This function checks whether two $encoding are equal (same, equvalent).
  746. function api_equal_encodings($encoding_1, $encoding_2) {
  747. // We have to deal with aliases. This function alone does not solve
  748. // the problem entirely. And there is no time for this kind of research.
  749. // At the momemnt, the quick proposition could be:
  750. return strcmp(api_refine_encoding_id($encoding_1), api_refine_encoding_id($encoding_2)) == 0 ? true : false;
  751. }
  752. // Returns true if the given encoding id means UTF-8, otherwise returns false.
  753. function api_is_utf8($encoding) {
  754. return api_equal_encodings($encoding, 'UTF-8');
  755. }
  756. // Returns the encoding currently used by the system.
  757. function api_get_system_encoding() {
  758. $system_encoding = api_get_setting('platform_charset');
  759. if (!empty($system_encoding)) {
  760. return $system_encoding;
  761. }
  762. global $charset;
  763. return empty($charset) ? 'ISO-8859-15' : $charset;
  764. }
  765. // Sets/Gets internal character encoding.
  766. // See http://php.net/manual/en/function.mb-internal-encoding
  767. function api_mb_internal_encoding($encoding = null) {
  768. static $mb_internal_encoding = null;
  769. if (empty($encoding)) {
  770. if (is_null($mb_internal_encoding)) {
  771. $mb_internal_encoding = @mb_internal_encoding();
  772. }
  773. return $mb_internal_encoding;
  774. }
  775. $mb_internal_encoding = $encoding;
  776. if (api_mb_supports($encoding)) {
  777. return @mb_internal_encoding($encoding);
  778. }
  779. return false;
  780. }
  781. // Sets/Gets current encoding for multibyte regex.
  782. // See http://php.net/manual/en/function.mb-regex-encoding
  783. function api_mb_regex_encoding($encoding = null) {
  784. static $mb_regex_encoding = null;
  785. if (empty($encoding)) {
  786. if (is_null($mb_regex_encoding)) {
  787. $mb_regex_encoding = @mb_regex_encoding();
  788. }
  789. return $mb_regex_encoding;
  790. }
  791. $mb_regex_encoding = $encoding;
  792. if (api_mb_supports($encoding)) {
  793. return @mb_regex_encoding($encoding);
  794. }
  795. return false;
  796. }
  797. // Retrieves internal configuration variables of iconv extension.
  798. // The parameter $type could be: 'iconv_internal_encoding', 'iconv_input_encoding', or 'iconv_output_encoding'.
  799. // See http://php.net/manual/en/function.iconv-get-encoding
  800. function api_iconv_get_encoding($type) {
  801. return api_iconv_set_encoding($type);
  802. }
  803. // Sets current setting for character encoding conversion.
  804. // The parameter $type could be: 'iconv_internal_encoding', 'iconv_input_encoding', or 'iconv_output_encoding'.
  805. function api_iconv_set_encoding($type, $encoding = null) {
  806. static $iconv_internal_encoding = null;
  807. static $iconv_input_encoding = null;
  808. static $iconv_output_encoding = null;
  809. if (!api_iconv_present()) {
  810. return false;
  811. }
  812. switch ($type) {
  813. case 'iconv_internal_encoding':
  814. if (empty($encoding)) {
  815. if (is_null($iconv_internal_encoding)) {
  816. $iconv_internal_encoding = @iconv_get_encoding($type);
  817. }
  818. return $iconv_internal_encoding;
  819. }
  820. if (api_iconv_supports($encoding)) {
  821. if(@iconv_set_encoding($type, $encoding)) {
  822. $iconv_internal_encoding = $encoding;
  823. return true;
  824. } else {
  825. return false;
  826. }
  827. } else {
  828. return false;
  829. }
  830. break;
  831. case 'iconv_input_encoding':
  832. if (empty($encoding)) {
  833. if (is_null($iconv_input_encoding)) {
  834. $iconv_input_encoding = @iconv_get_encoding($type);
  835. }
  836. return $iconv_input_encoding;
  837. }
  838. if (api_iconv_supports($encoding)) {
  839. if(@iconv_set_encoding($type, $encoding)) {
  840. $iconv_input_encoding = $encoding;
  841. return true;
  842. } else {
  843. return false;
  844. }
  845. } else {
  846. return false;
  847. }
  848. break;
  849. case 'iconv_output_encoding':
  850. if (empty($encoding)) {
  851. if (is_null($iconv_output_encoding)) {
  852. $iconv_output_encoding = @iconv_get_encoding($type);
  853. }
  854. return $iconv_output_encoding;
  855. }
  856. if (api_iconv_supports($encoding)) {
  857. if(@iconv_set_encoding($type, $encoding)) {
  858. $iconv_output_encoding = $encoding;
  859. return true;
  860. } else {
  861. return false;
  862. }
  863. } else {
  864. return false;
  865. }
  866. break;
  867. default:
  868. return false;
  869. }
  870. }
  871. // Checks whether the specified encoding is supported by this API.
  872. function api_is_encoding_supported($encoding) {
  873. return api_mb_supports($encoding) || api_iconv_supports($encoding);
  874. }
  875. // Checks whether the specified encoding is supported by mbstring library.
  876. function api_mb_supports($encoding) {
  877. static $supported = array();
  878. $encoding = api_refine_encoding_id($encoding);
  879. if (!isset($supported[$encoding])) {
  880. $mb_encodings = mb_list_encodings();
  881. $mb_encodings = array_map('api_refine_encoding_id', $mb_encodings);
  882. $supported[$encoding] = in_array($encoding, $mb_encodings);
  883. }
  884. return $supported[$encoding] ? true : false;
  885. }
  886. // Checks whether the specified non-UTF-8 encoding is supported by iconv library.
  887. function api_iconv_supports($encoding) {
  888. static $supported = array();
  889. $encoding = api_refine_encoding_id($encoding);
  890. if (!isset($supported[$encoding])) {
  891. if (api_iconv_present()) {
  892. $test_string = '';
  893. for ($i = 32; $i < 128; $i++) {
  894. $test_string .= chr($i);
  895. }
  896. $supported[$encoding] = (@iconv_strlen($test_string, $encoding)) ? true : false;
  897. } else {
  898. $supported[$encoding] = false;
  899. }
  900. }
  901. return $supported[$encoding];
  902. }
  903. // Checks whether the iconv library is installed and works.
  904. function api_iconv_present() {
  905. static $iconv_present = null;
  906. if (!is_null($iconv_present)) {
  907. return $iconv_present;
  908. }
  909. // I don't want to spoil the code with ugly strings.
  910. $test_string = '';
  911. for ($i = 32; $i < 128; $i++) {
  912. $test_string .= chr($i);
  913. }
  914. $iconv_present = (function_exists('iconv') &&
  915. @iconv('UTF-16LE', 'ISO-8859-1',
  916. @iconv('ISO-8859-1', 'UTF-16LE', $test_string)) == $test_string) ? true : false;
  917. return $iconv_present;
  918. }
  919. // Checks whether the specified encoding is supported by html-entities operations.
  920. function api_html_entity_supports($encoding) {
  921. static $supported = array();
  922. $encoding = api_refine_encoding_id($encoding);
  923. if (!isset($supported[$encoding])) {
  924. // See http://php.net/manual/en/function.htmlentities.php
  925. $html_entity_encodings = array(explode(',',
  926. '
  927. ISO-8859-1, ISO8859-1,
  928. ISO-8859-15, ISO8859-15,
  929. UTF-8,
  930. cp866, ibm866, 866,
  931. cp1251, Windows-1251, win-1251, 1251,
  932. cp1252, Windows-1252, 1252,
  933. KOI8-R, koi8-ru, koi8r,
  934. BIG5, 950,
  935. GB2312, 936,
  936. BIG5-HKSCS,
  937. Shift_JIS, SJIS, 932,
  938. EUC-JP, EUCJP
  939. '));
  940. $html_entity_encodings = array_map('trim', $html_entity_encodings);
  941. $html_entity_encodings = array_map('api_refine_encoding_id', $html_entity_encodings);
  942. $supported[$encoding] = in_array($encoding, $html_entity_encodings);
  943. }
  944. return $supported[$encoding] ? true : false;
  945. }
  946. // Returns true if the specified string is a valid UTF-8 one and false otherwise.
  947. function api_is_valid_utf8($string) {
  948. //return @mb_detect_encoding($string, 'UTF-8', true) == 'UTF-8' ? true : false;
  949. // Ivan Tcholakov, 05-OCT-2008: I do not trust mb_detect_encoding(). I have
  950. // found a string with a single cyrillic letter (single byte), that is
  951. // wrongly detected as UTF-8. Possibly, there would be problems with other
  952. // languages too.
  953. //
  954. // To understand the following algorithm see http://en.wikipedia.org/wiki/UTF-8
  955. $len = strlen($string);
  956. $i = 0;
  957. while ($i < $len) {
  958. $byte1 = ord($string[$i++]); // Here the current character begins. Its size is
  959. // determined by the senior bits in the first byte.
  960. if (($byte1 & 0x80) == 0x00) { // 0xxxxxxx
  961. // &
  962. // 10000000
  963. // --------
  964. // 00000000
  965. // This is s valid character and it contains a single byte.
  966. }
  967. elseif (($byte1 & 0xE0) == 0xC0) { // 110xxxxx 10xxxxxx
  968. // & &
  969. // 11100000 11000000
  970. // -------- --------
  971. // 11000000 10000000
  972. // The character contains two bytes.
  973. if ($i == $len)
  974. return false; // Here the string ends unexpectedly.
  975. if (!((ord($string[$i++]) & 0xC0) == 0x80))
  976. return false; // Invalid second byte, invalid string.
  977. }
  978. elseif(($byte1 & 0xF0) == 0xE0) { // 1110xxxx 10xxxxxx 10xxxxxx
  979. // & & &
  980. // 11110000 11000000 11000000
  981. // -------- -------- --------
  982. // 11100000 10000000 10000000
  983. // This is a character of three bytes.
  984. if ($i == $len) {
  985. return false; // Unexpected end of the string.
  986. }
  987. if (!((ord($string[$i++]) & 0xC0) == 0x80)) {
  988. return false; // Invalid second byte.
  989. }
  990. if ($i == $len) {
  991. return false; // Unexpected end of the string.
  992. }
  993. if (!((ord($string[$i++]) & 0xC0) == 0x80)) {
  994. return false; // Invalid third byte, invalid string.
  995. }
  996. }
  997. elseif(($byte1 & 0xF8) == 0xF0) { // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
  998. // & & & &
  999. // 11111000 11000000 11000000 11000000
  1000. // -------- -------- -------- --------
  1001. // 11110000 10000000 10000000 10000000
  1002. // This is a character of four bytes.
  1003. if ($i == $len) {
  1004. return false;
  1005. }
  1006. if (!((ord($string[$i++]) & 0xC0) == 0x80)) {
  1007. return false;
  1008. }
  1009. if ($i == $len) {
  1010. return false;
  1011. }
  1012. if (!((ord($string[$i++]) & 0xC0) == 0x80)) {
  1013. return false;
  1014. }
  1015. if ($i == $len) {
  1016. return false;
  1017. }
  1018. if (!((ord($string[$i++]) & 0xC0) == 0x80)) {
  1019. return false;
  1020. }
  1021. }
  1022. elseif(($byte1 & 0xFC) == 0xF8) { // 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
  1023. // & & & & &
  1024. // 11111100 11000000 11000000 11000000 11000000
  1025. // -------- -------- -------- -------- --------
  1026. // 11111000 10000000 10000000 10000000 10000000
  1027. // This is a character of five bytes.
  1028. if ($i == $len) {
  1029. return false;
  1030. }
  1031. if (!((ord($string[$i++]) & 0xC0) == 0x80)) {
  1032. return false;
  1033. }
  1034. if ($i == $len) {
  1035. return false;
  1036. }
  1037. if (!((ord($string[$i++]) & 0xC0) == 0x80)) {
  1038. return false;
  1039. }
  1040. if ($i == $len) {
  1041. return false;
  1042. }
  1043. if (!((ord($string[$i++]) & 0xC0) == 0x80)) {
  1044. return false;
  1045. }
  1046. if ($i == $len) {
  1047. return false;
  1048. }
  1049. if (!((ord($string[$i++]) & 0xC0) == 0x80)) {
  1050. return false;
  1051. }
  1052. }
  1053. elseif(($byte1 & 0xFE) == 0xFC) { // 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
  1054. // & & & & & &
  1055. // 11111110 11000000 11000000 11000000 11000000 11000000
  1056. // -------- -------- -------- -------- -------- --------
  1057. // 11111100 10000000 10000000 10000000 10000000 10000000
  1058. // This is a character of six bytes.
  1059. if ($i == $len) {
  1060. return false;
  1061. }
  1062. if (!((ord($string[$i++]) & 0xC0) == 0x80)) {
  1063. return false;
  1064. }
  1065. if ($i == $len) {
  1066. return false;
  1067. }
  1068. if (!((ord($string[$i++]) & 0xC0) == 0x80)) {
  1069. return false;
  1070. }
  1071. if ($i == $len) {
  1072. return false;
  1073. }
  1074. if (!((ord($string[$i++]) & 0xC0) == 0x80)) {
  1075. return false;
  1076. }
  1077. if ($i == $len) {
  1078. return false;
  1079. }
  1080. if (!((ord($string[$i++]) & 0xC0) == 0x80)) {
  1081. return false;
  1082. }
  1083. if ($i == $len) {
  1084. return false;
  1085. }
  1086. if (!((ord($string[$i++]) & 0xC0) == 0x80)) {
  1087. return false;
  1088. }
  1089. }
  1090. else {
  1091. return false; // In any other case the character is invalid.
  1092. }
  1093. // Here the current character is valid, it
  1094. // matches to some of the cases above.
  1095. // The next character is to be examinated.
  1096. }
  1097. return true; // Empty strings are valid too.
  1098. }
  1099. // Checks whether a string contains 7bit ASCII characters only.
  1100. function api_is_valid_ascii($string) {
  1101. return @mb_detect_encoding($string, 'ASCII', true) == 'ASCII' ? true : false;
  1102. }
  1103. //----------------------------------------------------------------------------
  1104. // Language management functions
  1105. //----------------------------------------------------------------------------
  1106. // Returns a pure language id, without possible suffixes
  1107. // that will disturb language identification in certain cases.
  1108. function api_refine_language_id($language) {
  1109. return (
  1110. str_replace('_unicode', '', strtolower(
  1111. str_replace('_latin', '',
  1112. str_replace('_corporate', '',
  1113. str_replace('_org', '',
  1114. str_replace('_KM', '', $language)))))));
  1115. }
  1116. //----------------------------------------------------------------------------
  1117. // Array functions
  1118. //----------------------------------------------------------------------------
  1119. // A case insensitive version of in_array() function.
  1120. // See http://php.net/manual/en/function.in-array.php
  1121. function api_in_array_nocase($needle, $haystack, $strict = false, $encoding = null) {
  1122. if (is_array($needle)) {
  1123. foreach ($needle as $item) {
  1124. if (api_in_array_nocase($item, $haystack, $strict, $encoding)) return true;
  1125. }
  1126. return false;
  1127. }
  1128. if (!is_string($needle)) {
  1129. return in_array($needle, $haystack, $strict);
  1130. }
  1131. $needle = api_strtolower($needle, $encoding);
  1132. foreach ($haystack as $item) {
  1133. if (api_strtolower($item, $encoding) == $needle) {
  1134. return true;
  1135. }
  1136. }
  1137. return false;
  1138. }
  1139. //----------------------------------------------------------------------------
  1140. // Multibyte string functions designed to upgrade the PHP5 mbstring extension
  1141. //----------------------------------------------------------------------------
  1142. // ---------- Multibyte string functions implemented in PHP 5.2.0+ -----------
  1143. // This is a multibyte replacement of strchr().
  1144. // This function exists in PHP 5 >= 5.2.0
  1145. // See http://php.net/manual/en/function.mb-strrchr
  1146. if (!function_exists('mb_strchr')) {
  1147. function mb_strchr($haystack, $needle, $part = false, $encoding = null) {
  1148. if (empty($encoding)) {
  1149. $encoding = mb_internal_encoding();
  1150. }
  1151. return mb_strstr($haystack, $needle, $part, $encoding);
  1152. }
  1153. }
  1154. // This is a multibyte replacement of stripos().
  1155. // This function exists in PHP 5 >= 5.2.0
  1156. // See http://php.net/manual/en/function.mb-stripos
  1157. if (!function_exists('mb_stripos')) {
  1158. function mb_stripos($haystack, $needle, $offset = 0, $encoding = null) {
  1159. if (empty($encoding)) {
  1160. $encoding = mb_internal_encoding();
  1161. }
  1162. return mb_strpos(mb_strtolower($haystack, $encoding), mb_strtolower($needle, $encoding), $offset, $encoding);
  1163. }
  1164. }
  1165. // This is a multibyte replacement of stristr().
  1166. // This function exists in PHP 5 >= 5.2.0
  1167. // See http://php.net/manual/en/function.mb-stristr
  1168. if (!function_exists('mb_stristr')) {
  1169. function mb_stristr($haystack, $needle, $part = false, $encoding = null) {
  1170. if (empty($encoding)) {
  1171. $encoding = mb_internal_encoding();
  1172. }
  1173. $pos = mb_strpos(mb_strtolower($haystack, $encoding), mb_strtolower($needle, $encoding), 0, $encoding);
  1174. if ($pos === false) {
  1175. return false;
  1176. }
  1177. elseif($part == true) {
  1178. return mb_substr($haystack, 0, $pos + 1, $encoding);
  1179. } else {
  1180. return mb_substr($haystack, $pos, mb_strlen($haystack, $encoding), $encoding);
  1181. }
  1182. }
  1183. }
  1184. // This is a multibyte replacement of strrchr().
  1185. // This function exists in PHP 5 >= 5.2.0
  1186. // See http://php.net/manual/en/function.mb-strrchr
  1187. if (!function_exists('mb_strrchr')) {
  1188. function mb_strrchr($haystack, $needle, $part = false, $encoding = null) {
  1189. if (empty($encoding)) {
  1190. $encoding = mb_internal_encoding();
  1191. }
  1192. $needle = mb_substr($needle, 0, 1, $encoding);
  1193. $pos = mb_strrpos($haystack, $needle, mb_strlen($haystack, $encoding) - 1, $encoding);
  1194. if ($pos === false) {
  1195. return false;
  1196. } elseif($part == true) {
  1197. return mb_substr($haystack, 0, $pos + 1, $encoding);
  1198. } else {
  1199. return mb_substr($haystack, $pos, mb_strlen($haystack, $encoding), $encoding);
  1200. }
  1201. }
  1202. }
  1203. // This is a multibyte replacement of strstr().
  1204. // This function exists in PHP 5 >= 5.2.0
  1205. // See http://php.net/manual/en/function.mb-strstr
  1206. if (!function_exists('mb_strstr')) {
  1207. function mb_strstr($haystack, $needle, $part = false, $encoding = null) {
  1208. if (empty($encoding)) {
  1209. $encoding = mb_internal_encoding();
  1210. }
  1211. $pos = mb_strpos($haystack, $needle, 0, $encoding);
  1212. if ($pos === false) {
  1213. return false;
  1214. } elseif($part == true) {
  1215. return mb_substr($haystack, 0, $pos + 1, $encoding);
  1216. } else {
  1217. return mb_substr($haystack, $pos, mb_strlen($haystack, $encoding), $encoding);
  1218. }
  1219. }
  1220. }
  1221. ?>