PluginProbe
Bit Form – Contact Form, Payment Forms, Multi Step Forms, Calculator & Custom Form Builder / 3.1.0
Bit Form – Contact Form, Payment Forms, Multi Step Forms, Calculator & Custom Form Builder v3.1.0
3.3.1 V-3.3.0 3.2.2 3.2.1 3.2.0 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 V3.0.3 V3.0.2 -3.0.1 V_3.0.0 1.1.1 1.1.8 1.2 1.3 1.4 1.4.18 1.5.2 1.9 2.0 2.10.0 2.10.1 All 138 releases
bit-form / vendor / arif-un / jcof / tests / test.php

test.php in Bit Form – Contact Form, Payment Forms, Multi Step Forms, Calculator & Custom Form Builder 3.1.0, at vendor/arif-un/jcof/tests/test.php

739 lines 16.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1
2 <?php
3
4 $b62alphabet = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
5 $b62alphanum = [];
6 for ($i = 0; $i < strlen($b62alphabet); $i++) {
7 $b62alphanum[$b62alphabet[$i]] = $i;
8 }
9
10 function isSep($ch)
11 {
12 return $ch == '[' || $ch == ']' || $ch == '{' || $ch == '}' ||
13 $ch == '(' || $ch == ')' || $ch == ',' || $ch == ':' || $ch == '"';
14 }
15
16 class StringWriter
17 {
18 public $str;
19
20 public $maybeNextSep;
21
22 public $prevCh;
23
24 public function __construct()
25 {
26 $this->str = '';
27 $this->maybeNextSep = null;
28 $this->prevCh = null;
29 }
30
31 public function write($s)
32 {
33 if ($this->maybeNextSep) {
34 if (! isSep($this->prevCh) && ! isSep($s[0])) {
35 $this->str .= $this->maybeNextSep;
36 }
37 $this->maybeNextSep = null;
38 }
39
40 $this->str .= $s;
41 $this->prevCh = $s[strlen($s) - 1];
42 }
43
44 public function maybeSep($sep)
45 {
46 if ($this->maybeNextSep) {
47 $this->write($this->maybeNextSep);
48 }
49
50 $this->maybeNextSep = $sep;
51 }
52 }
53
54 if (! function_exists('array_is_list')) {
55 function array_is_list(array $arr)
56 {
57 if ($arr === []) {
58 return true;
59 }
60
61 return array_keys($arr) === range(0, count($arr) - 1);
62 }
63 }
64
65 function analyzeValue($value, &$strings, &$objectShapes)
66 {
67 if (is_array($value) && array_is_list($value)) {
68 foreach ($value as $v) {
69 analyzeValue($v, $strings, $objectShapes);
70 }
71 } elseif (is_array($value) && ! array_is_list($value)) {
72 $keys = array_keys($value);
73 sort($keys);
74
75 if (count($keys) > 1) {
76 $shapeHash = json_encode($keys);
77 if (! isset($objectShapes[$shapeHash])) {
78 $objectShapes[$shapeHash] = ['count' => 1, 'keys' => $keys];
79 } else {
80 $objectShapes[$shapeHash]['count'] += 1;
81 }
82 } elseif (count($keys) == 1) {
83 if (! isset($strings[$keys[0]])) {
84 $strings[$keys[0]] = ['count' => 1];
85 } else {
86 $strings[$keys[0]]['count'] += 1;
87 }
88 }
89
90 foreach ($keys as $key) {
91 analyzeValue($value[$key], $strings, $objectShapes);
92 }
93 } elseif (is_string($value) && strlen($value) > 1) {
94 if (! isset($strings[$value])) {
95 $strings[$value] = ['count' => 1];
96 } else {
97 $strings[$value]['count'] += 1;
98 }
99 }
100 }
101
102 function analyze($value)
103 {
104 $strings = [];
105 $objectShapes = [];
106 analyzeValue($value, $strings, $objectShapes);
107
108 foreach ($objectShapes as $hash => $shape) {
109 if ($shape['count'] == 1) {
110 unset($objectShapes[$hash]);
111 }
112
113 foreach ($shape['keys'] as $key) {
114 if (! isset($strings[$key])) {
115 $strings[$key] = ['count' => 1];
116 } else {
117 $strings[$key]['count'] += 1;
118 }
119 }
120 }
121
122 foreach ($strings as $string => $s) {
123 if ($s['count'] == 1) {
124 unset($strings[$string]);
125 }
126 }
127
128 $stringList = array_keys($strings);
129 usort($stringList, function ($a, $b) use ($strings) {
130 return $strings[$b]['count'] - $strings[$a]['count'];
131 });
132
133 $stringIds = [];
134 for ($id = 0; $id < count($stringList); $id++) {
135 $stringIds[$stringList[$id]] = $id;
136 }
137
138 $objectShapeList = [];
139 $objectShapeIds = [];
140 foreach ($objectShapes as $hash => $shape) {
141 $objectShapeIds[$hash] = count($objectShapeList);
142 $objectShapeList[] = $shape['keys'];
143 }
144
145 return [
146 'stringList' => $stringList,
147 'stringIds' => $stringIds,
148 'objectShapeList' => $objectShapeList,
149 'objectShapeIds' => $objectShapeIds,
150 ];
151 }
152
153 function stringify($value)
154 {
155 $w = new StringWriter();
156 $meta = analyze($value);
157
158 stringifyStringTable($w, $meta);
159 $w->write(';');
160 stringifyObjectShapeTable($w, $meta);
161 $w->write(';');
162 stringifyValue($w, $meta, $value);
163
164 return $w->str;
165 }
166
167 function stringifyStringTable($w, $meta)
168 {
169 if (count($meta['stringList']) == 0) {
170 return;
171 }
172
173 stringifyString($w, $meta['stringList'][0]);
174 for ($i = 1; $i < count($meta['stringList']); $i++) {
175 $w->maybeSep(',');
176 stringifyString($w, $meta['stringList'][$i]);
177 }
178 }
179
180 function stringifyString($w, $string)
181 {
182 if (preg_match('/^[a-zA-Z0-9]+$/', $string)) {
183 $w->write($string);
184 } else {
185 $w->write(json_encode($string));
186 }
187 }
188
189 function stringifyObjectShapeTable($w, $meta)
190 {
191 if (count($meta['objectShapeList']) == 0) {
192 return;
193 }
194
195 stringifyObjectShape($w, $meta, $meta['objectShapeList'][0]);
196 for ($i = 1; $i < count($meta['objectShapeList']); $i++) {
197 $w->write(',');
198 stringifyObjectShape($w, $meta, $meta['objectShapeList'][$i]);
199 }
200 }
201
202 function stringifyObjectShape($w, $meta, $shape)
203 {
204 stringifyObjectKey($w, $meta, $shape[0]);
205 for ($i = 1; $i < count($shape); $i++) {
206 $w->maybeSep(':');
207 stringifyObjectKey($w, $meta, $shape[$i]);
208 }
209 }
210
211 function stringifyObjectKey($w, $meta, $key)
212 {
213 $id = isset($meta['stringIds'][$key]) ? $meta['stringIds'][$key] : null;
214 if ($id === null) {
215 $w->write(json_encode($key));
216 } else {
217 stringifyBase62($w, $id);
218 }
219 }
220
221 function stringifyBase62($w, $num)
222 {
223 global $b62alphabet;
224 $str = '';
225 do {
226 $str .= $b62alphabet[$num % 62];
227 $num = intval($num / 62);
228 } while ($num > 0);
229
230 for ($i = strlen($str) - 1; $i >= 0; $i--) {
231 $w->write($str[$i]);
232 }
233 }
234
235 function stringifyValue($w, $meta, $value)
236 {
237 if (is_array($value) && array_is_list($value)) {
238 $w->write('[');
239 if (count($value) == 0) {
240 $w->write(']');
241
242 return;
243 }
244 // print_r($value);
245 stringifyValue($w, $meta, $value[0]);
246 for ($i = 1; $i < count($value); $i++) {
247 $w->maybeSep(',');
248 stringifyValue($w, $meta, $value[$i]);
249 }
250
251 $w->write(']');
252 } elseif (is_array($value) && ! array_is_list($value)) {
253 $keys = array_keys($value);
254 sort($keys);
255 $hash = json_encode($keys);
256 $shapeId = isset($meta['objectShapeIds'][$hash]) ? $meta['objectShapeIds'][$hash] : null;
257 if ($shapeId === null) {
258 stringifyKeyedObjectValue($w, $meta, $value, $keys);
259 } else {
260 stringifyShapedObjectValue($w, $meta, $value, $keys, $shapeId);
261 }
262 } elseif (is_numeric($value)) {
263 if ($value == intval($value) && ($value < 0 || $value > 10)) {
264 $w->write($value < 0 ? 'I' : 'i');
265 stringifyBase62($w, abs($value));
266 } elseif (is_infinite($value) || is_nan($value)) {
267 $w->write('n');
268 } else {
269 $w->write(strval($value));
270 }
271 } elseif (is_string($value)) {
272 $stringId = isset($meta['stringIds'][$value]) ? $meta['stringIds'][$value] : null;
273 if ($stringId === null) {
274 $w->write(json_encode($value));
275 } else {
276 $w->write('s');
277 stringifyBase62($w, $stringId);
278 }
279 } elseif (is_bool($value)) {
280 $w->write($value ? 'b' : 'B');
281 } elseif ($value === null) {
282 $w->write('n');
283 } else {
284 throw new Exception("Can't serialize value: ".$value);
285 }
286 }
287
288 function stringifyShapedObjectValue($w, $meta, $value, $keys, $shapeId)
289 {
290 $w->write('(');
291 stringifyBase62($w, $shapeId);
292 if (count($keys) == 0) {
293 $w->write(')');
294
295 return;
296 }
297
298 foreach ($keys as $key) {
299 $w->maybeSep(',');
300 stringifyValue($w, $meta, $value[$key]);
301 }
302
303 $w->write(')');
304 }
305
306 function stringifyKeyedObjectValue($w, $meta, $value, $keys)
307 {
308 $w->write('{');
309 if (count($keys) == 0) {
310 $w->write('}');
311
312 return;
313 }
314
315 stringifyKeyValuePair($w, $meta, $keys[0], $value[$keys[0]]);
316 for ($i = 1; $i < count($keys); $i++) {
317 $w->maybeSep(',');
318 stringifyKeyValuePair($w, $meta, $keys[$i], $value[$keys[$i]]);
319 }
320
321 $w->write('}');
322 }
323
324 function stringifyKeyValuePair($w, $meta, $key, $val)
325 {
326 stringifyObjectKey($w, $meta, $key);
327 $w->maybeSep(':');
328 stringifyValue($w, $meta, $val);
329 }
330
331 class ParseErrors extends Exception
332 {
333 public $index;
334
335 public function __construct($msg, $index)
336 {
337 parent::__construct($msg);
338 $this->name = 'ParseError'; // In PHP, Exception has a 'message' property but not a 'name' property.
339 $this->index = $index;
340 }
341 }
342
343 class StringReader
344 {
345 public $str;
346
347 public $index;
348
349 public function __construct($str)
350 {
351 $this->str = $str;
352 $this->index = 0;
353 }
354
355 public function peek()
356 {
357 if ($this->index >= strlen($this->str)) {
358 return null;
359 } else {
360 return $this->str[$this->index];
361 }
362 }
363
364 public function consume()
365 {
366 $this->index += 1;
367 }
368
369 public function skip($ch)
370 {
371 $peeked = $this->peek();
372 if ($peeked != $ch) {
373 $this->error("Unexpected char: Expected '".$ch."', got '".$peeked."'");
374 }
375
376 $this->consume();
377 }
378
379 public function maybeSkip($ch)
380 {
381 if ($this->peek() == $ch) {
382 $this->consume();
383 }
384 }
385
386 public function error($msg)
387 {
388 throw new ParseErrors($msg, $this->index);
389 }
390 }
391
392 function parse($str)
393 {
394 $r = new StringReader($str);
395 $stringTable = parseStringTable($r);
396 $r->skip(';');
397 $objectShapeTable = parseObjectShapeTable($r, $stringTable);
398 $r->skip(';');
399
400 return parseValue($r, $stringTable, $objectShapeTable);
401 }
402
403 function parseStringTable($r)
404 {
405 if ($r->peek() == ';') {
406 return [];
407 }
408
409 $strings = [];
410 while (true) {
411 $strings[] = parseString($r);
412 $ch = $r->peek();
413 if ($ch == ';') {
414 return $strings;
415 } elseif ($ch == ',') {
416 $r->consume();
417 }
418 }
419 }
420
421 function parseString($r)
422 {
423 if ($r->peek() == '"') {
424 return parseJsonString($r);
425 } elseif (preg_match('/[a-zA-Z0-9]/', $r->peek())) {
426 return parsePlainString($r);
427 } else {
428 $r->error('Expected plain string or JSON string');
429 }
430 }
431
432 function parsePlainString($r)
433 {
434 $str = $r->peek();
435 $r->consume();
436
437 while (true) {
438 $ch = $r->peek();
439 if (! preg_match('/[a-zA-Z0-9]/', $ch)) {
440 return $str;
441 }
442
443 $str .= $ch;
444 $r->consume();
445 }
446 }
447
448 function parseJsonString($r)
449 {
450 $start = $r->index;
451 $r->skip('"');
452 while (true) {
453 $ch = $r->peek();
454 $r->consume();
455 if ($ch == '"') {
456 break;
457 } elseif ($ch == '\\') {
458 $r->consume();
459 } elseif ($ch === null) {
460 $r->error('Unexpected EOF');
461 }
462 }
463
464 $substring = substr($r->str, $start, $r->index - $start);
465
466 return json_decode($substring, true);
467 }
468
469 function parseObjectShapeTable($r, $stringTable)
470 {
471 if ($r->peek() == ';') {
472 return [];
473 }
474
475 $shapes = [];
476 while (true) {
477 $shapes[] = parseObjectShape($r, $stringTable);
478 $ch = $r->peek();
479 if ($ch == ';') {
480 return $shapes;
481 } elseif ($ch == ',') {
482 $r->consume();
483 }
484 }
485 }
486
487 function parseObjectShape($r, $stringTable)
488 {
489 $shape = [];
490 while (true) {
491 $shape[] = parseObjectKey($r, $stringTable);
492 $ch = $r->peek();
493 if ($ch == ',' || $ch == ';') {
494 return $shape;
495 } elseif ($ch == ':') {
496 $r->consume();
497 }
498 }
499 }
500
501 function parseObjectKey($r, $stringTable)
502 {
503 if ($r->peek() == '"') {
504 return parseJsonString($r);
505 } else {
506 $id = parseBase62($r);
507 if ($id >= count($stringTable)) {
508 $r->error('String ID '.$id.' out of range');
509 }
510
511 return $stringTable[$id];
512 }
513 }
514
515 function parseBase62($r)
516 {
517 global $b62alphanum;
518
519 if (! preg_match('/[0-9a-zA-Z]/', $r->peek())) {
520 $r->error('Expected base62 value');
521 }
522
523 $num = 0;
524 while (true) {
525 $num *= 62;
526 $num += $b62alphanum[$r->peek()];
527 $r->consume();
528 if (! preg_match('/[0-9a-zA-Z]/', $r->peek())) {
529 return $num;
530 }
531 }
532 }
533
534 function parseValue($r, $stringTable, $objectShapeTable)
535 {
536 $ch = $r->peek();
537 if ($ch == '[') {
538 return parseArrayValue($r, $stringTable, $objectShapeTable);
539 } elseif ($ch == '(') {
540 return parseShapedObjectValue($r, $stringTable, $objectShapeTable);
541 } elseif ($ch == '{') {
542 return parseKeyedObjectValue($r, $stringTable, $objectShapeTable);
543 } elseif (preg_match('/[iIf0-9\-]/', $ch)) {
544 return parseNumberValue($r);
545 } elseif ($ch == 's' || $ch == '"') {
546 return parseStringValue($r, $stringTable);
547 } elseif ($ch == 'b') {
548 $r->consume();
549
550 return true;
551 } elseif ($ch == 'B') {
552 $r->consume();
553
554 return false;
555 } elseif ($ch == 'n') {
556 $r->consume();
557
558 return null;
559 } else {
560 $r->error("Expected value, got '".$ch."'");
561 }
562 }
563
564 function parseArrayValue($r, $stringTable, $objectShapeTable)
565 {
566 $r->skip('[');
567 if ($r->peek() == ']') {
568 $r->consume();
569
570 return [];
571 }
572
573 $arr = [];
574 while (true) {
575 $arr[] = parseValue($r, $stringTable, $objectShapeTable);
576 $ch = $r->peek();
577 if ($ch == ']') {
578 $r->consume();
579
580 return $arr;
581 } elseif ($ch == ',') {
582 $r->consume();
583 }
584 }
585 }
586
587 function parseShapedObjectValue($r, $stringTable, $objectShapeTable)
588 {
589 $r->skip('(');
590 $shapeId = parseBase62($r);
591 if ($shapeId >= count($objectShapeTable)) {
592 $r->error('Shape ID '.$shapeId.' out of range');
593 }
594
595 $shape = $objectShapeTable[$shapeId];
596 $obj = [];
597 foreach ($shape as $key) {
598 if ($r->peek() == ',') {
599 $r->consume();
600 }
601 $obj[$key] = parseValue($r, $stringTable, $objectShapeTable);
602 }
603
604 $r->skip(')');
605
606 return $obj;
607 }
608
609 function parseKeyedObjectValue($r, $stringTable, $objectShapeTable)
610 {
611 $r->skip('{');
612 if ($r->peek() == '}') {
613 $r->consume();
614
615 return [];
616 }
617
618 $obj = [];
619 while (true) {
620 $key = parseObjectKey($r, $stringTable);
621 if ($r->peek() == ':') {
622 $r->consume();
623 }
624
625 $obj[$key] = parseValue($r, $stringTable, $objectShapeTable);
626 $ch = $r->peek();
627 if ($ch == ',') {
628 $r->consume();
629 } elseif ($ch == '}') {
630 $r->consume();
631
632 return $obj;
633 }
634 }
635 }
636
637 function parseNumberValue($r)
638 {
639 $ch = $r->peek();
640 if ($ch == 'i') {
641 $r->consume();
642
643 return parseBase62($r);
644 } elseif ($ch == 'I') {
645 $r->consume();
646
647 return -parseBase62($r);
648 } else {
649 return parseFloatValue($r);
650 }
651 }
652
653 function parseFloatValue($r)
654 {
655 // Here, we read the float, but then use PHP's float parser,
656 // because making a float parser and serializer pair
657 // which can round-trip any number is apparently pretty hard
658
659 $str = '';
660
661 if (($ch = $r->peek()) == '-') {
662 $str .= $ch;
663 $r->consume();
664 }
665
666 while (preg_match('/[0-9]/', $ch = $r->peek())) {
667 $str .= $ch;
668 $r->consume();
669 }
670
671 if ($str == '' || $str == '-') {
672 $r->error('Zero-length number in float literal');
673 }
674
675 if (($ch = $r->peek()) == '.') {
676 $str .= $ch;
677 $r->consume();
678
679 while (preg_match('/[0-9]/', $ch = $r->peek())) {
680 $str .= $ch;
681 $r->consume();
682 }
683
684 if ($str[strlen($str) - 1] == '.') {
685 $r->error('Zero-length fractional part in float literal');
686 }
687 }
688
689 $ch = $r->peek();
690 if ($ch == 'e' || $ch == 'E') {
691 $str .= $ch;
692 $r->consume();
693
694 $ch = $r->peek();
695 if ($ch == '+' || $ch == '-') {
696 $str .= $ch;
697 $r->consume();
698 }
699
700 while (preg_match('/[0-9]/', $ch = $r->peek())) {
701 $str .= $ch;
702 $r->consume();
703 }
704
705 if (! preg_match('/[0-9]/', $str[strlen($str) - 1])) {
706 $r->error('Zero-length exponential part in float literal');
707 }
708 }
709
710 return floatval($str);
711 }
712
713 function parseStringValue($r, $stringTable)
714 {
715 if ($r->peek() == '"') {
716 return parseJsonString($r);
717 } else {
718 $r->skip('s');
719 $id = parseBase62($r);
720 if ($id >= count($stringTable)) {
721 $r->error('String ID '.$id.' out of range');
722 }
723
724 return $stringTable[$id];
725 }
726 }
727
728 // print_r(
729 // stringify(
730 // // json_encode(
731 // parse('Programmer;"age""first-name""full-time""occupation";{"people"[(0,iw"Bob"b"Plumber")(0,is"Alice"b,s0)(0,iA"Bernard"n,n)(0,iV"El"B,s0)]}')
732 // // )
733 // )
734 // );
735
736 print_r(
737 parse('Programmer;"age""first-name""full-time""occupation";{"people"[(0,iw"Bob"b"Plumber")(0,is"Alice"b,s0)(0,iA"Bernard"n,n)(0,iV"El"B,s0)]}')
738 );
739