public
Description: A small Rails-inspired library of PHP helper functions. Simple stuff that really should be in core PHP.
Homepage:
Clone URL: git://github.com/jaz303/php-helpers.git
php-helpers / helpers-5.3.php
100644 526 lines (457 sloc) 14.399 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
<?php
/**
* php-helpers
* (c) 2009 Jason Frame [jason@onehackoranother.com]
*/
 
//
// These constants define the locations of your site's static assets.
// Define your own prior to inclusion of this lib or accept the defaults below.
// STATIC_ROOT/ will be prepended to each asset directory when generating
// asset paths.
 
if (!defined('STATIC_ROOT')) define('STATIC_ROOT', '');
if (!defined('STATIC_JS_DIR')) define('STATIC_JS_DIR', 'javascripts');
if (!defined('STATIC_IMAGE_DIR')) define('STATIC_IMAGE_DIR', 'images');
if (!defined('STATIC_CSS_DIR')) define('STATIC_CSS_DIR', 'stylesheets');
 
//
// Primitive helpers
 
/**
* Convert value to integer or null
*
* @param $i value to make into an integer
* @return null if $i is null, intval($i) otherwise
*/
function int_or_null($i) {
    return $i === null ? null : (int) $i;
}
 
/**
* Trim a string then constrain its length.
*
* @param $str string
* @param $len max length
* @return string, trimmed then reduced to length $len
*/
function trim_to($str, $len) {
    return substr(trim($str), 0, $len);
}
 
/**
* Trim a string, optionally constrain to a given length, or return null
*
* @param $str string
* @param $len optional max length
* @return null if $str is null, trimmed string with maximal length $len otherwise.
*/
function trim_or_null($str, $len = null) {
    if ($str === null) return null;
    return trim_to($str, $len ? $len : strlen($str));
}
 
/**
* Trim a string, optional constrain to a given length, returning the modified string,
* or null if the resultant string is empty.
*
* @param $str string
* @param $len optional max length
* @return $str, trimmed and constrained. Returns null if $str is empty after processing.
*/
function trim_to_null($str, $len = null) {
    $str = trim_to($str, $len ? $len : strlen($str));
    return strlen($str) ? $str : null;
}
//
// Support
 
/**
* Parse a selector of the form #foo.bar.baz into constituent ID and classes.
* An array argument will be returned unchanged.
*/
function parse_simple_selector($s) {
    if (!is_array($s)) {
        preg_match('/^(#([\w-]+))?((\.[\w-]+)*)$/', $s, $matches);
        $s = array();
        if (!empty($matches[2])) $s['id'] = $matches[2];
        if (!empty($matches[3])) $s['class'] = trim(str_replace('.', ' ', $matches[3]));
    }
    return $s;
}
 
/**
* Turn some representation of a URL into a string.
* Scalar parameters are coerced to strings and returned.
* Any other argument will be passed to url_for(), which should be implemented by
* your application.
*/
function generate_url($u) {
    return is_scalar($u) ? (string) $u : url_for($u);
}
 
function is_enumerable($thing) {
    return is_array($thing) || is_object($thing);
}
 
//
// Array paths (docs coming soon)
 
function array_path($array, $path, $default = null) {
    $path = explode('.', $path);
    while ($key = array_shift($path)) {
        if (!isset($array[$key])) return $default;
        $array = $array[$key];
    }
    return $array;
}
 
function array_path_unset(&$array, $path) {
    $tmp = & $array;
    $path = explode('.', $path);
    while (count($path) > 1) {
        $key = array_shift($path);
        if (!isset($tmp[$key])) return;
        $tmp = & $tmp[$key];
    }
    unset($tmp[array_shift($path)]);
}
 
function array_without_path($array) {
    $args = func_get_args();
    array_shift($args);
    foreach ($args as $path) array_path_unset($array, $path);
    return $array;
}
 
function array_path_replace(&$array, $path, $value) {
    $tmp = & $array;
    $path = explode('.', $path);
    while (count($path) > 1) {
        $key = array_shift($path);
        if (!isset($tmp[$key])) $tmp[$key] = array();
        $tmp = & $tmp[$key];
    }
    $tmp[array_shift($path)] = $value;
}
 
function array_path_to_name($path) {
    $bits = explode('.', $path);
    $out = array_shift($bits);
    while (count($bits)) $out .= '[' . array_shift($bits) . ']';
    return $out;
}
 
/**
* Generate a query string from an array, optionally replacing and/or removing
* elements from the array (referenced by path).
*
* @param $array array to turn into a query string
* @param $replace map of paths to replace, and their new values
* @param $remvoe array of paths to remove
*/
function query_string(array $array, $replace = null, $remove = null) {
    if ($replace !== null) {
        foreach ((array) $replace as $path => $v) {
            array_path_replace($array, $path, $v);
        }
    }
    if ($remove !== null) {
        foreach ((array) $remove as $path) {
            array_path_unset($array, $path);
        }
    }
    return array_url_encode($array);
}
 
