1 <?php
2
3 4 5 6 7 8 9 10
11
12 namespace ICanBoogie;
13
14 15 16 17 18 19 20 21 22 23 24 25
26 function escape($str, $charset=CHARSET)
27 {
28 return htmlspecialchars($str, ENT_COMPAT, $charset);
29 }
30
31 32 33 34 35 36 37 38 39 40 41
42 function escape_all($str, $charset=CHARSET)
43 {
44 return htmlentities($str, ENT_COMPAT, $charset);
45 }
46
47 if (!function_exists(__NAMESPACE__ . '\downcase'))
48 {
49 50 51 52 53 54 55
56 function downcase($str)
57 {
58 return mb_strtolower($str);
59 }
60 }
61
62 if (!function_exists(__NAMESPACE__ . '\upcase'))
63 {
64 65 66 67 68 69 70
71 function upcase($str)
72 {
73 return mb_strtoupper($str);
74 }
75 }
76
77 if (!function_exists(__NAMESPACE__ . '\capitalize'))
78 {
79 80 81 82 83 84
85 function capitalize($str)
86 {
87 return upcase(mb_substr($str, 0, 1)) . downcase(mb_substr($str, 1));
88 }
89 }
90
91 92 93 94 95 96 97 98 99 100
101 function shorten($str, $length=32, $position=.75, &$shortened=null)
102 {
103 $l = mb_strlen($str);
104
105 if ($l <= $length)
106 {
107 return $str;
108 }
109
110 $length--;
111 $position = (int) ($position * $length);
112
113 if ($position == 0)
114 {
115 $str = '…' . mb_substr($str, $l - $length);
116 }
117 else if ($position == $length)
118 {
119 $str = mb_substr($str, 0, $length) . '…';
120 }
121 else
122 {
123 $str = mb_substr($str, 0, $position) . '…' . mb_substr($str, $l - ($length - $position));
124 }
125
126 $shortened = true;
127
128 return $str;
129 }
130
131 132 133 134 135 136 137 138
139 function remove_accents($str, $charset=CHARSET)
140 {
141 $str = htmlentities($str, ENT_NOQUOTES, $charset);
142
143 $str = preg_replace('#&([A-za-z])(?:acute|cedil|caron|circ|grave|orn|ring|slash|th|tilde|uml);#', '\1', $str);
144 $str = preg_replace('#&([A-za-z]{2})(?:lig);#', '\1', $str);
145 $str = preg_replace('#&[^;]+;#', '', $str);
146
147 return $str;
148 }
149
150 151 152 153 154 155 156 157 158 159
160 function unaccent_compare($a, $b)
161 {
162 return strcmp(remove_accents($a), remove_accents($b));
163 }
164
165 166 167 168 169 170 171 172 173 174
175 function unaccent_compare_ci($a, $b)
176 {
177 return strcasecmp(remove_accents($a), remove_accents($b));
178 }
179
180 181 182 183 184 185 186 187 188 189 190 191
192 function normalize($str, $separator='-', $charset=CHARSET)
193 {
194 $str = str_replace('\'', '', $str);
195 $str = remove_accents($str, $charset);
196 $str = strtolower($str);
197 $str = preg_replace('#[^a-z0-9]+#', $separator, $str);
198 $str = trim($str, $separator);
199
200 return $str;
201 }
202
203 204 205 206 207 208 209 210 211 212
213 function dump($value)
214 {
215 if (function_exists('xdebug_var_dump'))
216 {
217 ob_start();
218
219 xdebug_var_dump($value);
220
221 $value = ob_get_clean();
222 }
223 else
224 {
225 $value = '<pre>' . escape(print_r($value, true)) . '</pre>';
226 }
227
228 return $value;
229 }
230
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
248 function format($str, array $args=array())
249 {
250 static $quotation_start;
251 static $quotation_end;
252
253 if ($quotation_start === null)
254 {
255 if (PHP_SAPI == 'cli')
256 {
257 $quotation_start = '"';
258 $quotation_end = '"';
259 }
260 else
261 {
262 $quotation_start = '<q>';
263 $quotation_end = '</q>';
264 }
265 }
266
267 if (!$args)
268 {
269 return $str;
270 }
271
272 $holders = array();
273 $i = 0;
274
275 foreach ($args as $key => $value)
276 {
277 if (is_object($value) && method_exists($value, '__toString'))
278 {
279 $value = (string) $value;
280 }
281
282 if (is_array($value) || is_object($value))
283 {
284 $value = dump($value);
285 }
286 else if (is_bool($value))
287 {
288 $value = $value ? '<em>true</em>' : '<em>false</em>';
289 }
290 else if (is_null($value))
291 {
292 $value = '<em>null</em>';
293 }
294
295 if (is_string($key))
296 {
297 switch ($key{0})
298 {
299 case ':': break;
300 case '!': $value = escape($value); break;
301 case '%': $value = $quotation_start . escape($value) . $quotation_end; break;
302
303 default:
304 {
305 $escaped_value = escape($value);
306
307 $holders['!' . $key] = $escaped_value;
308 $holders['%' . $key] = $quotation_start . $escaped_value . $quotation_end;
309
310 $key = ':' . $key;
311 }
312 }
313 }
314
315 $holders[$key] = $value;
316 $holders['\\' . $i] = $value;
317 $holders['{' . $i . '}'] = $value;
318
319 $i++;
320 }
321
322 return strtr($str, $holders);
323 }
324
325 326 327 328 329 330 331 332 333 334 335 336
337 function stable_sort(&$array, $picker=null)
338 {
339 static $transform, $restore;
340
341 $i = 0;
342
343 if (!$transform)
344 {
345 $transform = function(&$v, $k) use (&$i)
346 {
347 $v = array($v, ++$i, $k, $v);
348 };
349
350 $restore = function(&$v, $k)
351 {
352 $v = $v[3];
353 };
354 }
355
356 if ($picker)
357 {
358 array_walk
359 (
360 $array, function(&$v, $k) use (&$i, $picker)
361 {
362 $v = array($picker($v, $k), ++$i, $k, $v);
363 }
364 );
365 }
366 else
367 {
368 array_walk($array, $transform);
369 }
370
371 asort($array);
372
373 array_walk($array, $restore);
374 }
375
376 377 378 379 380 381 382 383 384 385 386 387
388 function sort_by_weight(array $array, $weight_picker)
389 {
390 if (!$array)
391 {
392 return $array;
393 }
394
395 $order = array();
396
397 foreach ($array as $k => $v)
398 {
399 $order[$k] = $weight_picker($v, $k);
400 }
401
402 $n = count($order);
403 $top = min($order) - $n;
404 $bottom = max($order) + $n;
405
406 foreach ($order as &$weight)
407 {
408 if ($weight === 'top')
409 {
410 $weight = --$top;
411 }
412 else if ($weight === 'bottom')
413 {
414 $weight = ++$bottom;
415 }
416 }
417
418 foreach ($order as $k => &$weight)
419 {
420 if (strpos($weight, 'before:') === 0)
421 {
422 $target = substr($weight, 7);
423
424 if (isset($order[$target]))
425 {
426 $order = array_insert($order, $target, $order[$target], $k);
427 }
428 else
429 {
430 $weight = 0;
431 }
432 }
433 else if (strpos($weight, 'after:') === 0)
434 {
435 $target = substr($weight, 6);
436
437 if (isset($order[$target]))
438 {
439 $order = array_insert($order, $target, $order[$target], $k, true);
440 }
441 else
442 {
443 $weight = 0;
444 }
445 }
446 }
447
448 stable_sort($order);
449
450 array_walk($order, function(&$v, $k) use($array) {
451
452 $v = $array[$k];
453
454 });
455
456 return $order;
457 }
458
459 460 461 462 463 464 465 466 467 468 469 470 471
472 function array_insert($array, $relative, $value, $key=null, $after=false)
473 {
474 if ($key)
475 {
476 unset($array[$key]);
477 }
478
479 $keys = array_keys($array);
480 $pos = array_search($relative, $keys, true);
481
482 if ($after)
483 {
484 $pos++;
485 }
486
487 $spliced = array_splice($array, $pos);
488
489 if ($key !== null)
490 {
491 $array = array_merge($array, array($key => $value));
492 }
493 else
494 {
495 array_unshift($spliced, $value);
496 }
497
498 return array_merge($array, $spliced);
499 }
500
501 502 503 504 505 506 507 508 509
510 function array_flatten($array, $separator='.', $depth=0)
511 {
512 $rc = array();
513
514 if (is_array($separator))
515 {
516 foreach ($array as $key => $value)
517 {
518 if (!is_array($value))
519 {
520 $rc[$key . ($depth ? $separator[1] : '')] = $value;
521
522 continue;
523 }
524
525 $values = array_flatten($value, $separator, $depth + 1);
526
527 foreach ($values as $vkey => $value)
528 {
529 $rc[$key . ($depth ? $separator[1] : '') . $separator[0] . $vkey] = $value;
530 }
531 }
532 }
533 else
534 {
535 foreach ($array as $key => $value)
536 {
537 if (!is_array($value))
538 {
539 $rc[$key] = $value;
540
541 continue;
542 }
543
544 $values = array_flatten($value, $separator);
545
546 foreach ($values as $vkey => $value)
547 {
548 $rc[$key . $separator . $vkey] = $value;
549 }
550 }
551 }
552
553 return $rc;
554 }
555
556 557 558 559 560 561 562 563
564 function array_merge_recursive(array $array1, array $array2=array())
565 {
566 $arrays = func_get_args();
567
568 $merge = array_shift($arrays);
569
570 foreach ($arrays as $array)
571 {
572 foreach ($array as $key => $val)
573 {
574
575
576
577
578
579 if (is_array($val) && array_key_exists($key, $merge))
580 {
581 $val = array_merge_recursive((array) $merge[$key], $val);
582 }
583
584
585
586
587
588
589 if (is_numeric($key))
590 {
591 $merge[] = $val;
592 }
593 else
594 {
595 $merge[$key] = $val;
596 }
597 }
598 }
599
600 return $merge;
601 }
602
603 function exact_array_merge_recursive(array $array1, array $array2=array())
604 {
605 $arrays = func_get_args();
606
607 $merge = array_shift($arrays);
608
609 foreach ($arrays as $array)
610 {
611 foreach ($array as $key => $val)
612 {
613
614
615
616
617
618 if (is_array($val) && array_key_exists($key, $merge))
619 {
620 $val = exact_array_merge_recursive((array) $merge[$key], $val);
621 }
622
623 $merge[$key] = $val;
624 }
625 }
626
627 return $merge;
628 }
629
630 631 632 633 634 635 636 637 638
639 function normalize_url_path($path)
640 {
641 static $cache = array();
642
643 if (isset($cache[$path]))
644 {
645 return $cache[$path];
646 }
647
648 $normalized = preg_replace('#\/index\.(html|php)$#', '/', $path);
649 $normalized = rtrim($normalized, '/');
650
651 if (!preg_match('#\.[a-z]+$#', $normalized))
652 {
653 $normalized .= '/';
654 }
655
656 $cache[$path] = $normalized;
657
658 return $normalized;
659 }
660
661 662 663 664 665 666 667
668 function generate_v4_uuid()
669 {
670 $data = openssl_random_pseudo_bytes(16);
671 $data[6] = chr(ord($data[6]) & 0x0f | 0x40);
672 $data[8] = chr(ord($data[8]) & 0x3f | 0x80);
673 return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
674 }