dolibarr 20.0.2
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 * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
5 * Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 * or see https://www.gnu.org/
20 */
21
28if (!function_exists('json_encode') || defined('PHPUNIT_MODE')) {
40 function dol_json_encode($elements)
41 {
42 dol_syslog("For better performance, enable the native json in your PHP", LOG_WARNING);
43
44 $num = 0;
45 if (is_object($elements)) { // Count number of properties for an object
46 foreach ($elements as $key => $value) {
47 $num++;
48 }
49 } else {
50 if (is_countable($elements)) {
51 $num = count($elements);
52 }
53 }
54
55 // determine type
56 if (is_numeric($elements)) {
57 return $elements;
58 } elseif (is_string($elements)) {
59 return '"'.$elements.'"';
60 }
61 if (is_numeric(key($elements)) && key($elements) == 0) {
62 // indexed (list)
63 $keysofelements = array_keys($elements); // Elements array must have key that does not start with 0 and end with num-1, so we will use this later.
64 $output = '[';
65 for ($i = 0, $last = ($num - 1); $i < $num; $i++) {
66 if (!isset($elements[$keysofelements[$i]])) {
67 continue;
68 }
69 if (is_array($elements[$keysofelements[$i]]) || is_object($elements[$keysofelements[$i]])) {
70 $output .= json_encode($elements[$keysofelements[$i]]);
71 } else {
72 $output .= _val($elements[$keysofelements[$i]]);
73 }
74 if ($i !== $last) {
75 $output .= ',';
76 }
77 }
78 $output .= ']';
79 } else {
80 // associative (object)
81 $output = '{';
82 $last = $num - 1;
83 $i = 0;
84 $tmpelements = array();
85 if (is_array($elements)) {
86 $tmpelements = $elements;
87 }
88 if (is_object($elements)) {
89 $tmpelements = get_object_vars($elements);
90 }
91 foreach ($tmpelements as $key => $value) {
92 $output .= '"'.$key.'":';
93 if (is_array($value)) {
94 $output .= json_encode($value);
95 } else {
96 $output .= _val($value);
97 }
98 if ($i !== $last) {
99 $output .= ',';
100 }
101 ++$i;
102 }
103 $output .= '}';
104 }
105
106 // return
107 return $output;
108 }
109
116 function _val($val)
117 {
118 if (is_string($val)) {
119 // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT
120 $ascii = '';
121 $strlen_var = strlen($val);
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 $ord_var_c = ord($val[$c]);
129
130 switch (true) {
131 case $ord_var_c == 0x08:
132 $ascii .= '\b';
133 break;
134 case $ord_var_c == 0x09:
135 $ascii .= '\t';
136 break;
137 case $ord_var_c == 0x0A:
138 $ascii .= '\n';
139 break;
140 case $ord_var_c == 0x0C:
141 $ascii .= '\f';
142 break;
143 case $ord_var_c == 0x0D:
144 $ascii .= '\r';
145 break;
146
147 case $ord_var_c == 0x22:
148 case $ord_var_c == 0x2F:
149 case $ord_var_c == 0x5C:
150 // double quote, slash, slosh
151 $ascii .= '\\'.$val[$c];
152 break;
153
154 case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
155 // characters U-00000000 - U-0000007F (same as ASCII)
156 $ascii .= $val[$c];
157 break;
158
159 case (($ord_var_c & 0xE0) == 0xC0):
160 // characters U-00000080 - U-000007FF, mask 110XXXXX
161 // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
162 $char = pack('C*', $ord_var_c, ord($val[$c + 1]));
163 $c += 1;
164 $utf16 = utf82utf16($char);
165 $ascii .= sprintf('\u%04s', bin2hex($utf16));
166 break;
167
168 case (($ord_var_c & 0xF0) == 0xE0):
169 // characters U-00000800 - U-0000FFFF, mask 1110XXXX
170 // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
171 $char = pack('C*', $ord_var_c, ord($val[$c + 1]), ord($val[$c + 2]));
172 $c += 2;
173 $utf16 = utf82utf16($char);
174 $ascii .= sprintf('\u%04s', bin2hex($utf16));
175 break;
176
177 case (($ord_var_c & 0xF8) == 0xF0):
178 // characters U-00010000 - U-001FFFFF, mask 11110XXX
179 // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
180 $char = pack('C*', $ord_var_c, ord($val[$c + 1]), ord($val[$c + 2]), ord($val[$c + 3]));
181 $c += 3;
182 $utf16 = utf82utf16($char);
183 $ascii .= sprintf('\u%04s', bin2hex($utf16));
184 break;
185
186 case (($ord_var_c & 0xFC) == 0xF8):
187 // characters U-00200000 - U-03FFFFFF, mask 111110XX
188 // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
189 $char = pack('C*', $ord_var_c, ord($val[$c + 1]), ord($val[$c + 2]), ord($val[$c + 3]), ord($val[$c + 4]));
190 $c += 4;
191 $utf16 = utf82utf16($char);
192 $ascii .= sprintf('\u%04s', bin2hex($utf16));
193 break;
194
195 case (($ord_var_c & 0xFE) == 0xFC):
196 // characters U-04000000 - U-7FFFFFFF, mask 1111110X
197 // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
198 $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]));
199 $c += 5;
200 $utf16 = utf82utf16($char);
201 $ascii .= sprintf('\u%04s', bin2hex($utf16));
202 break;
203 }
204 }
205
206 return '"'.$ascii.'"';
207 } elseif (is_int($val)) {
208 return sprintf('%d', $val);
209 } elseif (is_float($val)) {
210 return sprintf('%F', $val);
211 } elseif (is_bool($val)) {
212 return ($val ? 'true' : 'false');
213 } else {
214 return 'null';
215 }
216 }
217
218
229 function utf82utf16($utf8)
230 {
231 // oh please oh please oh please oh please oh please
232 if (function_exists('mb_convert_encoding')) {
233 return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8');
234 }
235
236 switch (strlen($utf8)) {
237 case 1:
238 // this case should never be reached, because we are in ASCII range
239 // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
240 return $utf8;
241
242 case 2:
243 // return a UTF-16 character from a 2-byte UTF-8 char
244 // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
245 return chr(0x07 & (ord($utf8[0]) >> 2)).chr((0xC0 & (ord($utf8[0]) << 6)) | (0x3F & ord($utf8[1])));
246
247 case 3:
248 // return a UTF-16 character from a 3-byte UTF-8 char
249 // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
250 return chr((0xF0 & (ord($utf8[0]) << 4)) | (0x0F & (ord($utf8[1]) >> 2))).chr((0xC0 & (ord($utf8[1]) << 6)) | (0x7F & ord($utf8[2])));
251 }
252
253 // ignoring UTF-32 for now, sorry
254 return '';
255 }
256}
257
258if (!function_exists('json_encode')) {
266 function json_encode($elements)
267 {
268 // @phan-suppress-next-line PhanDeprecatedFunction
269 return dol_json_encode($elements);
270 }
271}
272
273
274if (!function_exists('json_decode') || defined('PHPUNIT_MODE')) {
285 function dol_json_decode($json, $assoc = false)
286 {
287 dol_syslog("For better performance and security, enable the native json in your PHP", LOG_WARNING);
288
289 $comment = false;
290
291 $out = '';
292 $strLength = strlen($json); // Must stay strlen and not dol_strlen because we want technical length, not visible length
293
294 if (is_numeric($json)) {
295 return $json;
296 }
297
298 for ($i = 0; $i < $strLength; $i++) {
299 if (!$comment) {
300 if ($i == 0 && !in_array($json[$i], array('{', '[', '"', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'))) {
301 // Not a json format
302 return false;
303 }
304 if (($json[$i] == '{') || ($json[$i] == '[')) {
305 $out .= 'array(';
306 } elseif (($json[$i] == '}') || ($json[$i] == ']')) {
307 $out .= ')';
308 } elseif ($json[$i] == ':') {
309 $out .= ' => ';
310 } else {
311 $out .= $json[$i];
312 }
313 } else {
314 $out .= $json[$i];
315 }
316 // @phan-suppress-next-line PhanCompatibleNegativeStringOffset
317 if ($i >= 1 && $json[$i] == '"' && $json[$i - 1] != "\\") {
318 $comment = !$comment;
319 }
320 }
321
322 $out = _unval($out);
323
324 $array = array();
325
326 // Return an array
327 if ($out != '') {
328 try {
329 // @phan-suppress-next-line PhanPluginUnsafeEval
330 eval('$array = '.$out.';'); // not secured but this is no mode used as php json lib is always expected to be loaded now.
331 } catch (Exception $e) {
332 $array = array();
333 }
334 }
335
336 // Return an object
337 if (!$assoc) {
338 if (!empty($array)) {
339 $object = false;
340 if (count($array) > 0) {
341 $object = (object) array();
342 }
343 foreach ($array as $key => $value) {
344 if ($key) {
345 $object->{$key} = $value;
346 }
347 }
348
349 return $object;
350 }
351
352 return false;
353 }
354
355 return $array;
356 }
357
364 function _unval($val)
365 {
366 $reg = array();
367 while (preg_match('/\\\u([0-9A-F]{2})([0-9A-F]{2})/i', $val, $reg)) {
368 // single, escaped unicode character
369 $utf16 = chr(hexdec($reg[1])).chr(hexdec($reg[2]));
370 $utf8 = utf162utf8($utf16);
371 $val = preg_replace('/\\\u'.$reg[1].$reg[2].'/i', $utf8, $val);
372 }
373 return $val;
374 }
375
386 function utf162utf8($utf16)
387 {
388 // oh please oh please oh please oh please oh please
389 if (function_exists('mb_convert_encoding')) {
390 return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16');
391 }
392
393 $bytes = (ord($utf16[0]) << 8) | ord($utf16[1]);
394
395 switch (true) {
396 case ((0x7F & $bytes) == $bytes):
397 // this case should never be reached, because we are in ASCII range
398 // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
399 return chr($bytes);
400
401 case (0x07FF & $bytes) == $bytes:
402 // return a 2-byte UTF-8 character
403 // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
404 return chr(0xC0 | (($bytes >> 6) & 0x1F))
405 . chr(0x80 | ($bytes & 0x3F));
406
407 case (0xFFFF & $bytes) == $bytes:
408 // return a 3-byte UTF-8 character
409 // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
410 return chr(0xE0 | (($bytes >> 12) & 0x0F))
411 . chr(0x80 | (($bytes >> 6) & 0x3F))
412 . chr(0x80 | ($bytes & 0x3F));
413 }
414
415 // ignoring UTF-32 for now, sorry
416 return '';
417 }
418}
419
420if (!function_exists('json_decode')) {
429 function json_decode($json, $assoc = false)
430 {
431 // @phan-suppress-next-line PhanDeprecatedFunction
432 return dol_json_decode($json, $assoc);
433 }
434}
if( $user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
Definition card.php:58
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.