/**
* Generate a query string fragment.
*
* one string param - returned as-is
* one array param - passed to array_url_encode() and returned
* two string params - returns $arg1=$arg2
*
* @param $arg1
* @param $arg2
* @return query string fragment
*/
function query_string_fragment($k, $v = null) {
    if ($v === null) {
        if (is_array($k)) {
            return array_url_encode($k);
        } else {
            return (string) $k;
        }
    } else {
        return urlencode($k) . '=' . urlencode($v);
    }
}
 
function url_append($url, $k, $v = null) {
    $sep = (strpos($url, '?') === false) ? '?' : '&';
    return $url . $sep . query_string_fragment($k, $v);
}
 
function query_string_append($query_string, $k, $v = null) {
    return $query_string . (strlen($query_string) ? '&' : '') . query_string_fragment($k, $v);
}
 
function array_url_encode($array, $omit = null) {
    $out = array();
    _array_url_encode_recurse($array, $out, $omit, '');
    return implode('&', $out);
}
 
function _array_url_encode_recurse($src, &$dst, $omit, $prefix) {
    foreach ($src as $k => $v) {
        if ($k === $omit) continue;
        $name = strlen($prefix) ? "{$prefix}[$k]" : $k;
        if (is_enumerable($v)) {
            _array_url_encode_recurse($v, $dst, $omit, $name);
        } else {
            $dst[] = urlencode($name) . '=' . urlencode($v);
        }
    }
}
 
//
// Asset
 
/**
* Returns the URL for static asset $what
*
* If $what is an absolute URI/path, or a relative path starting with "./",
* it is returned unmodified. Otherwise, a static asset URL is generated based
* on STATIC_ROOT.
*/
function url_for_asset($what, $where) {
    if (preg_match('%^(https?://|\.?/)%', $what)) {
        return $what;
    } else {
        return STATIC_ROOT . "/$where/$what";
    }
}
 
function url_for_image($image) {
    return url_for_asset($image, STATIC_IMAGE_DIR);
}
 
function url_for_stylesheet($stylesheet) {
    return url_for_asset($stylesheet, STATIC_CSS_DIR);
}
 
function url_for_javascript($js) {
    return url_for_asset($js, STATIC_JS_DIR);
}
 
//
// Tag Helpers
 
function stylesheet_link_tag($css, $options = array()) {
    $options['href'] = url_for_stylesheet($css);
    $options['rel'] = 'stylesheet';
    $options['type'] = 'text/css';
    return tag('link', '', $options);
}
 
function javascript_include_tag($js, $options = array()) {
    $options['src'] = url_for_javascript($js);
    $options['type'] = 'text/javascript';
    return tag('script', '', $options);
}
 
//
//
 
function h($html, $q = ENT_QUOTES) {
    return htmlentities($html, $q);
}
 
function tag($tag, $content, $attribs = array()) {
    $attribs = attribute_list($attribs);
    return "<{$tag}{$attribs}>{$content}</{$tag}>";
}
 
function empty_tag($tag, $attribs = array()) {
    $attribs = attribute_list($attribs);
    return "<{$tag}{$attribs}/>";
}
 
function attribute_list($attribs) {
    $out = '';
    foreach ($attribs as $k => $v) {
$v = h($v);
$out .= " $k='$v'";
    }
    return $out;
}
 
/**
* Create an image tag.
*
* i('foo.png', array('alt' => 'Hello'))
* i('bar.png', '#my-image')
* i('baz.gif', '#my-image.my-class', array('width' => 500))
*/
function i($src, $options_or_selector = array(), $options = array()) {
    $options += parse_simple_selector($options_or_selector);
    $options['src'] = url_for_image($src);
    $options += array('alt' => '');
    return empty_tag('img', $as, $options);
}
 
function link_to($html, $url, $options = array()) {
    $options['href'] = generate_url($url);
    return tag('a', $html, $options);
}
 
function mail_to($html, $address = null, $options = array()) {
    if (is_array($address)) {
        $options = $address;
        $address = null;
    }
    if ($address === null) {
        $address = $html;
    }
    return link_to($html, "mailto:$address", $options);
}
 
//
// Input Helpers
 
function hidden_field_tag($name, $value, $options = array()) {
    return empty_tag('input', array(
        'type' => 'hidden',
        'name' => $name,
        'value' => $value
    ) + $options);
}
 
function hidden_field_tags($array, $prefix = '') {
    $html = '';
    foreach ($array as $k => $v) {
        $name = strlen($prefix) ? "{$prefix}[$k]" : $k;
        if (is_enumerable($v)) {
            $html .= hidden_field_tags($v, $name);
        } else {
            $html .= hidden_field_tag($name, $v);
        }
    }
    return $html;
}
 
function text_field_tag($name, $value = '', $options = array()) {
    return empty_tag('input', array(
        'type' => 'text',
        'name' => $name,
        'value' => $value
    ) + $options);
}
 
function password_field_tag($name, $value = '', $options = array()) {
    return empty_tag('input', array(
        'type' => 'password',
        'name' => $name,
        'value' => $value
    ) + $options);
}
 
