PageRenderTime 114ms CodeModel.GetById 68ms app.highlight 21ms RepoModel.GetById 18ms app.codeStats 1ms

/system/classes/Kohana/UTF8.php

https://bitbucket.org/sklyarov_ivan/trap
PHP | 767 lines | 280 code | 92 blank | 395 comment | 35 complexity | ec03f3f3774873147fd3920153615d36 MD5 | raw file
  1<?php defined('SYSPATH') OR die('No direct script access.');
  2/**
  3 * A port of [phputf8](http://phputf8.sourceforge.net/) to a unified set
  4 * of files. Provides multi-byte aware replacement string functions.
  5 *
  6 * For UTF-8 support to work correctly, the following requirements must be met:
  7 *
  8 * - PCRE needs to be compiled with UTF-8 support (--enable-utf8)
  9 * - Support for [Unicode properties](http://php.net/manual/reference.pcre.pattern.modifiers.php)
 10 *   is highly recommended (--enable-unicode-properties)
 11 * - UTF-8 conversion will be much more reliable if the
 12 *   [iconv extension](http://php.net/iconv) is loaded
 13 * - The [mbstring extension](http://php.net/mbstring) is highly recommended,
 14 *   but must not be overloading string functions
 15 *
 16 * [!!] This file is licensed differently from the rest of Kohana. As a port of
 17 * [phputf8](http://phputf8.sourceforge.net/), this file is released under the LGPL.
 18 *
 19 * @package    Kohana
 20 * @category   Base
 21 * @author     Kohana Team
 22 * @copyright  (c) 2007-2012 Kohana Team
 23 * @copyright  (c) 2005 Harry Fuecks
 24 * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt
 25 */
 26class Kohana_UTF8 {
 27
 28	/**
 29	 * @var  boolean  Does the server support UTF-8 natively?
 30	 */
 31	public static $server_utf8 = NULL;
 32
 33	/**
 34	 * @var  array  List of called methods that have had their required file included.
 35	 */
 36	public static $called = array();
 37
 38	/**
 39	 * Recursively cleans arrays, objects, and strings. Removes ASCII control
 40	 * codes and converts to the requested charset while silently discarding
 41	 * incompatible characters.
 42	 *
 43	 *     UTF8::clean($_GET); // Clean GET data
 44	 *
 45	 * [!!] This method requires [Iconv](http://php.net/iconv)
 46	 *
 47	 * @param   mixed   $var        variable to clean
 48	 * @param   string  $charset    character set, defaults to Kohana::$charset
 49	 * @return  mixed
 50	 * @uses    UTF8::strip_ascii_ctrl
 51	 * @uses    UTF8::is_ascii
 52	 */
 53	public static function clean($var, $charset = NULL)
 54	{
 55		if ( ! $charset)
 56		{
 57			// Use the application character set
 58			$charset = Kohana::$charset;
 59		}
 60
 61		if (is_array($var) OR is_object($var))
 62		{
 63			foreach ($var as $key => $val)
 64			{
 65				// Recursion!
 66				$var[self::clean($key)] = self::clean($val);
 67			}
 68		}
 69		elseif (is_string($var) AND $var !== '')
 70		{
 71			// Remove control characters
 72			$var = self::strip_ascii_ctrl($var);
 73
 74			if ( ! self::is_ascii($var))
 75			{
 76				// Disable notices
 77				$error_reporting = error_reporting(~E_NOTICE);
 78
 79				// iconv is expensive, so it is only used when needed
 80				$var = iconv($charset, $charset.'//IGNORE', $var);
 81
 82				// Turn notices back on
 83				error_reporting($error_reporting);
 84			}
 85		}
 86
 87		return $var;
 88	}
 89
 90	/**
 91	 * Tests whether a string contains only 7-bit ASCII bytes. This is used to
 92	 * determine when to use native functions or UTF-8 functions.
 93	 *
 94	 *     $ascii = UTF8::is_ascii($str);
 95	 *
 96	 * @param   mixed   $str    string or array of strings to check
 97	 * @return  boolean
 98	 */
 99	public static function is_ascii($str)
100	{
101		if (is_array($str))
102		{
103			$str = implode($str);
104		}
105
106		return ! preg_match('/[^\x00-\x7F]/S', $str);
107	}
108
109	/**
110	 * Strips out device control codes in the ASCII range.
111	 *
112	 *     $str = UTF8::strip_ascii_ctrl($str);
113	 *
114	 * @param   string  $str    string to clean
115	 * @return  string
116	 */
117	public static function strip_ascii_ctrl($str)
118	{
119		return preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]+/S', '', $str);
120	}
121
122	/**
123	 * Strips out all non-7bit ASCII bytes.
124	 *
125	 *     $str = UTF8::strip_non_ascii($str);
126	 *
127	 * @param   string  $str    string to clean
128	 * @return  string
129	 */
130	public static function strip_non_ascii($str)
131	{
132		return preg_replace('/[^\x00-\x7F]+/S', '', $str);
133	}
134
135	/**
136	 * Replaces special/accented UTF-8 characters by ASCII-7 "equivalents".
137	 *
138	 *     $ascii = UTF8::transliterate_to_ascii($utf8);
139	 *
140	 * @author  Andreas Gohr <andi@splitbrain.org>
141	 * @param   string  $str    string to transliterate
142	 * @param   integer $case   -1 lowercase only, +1 uppercase only, 0 both cases
143	 * @return  string
144	 */
145	public static function transliterate_to_ascii($str, $case = 0)
146	{
147		if ( ! isset(self::$called[__FUNCTION__]))
148		{
149			require Kohana::find_file('utf8', __FUNCTION__);
150
151			// Function has been called
152			self::$called[__FUNCTION__] = TRUE;
153		}
154
155		return _transliterate_to_ascii($str, $case);
156	}
157
158	/**
159	 * Returns the length of the given string. This is a UTF8-aware version
160	 * of [strlen](http://php.net/strlen).
161	 *
162	 *     $length = UTF8::strlen($str);
163	 *
164	 * @param   string  $str    string being measured for length
165	 * @return  integer
166	 * @uses    UTF8::$server_utf8
167	 */
168	public static function strlen($str)
169	{
170		if (UTF8::$server_utf8)
171			return mb_strlen($str, Kohana::$charset);
172
173		if ( ! isset(self::$called[__FUNCTION__]))
174		{
175			require Kohana::find_file('utf8', __FUNCTION__);
176
177			// Function has been called
178			self::$called[__FUNCTION__] = TRUE;
179		}
180
181		return _strlen($str);
182	}
183
184	/**
185	 * Finds position of first occurrence of a UTF-8 string. This is a
186	 * UTF8-aware version of [strpos](http://php.net/strpos).
187	 *
188	 *     $position = UTF8::strpos($str, $search);
189	 *
190	 * @author  Harry Fuecks <hfuecks@gmail.com>
191	 * @param   string  $str    haystack
192	 * @param   string  $search needle
193	 * @param   integer $offset offset from which character in haystack to start searching
194	 * @return  integer position of needle
195	 * @return  boolean FALSE if the needle is not found
196	 * @uses    UTF8::$server_utf8
197	 */
198	public static function strpos($str, $search, $offset = 0)
199	{
200		if (UTF8::$server_utf8)
201			return mb_strpos($str, $search, $offset, Kohana::$charset);
202
203		if ( ! isset(self::$called[__FUNCTION__]))
204		{
205			require Kohana::find_file('utf8', __FUNCTION__);
206
207			// Function has been called
208			self::$called[__FUNCTION__] = TRUE;
209		}
210
211		return _strpos($str, $search, $offset);
212	}
213
214	/**
215	 * Finds position of last occurrence of a char in a UTF-8 string. This is
216	 * a UTF8-aware version of [strrpos](http://php.net/strrpos).
217	 *
218	 *     $position = UTF8::strrpos($str, $search);
219	 *
220	 * @author  Harry Fuecks <hfuecks@gmail.com>
221	 * @param   string  $str    haystack
222	 * @param   string  $search needle
223	 * @param   integer $offset offset from which character in haystack to start searching
224	 * @return  integer position of needle
225	 * @return  boolean FALSE if the needle is not found
226	 * @uses    UTF8::$server_utf8
227	 */
228	public static function strrpos($str, $search, $offset = 0)
229	{
230		if (UTF8::$server_utf8)
231			return mb_strrpos($str, $search, $offset, Kohana::$charset);
232
233		if ( ! isset(self::$called[__FUNCTION__]))
234		{
235			require Kohana::find_file('utf8', __FUNCTION__);
236
237			// Function has been called
238			self::$called[__FUNCTION__] = TRUE;
239		}
240
241		return _strrpos($str, $search, $offset);
242	}
243
244	/**
245	 * Returns part of a UTF-8 string. This is a UTF8-aware version
246	 * of [substr](http://php.net/substr).
247	 *
248	 *     $sub = UTF8::substr($str, $offset);
249	 *
250	 * @author  Chris Smith <chris@jalakai.co.uk>
251	 * @param   string  $str    input string
252	 * @param   integer $offset offset
253	 * @param   integer $length length limit
254	 * @return  string
255	 * @uses    UTF8::$server_utf8
256	 * @uses    Kohana::$charset
257	 */
258	public static function substr($str, $offset, $length = NULL)
259	{
260		if (UTF8::$server_utf8)
261			return ($length === NULL)
262				? mb_substr($str, $offset, mb_strlen($str), Kohana::$charset)
263				: mb_substr($str, $offset, $length, Kohana::$charset);
264
265		if ( ! isset(self::$called[__FUNCTION__]))
266		{
267			require Kohana::find_file('utf8', __FUNCTION__);
268
269			// Function has been called
270			self::$called[__FUNCTION__] = TRUE;
271		}
272
273		return _substr($str, $offset, $length);
274	}
275
276	/**
277	 * Replaces text within a portion of a UTF-8 string. This is a UTF8-aware
278	 * version of [substr_replace](http://php.net/substr_replace).
279	 *
280	 *     $str = UTF8::substr_replace($str, $replacement, $offset);
281	 *
282	 * @author  Harry Fuecks <hfuecks@gmail.com>
283	 * @param   string  $str            input string
284	 * @param   string  $replacement    replacement string
285	 * @param   integer $offset         offset
286	 * @return  string
287	 */
288	public static function substr_replace($str, $replacement, $offset, $length = NULL)
289	{
290		if ( ! isset(self::$called[__FUNCTION__]))
291		{
292			require Kohana::find_file('utf8', __FUNCTION__);
293
294			// Function has been called
295			self::$called[__FUNCTION__] = TRUE;
296		}
297
298		return _substr_replace($str, $replacement, $offset, $length);
299	}
300
301	/**
302	 * Makes a UTF-8 string lowercase. This is a UTF8-aware version
303	 * of [strtolower](http://php.net/strtolower).
304	 *
305	 *     $str = UTF8::strtolower($str);
306	 *
307	 * @author  Andreas Gohr <andi@splitbrain.org>
308	 * @param   string  $str    mixed case string
309	 * @return  string
310	 * @uses    UTF8::$server_utf8
311	 */
312	public static function strtolower($str)
313	{
314		if (UTF8::$server_utf8)
315			return mb_strtolower($str, Kohana::$charset);
316
317		if ( ! isset(self::$called[__FUNCTION__]))
318		{
319			require Kohana::find_file('utf8', __FUNCTION__);
320
321			// Function has been called
322			self::$called[__FUNCTION__] = TRUE;
323		}
324
325		return _strtolower($str);
326	}
327
328	/**
329	 * Makes a UTF-8 string uppercase. This is a UTF8-aware version
330	 * of [strtoupper](http://php.net/strtoupper).
331	 *
332	 * @author  Andreas Gohr <andi@splitbrain.org>
333	 * @param   string  $str    mixed case string
334	 * @return  string
335	 * @uses    UTF8::$server_utf8
336	 * @uses    Kohana::$charset
337	 */
338	public static function strtoupper($str)
339	{
340		if (UTF8::$server_utf8)
341			return mb_strtoupper($str, Kohana::$charset);
342
343		if ( ! isset(self::$called[__FUNCTION__]))
344		{
345			require Kohana::find_file('utf8', __FUNCTION__);
346
347			// Function has been called
348			self::$called[__FUNCTION__] = TRUE;
349		}
350
351		return _strtoupper($str);
352	}
353
354	/**
355	 * Makes a UTF-8 string's first character uppercase. This is a UTF8-aware
356	 * version of [ucfirst](http://php.net/ucfirst).
357	 *
358	 *     $str = UTF8::ucfirst($str);
359	 *
360	 * @author  Harry Fuecks <hfuecks@gmail.com>
361	 * @param   string  $str    mixed case string
362	 * @return  string
363	 */
364	public static function ucfirst($str)
365	{
366		if ( ! isset(self::$called[__FUNCTION__]))
367		{
368			require Kohana::find_file('utf8', __FUNCTION__);
369
370			// Function has been called
371			self::$called[__FUNCTION__] = TRUE;
372		}
373
374		return _ucfirst($str);
375	}
376
377	/**
378	 * Makes the first character of every word in a UTF-8 string uppercase.
379	 * This is a UTF8-aware version of [ucwords](http://php.net/ucwords).
380	 *
381	 *     $str = UTF8::ucwords($str);
382	 *
383	 * @author  Harry Fuecks <hfuecks@gmail.com>
384	 * @param   string  $str    mixed case string
385	 * @return  string
386	 * @uses    UTF8::$server_utf8
387	 */
388	public static function ucwords($str)
389	{
390		if ( ! isset(self::$called[__FUNCTION__]))
391		{
392			require Kohana::find_file('utf8', __FUNCTION__);
393
394			// Function has been called
395			self::$called[__FUNCTION__] = TRUE;
396		}
397
398		return _ucwords($str);
399	}
400
401	/**
402	 * Case-insensitive UTF-8 string comparison. This is a UTF8-aware version
403	 * of [strcasecmp](http://php.net/strcasecmp).
404	 *
405	 *     $compare = UTF8::strcasecmp($str1, $str2);
406	 *
407	 * @author  Harry Fuecks <hfuecks@gmail.com>
408	 * @param   string  $str1   string to compare
409	 * @param   string  $str2   string to compare
410	 * @return  integer less than 0 if str1 is less than str2
411	 * @return  integer greater than 0 if str1 is greater than str2
412	 * @return  integer 0 if they are equal
413	 */
414	public static function strcasecmp($str1, $str2)
415	{
416		if ( ! isset(self::$called[__FUNCTION__]))
417		{
418			require Kohana::find_file('utf8', __FUNCTION__);
419
420			// Function has been called
421			self::$called[__FUNCTION__] = TRUE;
422		}
423
424		return _strcasecmp($str1, $str2);
425	}
426
427	/**
428	 * Returns a string or an array with all occurrences of search in subject
429	 * (ignoring case) and replaced with the given replace value. This is a
430	 * UTF8-aware version of [str_ireplace](http://php.net/str_ireplace).
431	 *
432	 * [!!] This function is very slow compared to the native version. Avoid
433	 * using it when possible.
434	 *
435	 * @author  Harry Fuecks <hfuecks@gmail.com
436	 * @param   string|array    $search     text to replace
437	 * @param   string|array    $replace    replacement text
438	 * @param   string|array    $str        subject text
439	 * @param   integer         $count      number of matched and replaced needles will be returned via this parameter which is passed by reference
440	 * @return  string  if the input was a string
441	 * @return  array   if the input was an array
442	 */
443	public static function str_ireplace($search, $replace, $str, & $count = NULL)
444	{
445		if ( ! isset(self::$called[__FUNCTION__]))
446		{
447			require Kohana::find_file('utf8', __FUNCTION__);
448
449			// Function has been called
450			self::$called[__FUNCTION__] = TRUE;
451		}
452
453		return _str_ireplace($search, $replace, $str, $count);
454	}
455
456	/**
457	 * Case-insenstive UTF-8 version of strstr. Returns all of input string
458	 * from the first occurrence of needle to the end. This is a UTF8-aware
459	 * version of [stristr](http://php.net/stristr).
460	 *
461	 *     $found = UTF8::stristr($str, $search);
462	 *
463	 * @author Harry Fuecks <hfuecks@gmail.com>
464	 * @param   string  $str    input string
465	 * @param   string  $search needle
466	 * @return  string  matched substring if found
467	 * @return  FALSE   if the substring was not found
468	 */
469	public static function stristr($str, $search)
470	{
471		if ( ! isset(self::$called[__FUNCTION__]))
472		{
473			require Kohana::find_file('utf8', __FUNCTION__);
474
475			// Function has been called
476			self::$called[__FUNCTION__] = TRUE;
477		}
478
479		return _stristr($str, $search);
480	}
481
482	/**
483	 * Finds the length of the initial segment matching mask. This is a
484	 * UTF8-aware version of [strspn](http://php.net/strspn).
485	 *
486	 *     $found = UTF8::strspn($str, $mask);
487	 *
488	 * @author Harry Fuecks <hfuecks@gmail.com>
489	 * @param   string  $str    input string
490	 * @param   string  $mask   mask for search
491	 * @param   integer $offset start position of the string to examine
492	 * @param   integer $length length of the string to examine
493	 * @return  integer length of the initial segment that contains characters in the mask
494	 */
495	public static function strspn($str, $mask, $offset = NULL, $length = NULL)
496	{
497		if ( ! isset(self::$called[__FUNCTION__]))
498		{
499			require Kohana::find_file('utf8', __FUNCTION__);
500
501			// Function has been called
502			self::$called[__FUNCTION__] = TRUE;
503		}
504
505		return _strspn($str, $mask, $offset, $length);
506	}
507
508	/**
509	 * Finds the length of the initial segment not matching mask. This is a
510	 * UTF8-aware version of [strcspn](http://php.net/strcspn).
511	 *
512	 *     $found = UTF8::strcspn($str, $mask);
513	 *
514	 * @author  Harry Fuecks <hfuecks@gmail.com>
515	 * @param   string  $str    input string
516	 * @param   string  $mask   mask for search
517	 * @param   integer $offset start position of the string to examine
518	 * @param   integer $length length of the string to examine
519	 * @return  integer length of the initial segment that contains characters not in the mask
520	 */
521	public static function strcspn($str, $mask, $offset = NULL, $length = NULL)
522	{
523		if ( ! isset(self::$called[__FUNCTION__]))
524		{
525			require Kohana::find_file('utf8', __FUNCTION__);
526
527			// Function has been called
528			self::$called[__FUNCTION__] = TRUE;
529		}
530
531		return _strcspn($str, $mask, $offset, $length);
532	}
533
534	/**
535	 * Pads a UTF-8 string to a certain length with another string. This is a
536	 * UTF8-aware version of [str_pad](http://php.net/str_pad).
537	 *
538	 *     $str = UTF8::str_pad($str, $length);
539	 *
540	 * @author  Harry Fuecks <hfuecks@gmail.com>
541	 * @param   string  $str                input string
542	 * @param   integer $final_str_length   desired string length after padding
543	 * @param   string  $pad_str            string to use as padding
544	 * @param   string  $pad_type           padding type: STR_PAD_RIGHT, STR_PAD_LEFT, or STR_PAD_BOTH
545	 * @return  string
546	 */
547	public static function str_pad($str, $final_str_length, $pad_str = ' ', $pad_type = STR_PAD_RIGHT)
548	{
549		if ( ! isset(self::$called[__FUNCTION__]))
550		{
551			require Kohana::find_file('utf8', __FUNCTION__);
552
553			// Function has been called
554			self::$called[__FUNCTION__] = TRUE;
555		}
556
557		return _str_pad($str, $final_str_length, $pad_str, $pad_type);
558	}
559
560	/**
561	 * Converts a UTF-8 string to an array. This is a UTF8-aware version of
562	 * [str_split](http://php.net/str_split).
563	 *
564	 *     $array = UTF8::str_split($str);
565	 *
566	 * @author  Harry Fuecks <hfuecks@gmail.com>
567	 * @param   string  $str            input string
568	 * @param   integer $split_length   maximum length of each chunk
569	 * @return  array
570	 */
571	public static function str_split($str, $split_length = 1)
572	{
573		if ( ! isset(self::$called[__FUNCTION__]))
574		{
575			require Kohana::find_file('utf8', __FUNCTION__);
576
577			// Function has been called
578			self::$called[__FUNCTION__] = TRUE;
579		}
580
581		return _str_split($str, $split_length);
582	}
583
584	/**
585	 * Reverses a UTF-8 string. This is a UTF8-aware version of [strrev](http://php.net/strrev).
586	 *
587	 *     $str = UTF8::strrev($str);
588	 *
589	 * @author  Harry Fuecks <hfuecks@gmail.com>
590	 * @param   string  $str    string to be reversed
591	 * @return  string
592	 */
593	public static function strrev($str)
594	{
595		if ( ! isset(self::$called[__FUNCTION__]))
596		{
597			require Kohana::find_file('utf8', __FUNCTION__);
598
599			// Function has been called
600			self::$called[__FUNCTION__] = TRUE;
601		}
602
603		return _strrev($str);
604	}
605
606	/**
607	 * Strips whitespace (or other UTF-8 characters) from the beginning and
608	 * end of a string. This is a UTF8-aware version of [trim](http://php.net/trim).
609	 *
610	 *     $str = UTF8::trim($str);
611	 *
612	 * @author  Andreas Gohr <andi@splitbrain.org>
613	 * @param   string  $str        input string
614	 * @param   string  $charlist   string of characters to remove
615	 * @return  string
616	 */
617	public static function trim($str, $charlist = NULL)
618	{
619		if ( ! isset(self::$called[__FUNCTION__]))
620		{
621			require Kohana::find_file('utf8', __FUNCTION__);
622
623			// Function has been called
624			self::$called[__FUNCTION__] = TRUE;
625		}
626
627		return _trim($str, $charlist);
628	}
629
630	/**
631	 * Strips whitespace (or other UTF-8 characters) from the beginning of
632	 * a string. This is a UTF8-aware version of [ltrim](http://php.net/ltrim).
633	 *
634	 *     $str = UTF8::ltrim($str);
635	 *
636	 * @author  Andreas Gohr <andi@splitbrain.org>
637	 * @param   string  $str        input string
638	 * @param   string  $charlist   string of characters to remove
639	 * @return  string
640	 */
641	public static function ltrim($str, $charlist = NULL)
642	{
643		if ( ! isset(self::$called[__FUNCTION__]))
644		{
645			require Kohana::find_file('utf8', __FUNCTION__);
646
647			// Function has been called
648			self::$called[__FUNCTION__] = TRUE;
649		}
650
651		return _ltrim($str, $charlist);
652	}
653
654	/**
655	 * Strips whitespace (or other UTF-8 characters) from the end of a string.
656	 * This is a UTF8-aware version of [rtrim](http://php.net/rtrim).
657	 *
658	 *     $str = UTF8::rtrim($str);
659	 *
660	 * @author  Andreas Gohr <andi@splitbrain.org>
661	 * @param   string  $str        input string
662	 * @param   string  $charlist   string of characters to remove
663	 * @return  string
664	 */
665	public static function rtrim($str, $charlist = NULL)
666	{
667		if ( ! isset(self::$called[__FUNCTION__]))
668		{
669			require Kohana::find_file('utf8', __FUNCTION__);
670
671			// Function has been called
672			self::$called[__FUNCTION__] = TRUE;
673		}
674
675		return _rtrim($str, $charlist);
676	}
677
678	/**
679	 * Returns the unicode ordinal for a character. This is a UTF8-aware
680	 * version of [ord](http://php.net/ord).
681	 *
682	 *     $digit = UTF8::ord($character);
683	 *
684	 * @author  Harry Fuecks <hfuecks@gmail.com>
685	 * @param   string  $chr    UTF-8 encoded character
686	 * @return  integer
687	 */
688	public static function ord($chr)
689	{
690		if ( ! isset(self::$called[__FUNCTION__]))
691		{
692			require Kohana::find_file('utf8', __FUNCTION__);
693
694			// Function has been called
695			self::$called[__FUNCTION__] = TRUE;
696		}
697
698		return _ord($chr);
699	}
700
701	/**
702	 * Takes an UTF-8 string and returns an array of ints representing the Unicode characters.
703	 * Astral planes are supported i.e. the ints in the output can be > 0xFFFF.
704	 * Occurrences of the BOM are ignored. Surrogates are not allowed.
705	 *
706	 *     $array = UTF8::to_unicode($str);
707	 *
708	 * The Original Code is Mozilla Communicator client code.
709	 * The Initial Developer of the Original Code is Netscape Communications Corporation.
710	 * Portions created by the Initial Developer are Copyright (C) 1998 the Initial Developer.
711	 * Ported to PHP by Henri Sivonen <hsivonen@iki.fi>, see <http://hsivonen.iki.fi/php-utf8/>
712	 * Slight modifications to fit with phputf8 library by Harry Fuecks <hfuecks@gmail.com>
713	 *
714	 * @param   string  $str    UTF-8 encoded string
715	 * @return  array   unicode code points
716	 * @return  FALSE   if the string is invalid
717	 */
718	public static function to_unicode($str)
719	{
720		if ( ! isset(self::$called[__FUNCTION__]))
721		{
722			require Kohana::find_file('utf8', __FUNCTION__);
723
724			// Function has been called
725			self::$called[__FUNCTION__] = TRUE;
726		}
727
728		return _to_unicode($str);
729	}
730
731	/**
732	 * Takes an array of ints representing the Unicode characters and returns a UTF-8 string.
733	 * Astral planes are supported i.e. the ints in the input can be > 0xFFFF.
734	 * Occurrances of the BOM are ignored. Surrogates are not allowed.
735	 *
736	 *     $str = UTF8::to_unicode($array);
737	 *
738	 * The Original Code is Mozilla Communicator client code.
739	 * The Initial Developer of the Original Code is Netscape Communications Corporation.
740	 * Portions created by the Initial Developer are Copyright (C) 1998 the Initial Developer.
741	 * Ported to PHP by Henri Sivonen <hsivonen@iki.fi>, see http://hsivonen.iki.fi/php-utf8/
742	 * Slight modifications to fit with phputf8 library by Harry Fuecks <hfuecks@gmail.com>.
743	 *
744	 * @param   array   $str    unicode code points representing a string
745	 * @return  string  utf8 string of characters
746	 * @return  boolean FALSE if a code point cannot be found
747	 */
748	public static function from_unicode($arr)
749	{
750		if ( ! isset(self::$called[__FUNCTION__]))
751		{
752			require Kohana::find_file('utf8', __FUNCTION__);
753
754			// Function has been called
755			self::$called[__FUNCTION__] = TRUE;
756		}
757
758		return _from_unicode($arr);
759	}
760
761} // End UTF8
762
763if (Kohana_UTF8::$server_utf8 === NULL)
764{
765	// Determine if this server supports UTF-8 natively
766	Kohana_UTF8::$server_utf8 = extension_loaded('mbstring');
767}