PageRenderTime 269ms CodeModel.GetById 121ms app.highlight 67ms RepoModel.GetById 74ms app.codeStats 0ms

/demo/yii/web/helpers/CJSON.php

https://bitbucket.org/dzio/yii-bootstrap
PHP | 704 lines | 429 code | 86 blank | 189 comment | 91 complexity | 175b8f727160688a873544f4872d0e0e MD5 | raw file
  1<?php
  2/**
  3* JSON (JavaScript Object Notation) is a lightweight data-interchange
  4* format. It is easy for humans to read and write. It is easy for machines
  5* to parse and generate. It is based on a subset of the JavaScript
  6* Programming Language, Standard ECMA-262 3rd Edition - December 1999.
  7* This feature can also be found in  Python. JSON is a text format that is
  8* completely language independent but uses conventions that are familiar
  9* to programmers of the C-family of languages, including C, C++, C#, Java,
 10* JavaScript, Perl, TCL, and many others. These properties make JSON an
 11* ideal data-interchange language.
 12*
 13* This package provides a simple encoder and decoder for JSON notation. It
 14* is intended for use with client-side Javascript applications that make
 15* use of HTTPRequest to perform server communication functions - data can
 16* be encoded into JSON notation for use in a client-side javascript, or
 17* decoded from incoming Javascript requests. JSON format is native to
 18* Javascript, and can be directly eval()'ed with no further parsing
 19* overhead
 20*
 21* All strings should be in ASCII or UTF-8 format!
 22*
 23* LICENSE: Redistribution and use in source and binary forms, with or
 24* without modification, are permitted provided that the following
 25* conditions are met: Redistributions of source code must retain the
 26* above copyright notice, this list of conditions and the following
 27* disclaimer. Redistributions in binary form must reproduce the above
 28* copyright notice, this list of conditions and the following disclaimer
 29* in the documentation and/or other materials provided with the
 30* distribution.
 31*
 32* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
 33* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 34* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
 35* NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 36* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 37* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 38* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 39* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
 40* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 41* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
 42* DAMAGE.
 43*
 44* @author	  Michal Migurski <mike-json@teczno.com>
 45* @author	  Matt Knapp <mdknapp[at]gmail[dot]com>
 46* @author	  Brett Stimmerman <brettstimmerman[at]gmail[dot]com>
 47* @copyright   2005 Michal Migurski
 48* @license	 http://www.opensource.org/licenses/bsd-license.php
 49* @link		http://pear.php.net/pepr/pepr-proposal-show.php?id=198
 50*/
 51
 52/**
 53 * CJSON converts PHP data to and from JSON format.
 54 *
 55 * @author	 Michal Migurski <mike-json@teczno.com>
 56 * @author	 Matt Knapp <mdknapp[at]gmail[dot]com>
 57 * @author	 Brett Stimmerman <brettstimmerman[at]gmail[dot]com>
 58 * @version $Id: CJSON.php 3204 2011-05-05 21:36:32Z alexander.makarow $
 59 * @package	system.web.helpers
 60 * @since 1.0
 61 */
 62class CJSON
 63{
 64	/**
 65	 * Marker constant for JSON::decode(), used to flag stack state
 66	 */
 67	const JSON_SLICE = 1;
 68
 69	/**
 70	* Marker constant for JSON::decode(), used to flag stack state
 71	*/
 72	const JSON_IN_STR = 2;
 73
 74	/**
 75	* Marker constant for JSON::decode(), used to flag stack state
 76	*/
 77	const JSON_IN_ARR = 4;
 78
 79	/**
 80	* Marker constant for JSON::decode(), used to flag stack state
 81	*/
 82	const JSON_IN_OBJ = 8;
 83
 84	/**
 85	* Marker constant for JSON::decode(), used to flag stack state
 86	*/
 87	const JSON_IN_CMT = 16;
 88
 89   /**
 90	* Encodes an arbitrary variable into JSON format
 91	*
 92	* @param mixed $var any number, boolean, string, array, or object to be encoded.
 93	* If var is a string, it will be converted to UTF-8 format first before being encoded.
 94	* @return string JSON string representation of input var
 95	*/
 96	public static function encode($var)
 97	{
 98		switch (gettype($var)) {
 99			case 'boolean':
100				return $var ? 'true' : 'false';
101
102			case 'NULL':
103				return 'null';
104
105			case 'integer':
106				return (int) $var;
107
108			case 'double':
109			case 'float':
110				return str_replace(',','.',(float)$var); // locale-independent representation
111
112			case 'string':
113				if (($enc=strtoupper(Yii::app()->charset))!=='UTF-8')
114					$var=iconv($enc, 'UTF-8', $var);
115
116				if(function_exists('json_encode'))
117					return json_encode($var);
118
119				// STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT
120				$ascii = '';
121				$strlen_var = strlen($var);
122
123			   /*
124				* Iterate over every character in the string,
125				* escaping with a slash or encoding to UTF-8 where necessary
126				*/
127				for ($c = 0; $c < $strlen_var; ++$c) {
128
129					$ord_var_c = ord($var{$c});
130
131					switch (true) {
132						case $ord_var_c == 0x08:
133							$ascii .= '\b';
134							break;
135						case $ord_var_c == 0x09:
136							$ascii .= '\t';
137							break;
138						case $ord_var_c == 0x0A:
139							$ascii .= '\n';
140							break;
141						case $ord_var_c == 0x0C:
142							$ascii .= '\f';
143							break;
144						case $ord_var_c == 0x0D:
145							$ascii .= '\r';
146							break;
147
148						case $ord_var_c == 0x22:
149						case $ord_var_c == 0x2F:
150						case $ord_var_c == 0x5C:
151							// double quote, slash, slosh
152							$ascii .= '\\'.$var{$c};
153							break;
154
155						case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
156							// characters U-00000000 - U-0000007F (same as ASCII)
157							$ascii .= $var{$c};
158							break;
159
160						case (($ord_var_c & 0xE0) == 0xC0):
161							// characters U-00000080 - U-000007FF, mask 110XXXXX
162							// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
163							$char = pack('C*', $ord_var_c, ord($var{$c+1}));
164							$c+=1;
165							$utf16 =  self::utf8ToUTF16BE($char);
166							$ascii .= sprintf('\u%04s', bin2hex($utf16));
167							break;
168
169						case (($ord_var_c & 0xF0) == 0xE0):
170							// characters U-00000800 - U-0000FFFF, mask 1110XXXX
171							// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
172							$char = pack('C*', $ord_var_c,
173										 ord($var{$c+1}),
174										 ord($var{$c+2}));
175							$c+=2;
176							$utf16 = self::utf8ToUTF16BE($char);
177							$ascii .= sprintf('\u%04s', bin2hex($utf16));
178							break;
179
180						case (($ord_var_c & 0xF8) == 0xF0):
181							// characters U-00010000 - U-001FFFFF, mask 11110XXX
182							// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
183							$char = pack('C*', $ord_var_c,
184										 ord($var{$c+1}),
185										 ord($var{$c+2}),
186										 ord($var{$c+3}));
187							$c+=3;
188							$utf16 = self::utf8ToUTF16BE($char);
189							$ascii .= sprintf('\u%04s', bin2hex($utf16));
190							break;
191
192						case (($ord_var_c & 0xFC) == 0xF8):
193							// characters U-00200000 - U-03FFFFFF, mask 111110XX
194							// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
195							$char = pack('C*', $ord_var_c,
196										 ord($var{$c+1}),
197										 ord($var{$c+2}),
198										 ord($var{$c+3}),
199										 ord($var{$c+4}));
200							$c+=4;
201							$utf16 = self::utf8ToUTF16BE($char);
202							$ascii .= sprintf('\u%04s', bin2hex($utf16));
203							break;
204
205						case (($ord_var_c & 0xFE) == 0xFC):
206							// characters U-04000000 - U-7FFFFFFF, mask 1111110X
207							// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
208							$char = pack('C*', $ord_var_c,
209										 ord($var{$c+1}),
210										 ord($var{$c+2}),
211										 ord($var{$c+3}),
212										 ord($var{$c+4}),
213										 ord($var{$c+5}));
214							$c+=5;
215							$utf16 = self::utf8ToUTF16BE($char);
216							$ascii .= sprintf('\u%04s', bin2hex($utf16));
217							break;
218					}
219				}
220
221				return '"'.$ascii.'"';
222
223			case 'array':
224			   /*
225				* As per JSON spec if any array key is not an integer
226				* we must treat the the whole array as an object. We
227				* also try to catch a sparsely populated associative
228				* array with numeric keys here because some JS engines
229				* will create an array with empty indexes up to
230				* max_index which can cause memory issues and because
231				* the keys, which may be relevant, will be remapped
232				* otherwise.
233				*
234				* As per the ECMA and JSON specification an object may
235				* have any string as a property. Unfortunately due to
236				* a hole in the ECMA specification if the key is a
237				* ECMA reserved word or starts with a digit the
238				* parameter is only accessible using ECMAScript's
239				* bracket notation.
240				*/
241
242				// treat as a JSON object
243				if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) {
244					return '{' .
245						   join(',', array_map(array('CJSON', 'nameValue'),
246											   array_keys($var),
247											   array_values($var)))
248						   . '}';
249				}
250
251				// treat it like a regular array
252				return '[' . join(',', array_map(array('CJSON', 'encode'), $var)) . ']';
253
254			case 'object':
255				if ($var instanceof Traversable)
256				{
257					$vars = array();
258					foreach ($var as $k=>$v)
259						$vars[$k] = $v;
260				}
261				else
262					$vars = get_object_vars($var);
263				return '{' .
264					   join(',', array_map(array('CJSON', 'nameValue'),
265										   array_keys($vars),
266										   array_values($vars)))
267					   . '}';
268
269			default:
270				return '';
271		}
272	}
273
274   /**
275	* array-walking function for use in generating JSON-formatted name-value pairs
276	*
277	* @param string $name  name of key to use
278	* @param mixed $value reference to an array element to be encoded
279	*
280	* @return   string  JSON-formatted name-value pair, like '"name":value'
281	* @access   private
282	*/
283	protected static function nameValue($name, $value)
284	{
285		return self::encode(strval($name)) . ':' . self::encode($value);
286	}
287
288   /**
289	* reduce a string by removing leading and trailing comments and whitespace
290	*
291	* @param string $str string value to strip of comments and whitespace
292	*
293	* @return string string value stripped of comments and whitespace
294	* @access   private
295	*/
296	protected static function reduceString($str)
297	{
298		$str = preg_replace(array(
299
300				// eliminate single line comments in '// ...' form
301				'#^\s*//(.+)$#m',
302
303				// eliminate multi-line comments in '/* ... */' form, at start of string
304				'#^\s*/\*(.+)\*/#Us',
305
306				// eliminate multi-line comments in '/* ... */' form, at end of string
307				'#/\*(.+)\*/\s*$#Us'
308
309			), '', $str);
310
311		// eliminate extraneous space
312		return trim($str);
313	}
314
315   /**
316	* decodes a JSON string into appropriate variable
317	*
318	* @param string $str  JSON-formatted string
319	* @param boolean $useArray  whether to use associative array to represent object data
320	* @return mixed   number, boolean, string, array, or object corresponding to given JSON input string.
321	*    Note that decode() always returns strings in ASCII or UTF-8 format!
322	* @access   public
323	*/
324	public static function decode($str, $useArray=true)
325	{
326		if(function_exists('json_decode'))
327			return json_decode($str,$useArray);
328
329		$str = self::reduceString($str);
330
331		switch (strtolower($str)) {
332			case 'true':
333				return true;
334
335			case 'false':
336				return false;
337
338			case 'null':
339				return null;
340
341			default:
342				if (is_numeric($str)) {
343					// Lookie-loo, it's a number
344
345					// This would work on its own, but I'm trying to be
346					// good about returning integers where appropriate:
347					// return (float)$str;
348
349					// Return float or int, as appropriate
350					return ((float)$str == (integer)$str)
351						? (integer)$str
352						: (float)$str;
353
354				} elseif (preg_match('/^("|\').+(\1)$/s', $str, $m) && $m[1] == $m[2]) {
355					// STRINGS RETURNED IN UTF-8 FORMAT
356					$delim = substr($str, 0, 1);
357					$chrs = substr($str, 1, -1);
358					$utf8 = '';
359					$strlen_chrs = strlen($chrs);
360
361					for ($c = 0; $c < $strlen_chrs; ++$c) {
362
363						$substr_chrs_c_2 = substr($chrs, $c, 2);
364						$ord_chrs_c = ord($chrs{$c});
365
366						switch (true) {
367							case $substr_chrs_c_2 == '\b':
368								$utf8 .= chr(0x08);
369								++$c;
370								break;
371							case $substr_chrs_c_2 == '\t':
372								$utf8 .= chr(0x09);
373								++$c;
374								break;
375							case $substr_chrs_c_2 == '\n':
376								$utf8 .= chr(0x0A);
377								++$c;
378								break;
379							case $substr_chrs_c_2 == '\f':
380								$utf8 .= chr(0x0C);
381								++$c;
382								break;
383							case $substr_chrs_c_2 == '\r':
384								$utf8 .= chr(0x0D);
385								++$c;
386								break;
387
388							case $substr_chrs_c_2 == '\\"':
389							case $substr_chrs_c_2 == '\\\'':
390							case $substr_chrs_c_2 == '\\\\':
391							case $substr_chrs_c_2 == '\\/':
392								if (($delim == '"' && $substr_chrs_c_2 != '\\\'') ||
393								   ($delim == "'" && $substr_chrs_c_2 != '\\"')) {
394									$utf8 .= $chrs{++$c};
395								}
396								break;
397
398							case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)):
399								// single, escaped unicode character
400								$utf16 = chr(hexdec(substr($chrs, ($c+2), 2)))
401									   . chr(hexdec(substr($chrs, ($c+4), 2)));
402								$utf8 .= self::utf16beToUTF8($utf16);
403								$c+=5;
404								break;
405
406							case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F):
407								$utf8 .= $chrs{$c};
408								break;
409
410							case ($ord_chrs_c & 0xE0) == 0xC0:
411								// characters U-00000080 - U-000007FF, mask 110XXXXX
412								//see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
413								$utf8 .= substr($chrs, $c, 2);
414								++$c;
415								break;
416
417							case ($ord_chrs_c & 0xF0) == 0xE0:
418								// characters U-00000800 - U-0000FFFF, mask 1110XXXX
419								// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
420								$utf8 .= substr($chrs, $c, 3);
421								$c += 2;
422								break;
423
424							case ($ord_chrs_c & 0xF8) == 0xF0:
425								// characters U-00010000 - U-001FFFFF, mask 11110XXX
426								// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
427								$utf8 .= substr($chrs, $c, 4);
428								$c += 3;
429								break;
430
431							case ($ord_chrs_c & 0xFC) == 0xF8:
432								// characters U-00200000 - U-03FFFFFF, mask 111110XX
433								// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
434								$utf8 .= substr($chrs, $c, 5);
435								$c += 4;
436								break;
437
438							case ($ord_chrs_c & 0xFE) == 0xFC:
439								// characters U-04000000 - U-7FFFFFFF, mask 1111110X
440								// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
441								$utf8 .= substr($chrs, $c, 6);
442								$c += 5;
443								break;
444
445						}
446
447					}
448
449					return $utf8;
450
451				} elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) {
452					// array, or object notation
453
454					if ($str{0} == '[') {
455						$stk = array(self::JSON_IN_ARR);
456						$arr = array();
457					} else {
458						if ($useArray) {
459							$stk = array(self::JSON_IN_OBJ);
460							$obj = array();
461						} else {
462							$stk = array(self::JSON_IN_OBJ);
463							$obj = new stdClass();
464						}
465					}
466
467					array_push($stk, array('what'  => self::JSON_SLICE,
468										   'where' => 0,
469										   'delim' => false));
470
471					$chrs = substr($str, 1, -1);
472					$chrs = self::reduceString($chrs);
473
474					if ($chrs == '') {
475						if (reset($stk) == self::JSON_IN_ARR) {
476							return $arr;
477
478						} else {
479							return $obj;
480
481						}
482					}
483
484					//print("\nparsing {$chrs}\n");
485
486					$strlen_chrs = strlen($chrs);
487
488					for ($c = 0; $c <= $strlen_chrs; ++$c) {
489
490						$top = end($stk);
491						$substr_chrs_c_2 = substr($chrs, $c, 2);
492
493						if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == self::JSON_SLICE))) {
494							// found a comma that is not inside a string, array, etc.,
495							// OR we've reached the end of the character list
496							$slice = substr($chrs, $top['where'], ($c - $top['where']));
497							array_push($stk, array('what' => self::JSON_SLICE, 'where' => ($c + 1), 'delim' => false));
498							//print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
499
500							if (reset($stk) == self::JSON_IN_ARR) {
501								// we are in an array, so just push an element onto the stack
502								array_push($arr, self::decode($slice,$useArray));
503
504							} elseif (reset($stk) == self::JSON_IN_OBJ) {
505								// we are in an object, so figure
506								// out the property name and set an
507								// element in an associative array,
508								// for now
509								if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
510									// "name":value pair
511									$key = self::decode($parts[1],$useArray);
512									$val = self::decode($parts[2],$useArray);
513
514									if ($useArray) {
515										$obj[$key] = $val;
516									} else {
517										$obj->$key = $val;
518									}
519								} elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
520									// name:value pair, where name is unquoted
521									$key = $parts[1];
522									$val = self::decode($parts[2],$useArray);
523
524									if ($useArray) {
525										$obj[$key] = $val;
526									} else {
527										$obj->$key = $val;
528									}
529								}
530
531							}
532
533						} elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != self::JSON_IN_STR)) {
534							// found a quote, and we are not inside a string
535							array_push($stk, array('what' => self::JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c}));
536							//print("Found start of string at {$c}\n");
537
538						} elseif (($chrs{$c} == $top['delim']) &&
539								 ($top['what'] == self::JSON_IN_STR) &&
540								 (($chrs{$c - 1} != "\\") ||
541								 ($chrs{$c - 1} == "\\" && $chrs{$c - 2} == "\\"))) {
542							// found a quote, we're in a string, and it's not escaped
543							array_pop($stk);
544							//print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n");
545
546						} elseif (($chrs{$c} == '[') &&
547								 in_array($top['what'], array(self::JSON_SLICE, self::JSON_IN_ARR, self::JSON_IN_OBJ))) {
548							// found a left-bracket, and we are in an array, object, or slice
549							array_push($stk, array('what' => self::JSON_IN_ARR, 'where' => $c, 'delim' => false));
550							//print("Found start of array at {$c}\n");
551
552						} elseif (($chrs{$c} == ']') && ($top['what'] == self::JSON_IN_ARR)) {
553							// found a right-bracket, and we're in an array
554							array_pop($stk);
555							//print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
556
557						} elseif (($chrs{$c} == '{') &&
558								 in_array($top['what'], array(self::JSON_SLICE, self::JSON_IN_ARR, self::JSON_IN_OBJ))) {
559							// found a left-brace, and we are in an array, object, or slice
560							array_push($stk, array('what' => self::JSON_IN_OBJ, 'where' => $c, 'delim' => false));
561							//print("Found start of object at {$c}\n");
562
563						} elseif (($chrs{$c} == '}') && ($top['what'] == self::JSON_IN_OBJ)) {
564							// found a right-brace, and we're in an object
565							array_pop($stk);
566							//print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
567
568						} elseif (($substr_chrs_c_2 == '/*') &&
569								 in_array($top['what'], array(self::JSON_SLICE, self::JSON_IN_ARR, self::JSON_IN_OBJ))) {
570							// found a comment start, and we are in an array, object, or slice
571							array_push($stk, array('what' => self::JSON_IN_CMT, 'where' => $c, 'delim' => false));
572							$c++;
573							//print("Found start of comment at {$c}\n");
574
575						} elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == self::JSON_IN_CMT)) {
576							// found a comment end, and we're in one now
577							array_pop($stk);
578							$c++;
579
580							for ($i = $top['where']; $i <= $c; ++$i)
581								$chrs = substr_replace($chrs, ' ', $i, 1);
582
583							//print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
584
585						}
586
587					}
588
589					if (reset($stk) == self::JSON_IN_ARR) {
590						return $arr;
591
592					} elseif (reset($stk) == self::JSON_IN_OBJ) {
593						return $obj;
594
595					}
596
597				}
598		}
599	}
600
601	/**
602	* This function returns any UTF-8 encoded text as a list of
603	* Unicode values:
604	* @param string $str string to convert
605	* @return string
606	* @author Scott Michael Reynen <scott@randomchaos.com>
607	* @link   http://www.randomchaos.com/document.php?source=php_and_unicode
608	* @see	unicodeToUTF8()
609	*/
610	protected static function utf8ToUnicode( &$str )
611	{
612		$unicode = array();
613		$values = array();
614		$lookingFor = 1;
615
616		for ($i = 0; $i < strlen( $str ); $i++ )
617		{
618			$thisValue = ord( $str[ $i ] );
619			if ( $thisValue < 128 )
620				$unicode[] = $thisValue;
621			else
622			{
623				if ( count( $values ) == 0 )
624					$lookingFor = ( $thisValue < 224 ) ? 2 : 3;
625				$values[] = $thisValue;
626				if ( count( $values ) == $lookingFor )
627				{
628					$number = ( $lookingFor == 3 ) ?
629						( ( $values[0] % 16 ) * 4096 ) + ( ( $values[1] % 64 ) * 64 ) + ( $values[2] % 64 ):
630						( ( $values[0] % 32 ) * 64 ) + ( $values[1] % 64 );
631					$unicode[] = $number;
632					$values = array();
633					$lookingFor = 1;
634				}
635			}
636		}
637		return $unicode;
638	}
639
640	/**
641	* This function converts a Unicode array back to its UTF-8 representation
642	* @param string $str string to convert
643	* @return string
644	* @author Scott Michael Reynen <scott@randomchaos.com>
645	* @link   http://www.randomchaos.com/document.php?source=php_and_unicode
646	* @see	utf8ToUnicode()
647	*/
648	protected static function unicodeToUTF8( &$str )
649	{
650		$utf8 = '';
651		foreach( $str as $unicode )
652		{
653			if ( $unicode < 128 )
654			{
655				$utf8.= chr( $unicode );
656			}
657			elseif ( $unicode < 2048 )
658			{
659				$utf8.= chr( 192 +  ( ( $unicode - ( $unicode % 64 ) ) / 64 ) );
660				$utf8.= chr( 128 + ( $unicode % 64 ) );
661			}
662			else
663			{
664				$utf8.= chr( 224 + ( ( $unicode - ( $unicode % 4096 ) ) / 4096 ) );
665				$utf8.= chr( 128 + ( ( ( $unicode % 4096 ) - ( $unicode % 64 ) ) / 64 ) );
666				$utf8.= chr( 128 + ( $unicode % 64 ) );
667			}
668		}
669		return $utf8;
670	}
671
672	/**
673	* UTF-8 to UTF-16BE conversion.
674	*
675	* Maybe really UCS-2 without mb_string due to utf8ToUnicode limits
676	* @param string $str string to convert
677	* @param boolean $bom whether to output BOM header
678	* @return string
679	*/
680	protected static function utf8ToUTF16BE(&$str, $bom = false)
681	{
682		$out = $bom ? "\xFE\xFF" : '';
683		if(function_exists('mb_convert_encoding'))
684			return $out.mb_convert_encoding($str,'UTF-16BE','UTF-8');
685
686		$uni = self::utf8ToUnicode($str);
687		foreach($uni as $cp)
688			$out .= pack('n',$cp);
689		return $out;
690	}
691
692	/**
693	 * UTF-8 to UTF-16BE conversion.
694	 *
695	 * Maybe really UCS-2 without mb_string due to utf8ToUnicode limits
696	 * @param string $str string to convert
697	 * @return string
698	 */
699	protected static function utf16beToUTF8(&$str)
700	{
701		$uni = unpack('n*',$str);
702		return self::unicodeToUTF8($uni);
703	}
704}