function file_field_tag($name, $options = array()) {
    return empty_tag('input', array(
        'type' => 'file',
        'name' => $name
    ) + $options);
}
 
function check_box_tag($name, $checked = false, $options = array()) {
    $options['type'] = 'checkbox';
    $options['name'] = $name;
    $options['value'] = 1;
    if ($checked) $options['checked'] = 'checked';
    return hidden_field_tag($name, 0) . empty_tag('input', $options);
}
 
function radio_button_tag($name, $value, $current_value = null, $options = array()) {
    $options['type'] = 'radio';
    $options['name'] = $name;
    $options['value'] = $value;
    if ($value == $current_value || $current_value === true) $options['checked'] = 'checked';
    return empty_tag('input', $options);
}
 
function text_area_tag($name, $value, $options = array()) {
    $options['name'] = $name;
    return tag('textarea', $value, $options + array('rows' => 6, 'cols' => 50));
}
 
function select_box($name, $choices, $selected = null, $options = array()) {
    
    $options += array('keys' => true, 'multiple' => false, 'groups' => false);
    $options['name'] = $name;
    
    $ofs_opts = array('groups' => $options['groups'], 'keys' => $options['keys']);
    unset($options['groups']);
    unset($options['keys']);
    
    if ($options['multiple']) $selected = (array) $selected;
    
    return tag('select', options_for_select($choices, $selected, $ofs_opts), $options);
    
}
 
function options_for_select($choices, $selected = null, $options = array()) {
    $options += array('groups' => false, 'keys' => true);
    $html = '';
    if ($options['groups']) {
        foreach ($choices as $group_label => $group_options) {
            $html .= '<optgroup label="' . h($group_label) . '">';
            $html .= option_group($group_options, $selected, $options['keys']);
            $html .= '</optgroup>';
        }
    } else {
        $html .= option_group($choices, $selected, $options['keys']);
    }
    return $html;
}
 
function option_group($choices, $selected, $use_keys) {
    $html = '';
    foreach ($choices as $k => $v) {
        $c = $use_keys ? $k : $v;
        $s = is_array($selected) ? in_array($c, $selected) : ($selected == $c);
        $s = $s ? ' selected="selected"' : '';
        $v = htmlentities($v);
        if ($use_keys) {
            $k = htmlentities($k);
            $html .= "<option value=\"$k\"{$s}>{$v}</option>";
        } else {
            $html .= "<option{$s}>{$v}</option>";
        }
    }
    return $html;
}
 
//
// Functional programming primitives
 
// returns the arity of the given closure
function arity($lambda) {
    $r = new ReflectionObject($lambda);
    $m = $r->getMethod('__invoke');
    return $m->getNumberOfParameters();
}
 
function every($iterable, $lambda) {
    if (arity($lambda) < 2) {
        foreach ($iterable as $i) $lambda($i);
    } else {
        foreach ($iterable as $k => $v) $lambda($k, $v);
    }
}
 
function every_with_index($iterable, $lambda) {
    $c = 0;
    if (arity($lambda) < 3) {
        foreach ($iterable as $i) $lambda($i, $c++);
    } else {
        foreach ($iterable as $k => $v) $lambda($k, $v, $c++);
    }
}
 
function map($iterable, $lambda) {
    $out = array();
    foreach ($iterable as $v) $out[] = $lambda($v);
    return $out;
}
 
function kmap($iterable, $lambda) {
    $out = array();
    foreach ($iterable as $k => $v) $out[$k] = $lambda($v);
    return $out;
}
 
// returns true iff $lambda($v) returns true for all values $v in $iterable
function all($iterable, $lambda) {
    foreach ($iterable as $v) {
        if (!$lambda($v)) return false;
    }
    return true;
}
 
// returns true iff $lambda($v) returns true for any value $v in $iterable
function any($iterable, $lambda) {
    foreach ($iterable as $v) {
        if ($lambda($v)) return true;
    }
    return false;
}
 
function inject($iterable, $memo, $lambda) {
    if (arity($lambda) < 3) {
        foreach ($iterable as $v) $memo = $lambda($memo, $v);
    } else {
        foreach ($iterable as $k => $v) $memo = $lambda($memo, $k, $v);
    }
    return $memo;
}
 
// filters $iterable, returning only those values for which $lambda($v) is true
function filter($iterable, $lambda) {
    $out = array();
    foreach ($iterable as $v) if ($lambda($v)) $out[] = $v;
    return $out;
}
 
// as filter(), but preserves keys
function kfilter($iterable, $lambda) {
    $out = array();
    foreach ($iterable as $k => $v) if ($lambda($v)) $out[$k] = $v;
    return $out;
}
 
// filters $iterable, removing those values for which $lambda($v) is true
function reject($iterable, $lambda) {
    $out = array();
    foreach ($iterable as $v) if (!$lambda($v)) $out[] = $v;
    return $out;
}
 
// as reject(), but preserves keys
function kreject($iterable, $lambda) {
    $out = array();
    foreach ($iterable as $k => $v) if (!$lambda($v)) $out[$k] = $v;
    return $out;
}
?>