dolibarr  19.0.0-dev
json.lib.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2011-2012 Laurent Destailleur <eldy@users.sourceforge.net>
3  * Copyright (C) 2011-2012 Regis Houssin <regis.houssin@inodbox.com>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <https://www.gnu.org/licenses/>.
17  * or see https://www.gnu.org/
18  */
19 
26 if (!function_exists('json_encode')) {
33  function json_encode($elements)
34  {
35  return dol_json_encode($elements);
36  }
37 }
38 
39 
50 function dol_json_encode($elements)
51 {
52  dol_syslog("For better performance, enable the native json in your PHP", LOG_WARNING);
53 
54  $num = 0;
55  if (is_object($elements)) { // Count number of properties for an object
56  foreach ($elements as $key => $value) {
57  $num++;
58  }
59  } else {
60  $num = count($elements);
61  }
62  //var_dump($num);
63 
64  // determine type
65  if (is_numeric(key($elements)) && key($elements) == 0) {
66  // indexed (list)
67  $keysofelements = array_keys($elements); // Elements array mus have key that does not start with 0 and end with num-1, so we will use this later.
68  $output = '[';
69  for ($i = 0, $last = ($num - 1); $i < $num; $i++) {
70  if (!isset($elements[$keysofelements[$i]])) {
71  continue;
72  }
73  if (is_array($elements[$keysofelements[$i]]) || is_object($elements[$keysofelements[$i]])) {
74  $output .= json_encode($elements[$keysofelements[$i]]);
75  } else {
76  $output .= _val($elements[$keysofelements[$i]]);
77  }
78  if ($i !== $last) {
79  $output .= ',';
80  }
81  }
82  $output .= ']';
83  } else {
84  // associative (object)
85  $output = '{';
86  $last = $num - 1;
87  $i = 0;
88  $tmpelements = array();
89  if (is_array($elements)) {
90  $tmpelements = $elements;
91  }
92  if (is_object($elements)) {
93  $tmpelements = get_object_vars($elements);
94  }
95  foreach ($tmpelements as $key => $value) {
96  $output .= '"'.$key.'":';
97  if (is_array($value)) {
98  $output .= json_encode($value);
99  } else {
100  $output .= _val($value);
101  }
102  if ($i !== $last) {
103  $output .= ',';
104  }
105  ++$i;
106  }
107  $output .= '}';
108  }
109 
110  // return
111  return $output;
112 }
113 
120 function _val($val)
121 {
122  if (is_string($val)) {
123  // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT
124  $ascii = '';
125  $strlen_var = strlen($val);
126 
127  /*
128  * Iterate over every character in the string,
129  * escaping with a slash or encoding to UTF-8 where necessary
130  */
131  for ($c = 0; $c < $strlen_var; ++$c) {
132  $ord_var_c = ord($val[$c]);
133 
134  switch (true) {
135  case $ord_var_c == 0x08:
136  $ascii .= '\b';
137  break;
138  case $ord_var_c == 0x09:
139  $ascii .= '\t';
140  break;
141  case $ord_var_c == 0x0A:
142  $ascii .= '\n';
143  break;
144  case $ord_var_c == 0x0C:
145  $ascii .= '\f';
146  break;
147  case $ord_var_c == 0x0D:
148  $ascii .= '\r';
149  break;
150 
151  case $ord_var_c == 0x22:
152  case $ord_var_c == 0x2F:
153  case $ord_var_c == 0x5C:
154  // double quote, slash, slosh
155  $ascii .= '\\'.$val[$c];
156  break;
157 
158  case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
159  // characters U-00000000 - U-0000007F (same as ASCII)
160  $ascii .= $val[$c];
161  break;
162 
163  case (($ord_var_c & 0xE0) == 0xC0):
164  // characters U-00000080 - U-000007FF, mask 110XXXXX
165  // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
166  $char = pack('C*', $ord_var_c, ord($val[$c + 1]));
167  $c += 1;
168  $utf16 = utf82utf16($char);
169  $ascii .= sprintf('\u%04s', bin2hex($utf16));
170  break;
171 
172  case (($ord_var_c & 0xF0) == 0xE0):
173  // characters U-00000800 - U-0000FFFF, mask 1110XXXX
174  // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
175  $char = pack('C*', $ord_var_c, ord($val[$c + 1]), ord($val[$c + 2]));
176  $c += 2;
177  $utf16 = utf82utf16($char);
178  $ascii .= sprintf('\u%04s', bin2hex($utf16));
179  break;
180 
181  case (($ord_var_c & 0xF8) == 0xF0):
182  // characters U-00010000 - U-001FFFFF, mask 11110XXX
183  // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
184  $char = pack('C*', $ord_var_c, ord($val[$c + 1]), ord($val[$c + 2]), ord($val[$c + 3]));
185  $c += 3;
186  $utf16 = utf82utf16($char);
187  $ascii .= sprintf('\u%04s', bin2hex($utf16));
188  break;
189 
190  case (($ord_var_c & 0xFC) == 0xF8):
191  // characters U-00200000 - U-03FFFFFF, mask 111110XX
192  // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
193  $char = pack('C*', $ord_var_c, ord($val[$c + 1]), ord($val[$c + 2]), ord($val[$c + 3]), ord($val[$c + 4]));
194  $c += 4;
195  $utf16 = utf82utf16($char);
196  $ascii .= sprintf('\u%04s', bin2hex($utf16));
197  break;
198 
199  case (($ord_var_c & 0xFE) == 0xFC):
200  // characters U-04000000 - U-7FFFFFFF, mask 1111110X
201  // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
202  $char = pack('C*', $ord_var_c, ord($val[$c + 1]), ord($val[$c + 2]), ord($val[$c + 3]), ord($val[$c + 4]), ord($val[$c + 5]));
203  $c += 5;
204  $utf16 = utf82utf16($char);
205  $ascii .= sprintf('\u%04s', bin2hex($utf16));
206  break;
207  }
208  }
209 
210  return '"'.$ascii.'"';
211  } elseif (is_int($val)) {
212  return sprintf('%d', $val);
213  } elseif (is_float($val)) {
214  return sprintf('%F', $val);
215  } elseif (is_bool($val)) {
216  return ($val ? 'true' : 'false');
217  } else {
218  return 'null';
219  }
220 }
221 
222 if (!function_exists('json_decode')) {
230  function json_decode($json, $assoc = false)
231  {
232  return dol_json_decode($json, $assoc);
233  }
234 }
235 
245 function dol_json_decode($json, $assoc = false)
246 {
247  dol_syslog("For better performance, enable the native json in your PHP", LOG_WARNING);
248 
249  $comment = false;
250 
251  $out = '';
252  $strLength = strlen($json); // Must stay strlen and not dol_strlen because we want technical length, not visible length
253  for ($i = 0; $i < $strLength; $i++) {
254  if (!$comment) {
255  if (($json[$i] == '{') || ($json[$i] == '[')) {
256  $out .= 'array(';
257  } elseif (($json[$i] == '}') || ($json[$i] == ']')) {
258  $out .= ')';
259  } elseif ($json[$i] == ':') {
260  $out .= ' => ';
261  } else {
262  $out .= $json[$i];
263  }
264  } else {
265  $out .= $json[$i];
266  }
267  if ($json[$i] == '"' && $json[($i - 1)] != "\\") {
268  $comment = !$comment;
269  }
270  }
271 
272  $out = _unval($out);
273 
274  $array = array();
275 
276  // Return an array
277  if ($out != '') {
278  try {
279  eval('$array = '.$out.';');
280  } catch (Exception $e) {
281  $array = array();
282  }
283  }
284 
285  // Return an object
286  if (!$assoc) {
287  if (!empty($array)) {
288  $object = false;
289  if (count($array) > 0) {
290  $object = (object) array();
291  }
292  foreach ($array as $key => $value) {
293  if ($key) {
294  $object->{$key} = $value;
295  }
296  }
297 
298  return $object;
299  }
300 
301  return false;
302  }
303 
304  return $array;
305 }
306 
313 function _unval($val)
314 {
315  $reg = array();
316  while (preg_match('/\\\u([0-9A-F]{2})([0-9A-F]{2})/i', $val, $reg)) {
317  // single, escaped unicode character
318  $utf16 = chr(hexdec($reg[1])).chr(hexdec($reg[2]));
319  $utf8 = utf162utf8($utf16);
320  $val = preg_replace('/\\\u'.$reg[1].$reg[2].'/i', $utf8, $val);
321  }
322  return $val;
323 }
324 
335 function utf162utf8($utf16)
336 {
337  // oh please oh please oh please oh please oh please
338  if (function_exists('mb_convert_encoding')) {
339  return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16');
340  }
341 
342  $bytes = (ord($utf16[0]) << 8) | ord($utf16[1]);
343 
344  switch (true) {
345  case ((0x7F & $bytes) == $bytes):
346  // this case should never be reached, because we are in ASCII range
347  // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
348  return chr($bytes);
349 
350  case (0x07FF & $bytes) == $bytes:
351  // return a 2-byte UTF-8 character
352  // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
353  return chr(0xC0 | (($bytes >> 6) & 0x1F))
354  . chr(0x80 | ($bytes & 0x3F));
355 
356  case (0xFFFF & $bytes) == $bytes:
357  // return a 3-byte UTF-8 character
358  // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
359  return chr(0xE0 | (($bytes >> 12) & 0x0F))
360  . chr(0x80 | (($bytes >> 6) & 0x3F))
361  . chr(0x80 | ($bytes & 0x3F));
362  }
363 
364  // ignoring UTF-32 for now, sorry
365  return '';
366 }
367 
378 function utf82utf16($utf8)
379 {
380  // oh please oh please oh please oh please oh please
381  if (function_exists('mb_convert_encoding')) {
382  return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8');
383  }
384 
385  switch (strlen($utf8)) {
386  case 1:
387  // this case should never be reached, because we are in ASCII range
388  // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
389  return $utf8;
390 
391  case 2:
392  // return a UTF-16 character from a 2-byte UTF-8 char
393  // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
394  return chr(0x07 & (ord($utf8[0]) >> 2)).chr((0xC0 & (ord($utf8[0]) << 6)) | (0x3F & ord($utf8[1])));
395 
396  case 3:
397  // return a UTF-16 character from a 3-byte UTF-8 char
398  // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
399  return chr((0xF0 & (ord($utf8[0]) << 4)) | (0x0F & (ord($utf8[1]) >> 2))).chr((0xC0 & (ord($utf8[1]) << 6)) | (0x7F & ord($utf8[2])));
400  }
401 
402  // ignoring UTF-32 for now, sorry
403  return '';
404 }
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
_val($val)
Return text according to type.
Definition: json.lib.php:120
if(!function_exists('json_decode')) dol_json_decode($json, $assoc=false)
Implement json_decode for PHP that does not support it Use json_encode and json_decode in your code !
Definition: json.lib.php:245
utf162utf8($utf16)
Convert a string from one UTF-16 char to one UTF-8 char.
Definition: json.lib.php:335
_unval($val)
Return text according to type.
Definition: json.lib.php:313
if(!function_exists('json_encode')) dol_json_encode($elements)
Implement json_encode for PHP that does not support it.
Definition: json.lib.php:50
utf82utf16($utf8)
Convert a string from one UTF-8 char to one UTF-16 char.
Definition: json.lib.php:378