source: branches/eli_branch/lib/Utilities.inc.php @ 447

Last change on this file since 447 was 439, checked in by anonymous, 11 years ago

added public and private keywords to all properties and methods, changed old classname constructor function to construct, removed more ?> closing tags

File size: 36.0 KB
Line 
1<?php
2/**
3 * The Strangecode Codebase - a general application development framework for PHP
4 * For details visit the project site: <http://trac.strangecode.com/codebase/>
5 * Copyright 2001-2012 Strangecode, LLC
6 *
7 * This file is part of The Strangecode Codebase.
8 *
9 * The Strangecode Codebase is free software: you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as published by the
11 * Free Software Foundation, either version 3 of the License, or (at your option)
12 * any later version.
13 *
14 * The Strangecode Codebase is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 * details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * The Strangecode Codebase. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23/**
24 * Utilities.inc.php
25 */
26
27
28/**
29 * Print variable dump.
30 *
31 * @param  mixed $var      Variable to dump.
32 * @param  bool  $display   Hide the dump in HTML comments?
33 * @param  bool  $var_dump Use var_dump instead of print_r.
34 */
35function dump($var, $display=false, $var_dump=false)
36{
37    if (defined('_CLI')) {
38        echo "\n";
39    } else {       
40        echo $display ? "\n<br /><pre>\n" : "\n\n\n<!--\n";
41    }
42    if ($var_dump) {
43        var_dump($var);
44    } else {
45        print_r($var);
46    }
47    if (defined('_CLI')) {
48        echo "\n";
49    } else {       
50        echo $display ?  "\n</pre><br />\n" : "\n-->\n\n\n";
51    }
52}
53
54/**
55 * Return dump as variable.
56 *
57 * @param  mixed $var           Variable to dump.
58 * @param  bool  $serialize     Remove line-endings. Useful for logging variables.
59 * @return string Dump of var.
60 */
61function getDump($var, $serialize=false)
62{
63    ob_start();
64    print_r($var);
65    $d = ob_get_contents();
66    ob_end_clean();
67    return $serialize ? preg_replace('/\s+/m', '', $d) : $d;
68}
69
70/**
71 * Return dump as cleaned text. Useful for dumping data into emails.
72 *
73 * @param  array    $var        Variable to dump.
74 * @param  strong   $indent     A string to prepend indented lines (tab for example).
75 * @return string Dump of var.
76 */
77function fancyDump($var, $indent='')
78{
79    $output = '';
80    if (is_array($var)) {
81        foreach ($var as $k=>$v) {
82            $k = ucfirst(mb_strtolower(str_replace(array('_', '  '), ' ', $k)));
83            if (is_array($v)) {
84                $output .= sprintf("\n%s%s: %s\n", $indent, $k, fancyDump($v, $indent . $indent));
85            } else {
86                $output .= sprintf("%s%s: %s\n", $indent, $k, $v);
87            }
88        }
89    } else {
90        $output .= sprintf("%s%s\n", $indent, $var);
91    }
92    return $output;
93}
94
95/**
96 * Returns text with appropriate html translations.
97 *
98 * @param  string $text             Text to clean.
99 * @param  bool   $preserve_html    If set to true, oTxt will not translate <, >, ", or '
100 *                                  characters into HTML entities. This allows HTML to pass through unmunged.
101 * @return string                   Cleaned text.
102 */
103function oTxt($text, $preserve_html=false)
104{
105    $app =& App::getInstance();
106
107    $search = array();
108    $replace = array();
109
110    // Make converted ampersand entities into normal ampersands (they will be done manually later) to retain HTML entities.
111    $search['retain_ampersand']     = '/&amp;/';
112    $replace['retain_ampersand']    = '&';
113
114    if ($preserve_html) {
115        // Convert characters that must remain non-entities for displaying HTML.
116        $search['retain_left_angle']       = '/&lt;/';
117        $replace['retain_left_angle']      = '<';
118
119        $search['retain_right_angle']      = '/&gt;/';
120        $replace['retain_right_angle']     = '>';
121
122        $search['retain_single_quote']     = '/&#039;/';
123        $replace['retain_single_quote']    = "'";
124
125        $search['retain_double_quote']     = '/&quot;/';
126        $replace['retain_double_quote']    = '"';
127    }
128
129    // & becomes &amp;. Exclude any occurrence where the & is followed by a alphanum or unicode character.
130    $search['ampersand']        = '/&(?![\w\d#]{1,10};)/';
131    $replace['ampersand']       = '&amp;';
132
133    return preg_replace($search, $replace, htmlspecialchars($text, ENT_QUOTES, $app->getParam('character_set')));
134}
135
136/**
137 * Returns text with stylistic modifications. Warning: this will break some HTML attributes!
138 * TODO: Allow a string such as this to be passed: <a href="javascript:openPopup('/foo/bar.php')">Click here</a>
139 *
140 * @param  string   $text Text to clean.
141 * @return string         Cleaned text.
142 */
143function fancyTxt($text)
144{
145    $search = array();
146    $replace = array();
147
148    // "double quoted text"  becomes  &ldquo;double quoted text&rdquo;
149    $search['double_quotes']    = '/(^|[^\w=])(?:"|&quot;|&#34;|&#x22;|&ldquo;)([^"]+?)(?:"|&quot;|&#34;|&#x22;|&rdquo;)([^\w]|$)/ms'; // " is the same as &quot; and &#34; and &#x22;
150    $replace['double_quotes']   = '$1&ldquo;$2&rdquo;$3';
151
152    // text's apostrophes  become  text&rsquo;s apostrophes
153    $search['apostrophe']       = '/(\w)(?:\'|&#39;|&#039;)(\w)/ms';
154    $replace['apostrophe']      = '$1&rsquo;$2';
155
156    // 'single quoted text'  becomes  &lsquo;single quoted text&rsquo;
157    $search['single_quotes']    = '/(^|[^\w=])(?:\'|&#39;|&lsquo;)([^\']+?)(?:\'|&#39;|&rsquo;)([^\w]|$)/ms';
158    $replace['single_quotes']   = '$1&lsquo;$2&rsquo;$3';
159
160    // plural posessives' apostrophes become posessives&rsquo;
161    $search['apostrophes']      = '/(s)(?:\'|&#39;|&#039;)(\s)/ms';
162    $replace['apostrophes']     = '$1&rsquo;$2';
163
164    // em--dashes  become em&mdash;dashes
165    $search['em_dash']          = '/(\s*[^!<-])--([^>-]\s*)/';
166    $replace['em_dash']         = '$1&mdash;$2';
167
168    return preg_replace($search, $replace, $text);
169}
170
171/**
172 * Applies a class to search terms to highlight them ala google results.
173 *
174 * @param  string   $text   Input text to search.
175 * @param  string   $search String of word(s) that will be highlighted.
176 * @param  string   $class  CSS class to apply.
177 * @return string           Text with searched words wrapped in <span>.
178 */
179function highlightWords($text, $search, $class='sc-highlightwords')
180{
181    $words = preg_split('/[^\w]/', $search, -1, PREG_SPLIT_NO_EMPTY);
182   
183    $search = array();
184    $replace = array();
185   
186    foreach ($words as $w) {
187        if ('' != trim($w)) {
188            $search[] = '/\b(' . preg_quote($w) . ')\b/i';
189            $replace[] = '<span class="' . $class . '">$1</span>';
190        }
191    }
192
193    return empty($replace) ? $text : preg_replace($search, $replace, $text);
194}
195
196/**
197 * Generates a hexadecimal html color based on provided word.
198 *
199 * @access public
200 * @param  string $text  A string for which to convert to color.
201 * @return string  A hexadecimal html color.
202 */
203function getTextColor($text, $method=1)
204{
205    $hash = md5($text);
206    $rgb = array(
207        mb_substr($hash, 0, 1),
208        mb_substr($hash, 1, 1),
209        mb_substr($hash, 2, 1),
210        mb_substr($hash, 3, 1),
211        mb_substr($hash, 4, 1),
212        mb_substr($hash, 5, 1),
213    );
214
215    switch ($method) {
216    case 1 :
217    default :
218        // Reduce all hex values slightly to avoid all white.
219        array_walk($rgb, create_function('&$v', '$v = dechex(round(hexdec($v) * 0.87));'));
220        break;
221    case 2 :
222        foreach ($rgb as $i => $v) {
223            if (hexdec($v) > hexdec('c')) {
224                $rgb[$i] = dechex(hexdec('f') - hexdec($v));
225            }
226        }
227        break;
228    }
229
230    return join('', $rgb);
231}
232
233/**
234 * Encodes a string into unicode values 128-255.
235 * Useful for hiding an email address from spambots.
236 *
237 * @access  public
238 * @param   string   $text   A line of text to encode.
239 * @return  string   Encoded text.
240 */
241function encodeAscii($text)
242{
243    $output = '';
244    $num = mb_strlen($text);
245    for ($i=0; $i<$num; $i++) {
246        $output .= sprintf('&#%03s', ord($text{$i}));
247    }
248    return $output;
249}
250
251/**
252 * Encodes an email into a "user at domain dot com" format.
253 *
254 * @access  public
255 * @param   string   $email   An email to encode.
256 * @param   string   $at      Replaces the @.
257 * @param   string   $dot     Replaces the ..
258 * @return  string   Encoded email.
259 */
260function encodeEmail($email, $at=' at ', $dot=' dot ')
261{
262    $search = array('/@/', '/\./');
263    $replace = array($at, $dot);
264    return preg_replace($search, $replace, $email);
265}
266
267/**
268 * Turns "a really long string" into "a rea...string"
269 *
270 * @access  public
271 * @param   string  $str    Input string
272 * @param   int     $len    Maximum string length.
273 * @param   string  $where  Where to cut the string. One of: 'start', 'middle', or 'end'.
274 * @return  string          Truncated output string
275 * @author  Quinn Comendant <quinn@strangecode.com>
276 * @since   29 Mar 2006 13:48:49
277 */
278function truncate($str, $len, $where='end', $delim='
')
279{
280    if ($len <= 3 || mb_strlen($str) <= 3) {
281        return '';
282    }
283    $part1 = floor(($len - 3) / 2);
284    $part2 = ceil(($len - 3) / 2);
285    switch ($where) {
286    case 'start' :
287        return preg_replace(array(sprintf('/^.{4,}(.{%s})$/sU', $part1 + $part2), '/\s*\.{3,}\s*/sU'), array($delim . '$1', $delim), $str);
288        break;
289    default :
290    case 'middle' :
291        return preg_replace(array(sprintf('/^(.{%s}).{4,}(.{%s})$/sU', $part1, $part2), '/\s*\.{3,}\s*/sU'), array('$1' . $delim . '$2', $delim), $str);
292        break;   
293    case 'end' :
294        return preg_replace(array(sprintf('/^(.{%s}).{4,}$/sU', $part1 + $part2), '/\s*\.{3,}\s*/sU'), array('$1' . $delim, $delim), $str);
295        break;
296    }
297}
298
299/*
300* A substitution for the missing mb_ucfirst function.
301*
302* @access   public
303* @param    string  $string The string
304* @return   string          String with upper-cased first character.
305* @author   Quinn Comendant <quinn@strangecode.com>
306* @version  1.0
307* @since    06 Dec 2008 17:04:01
308*/
309if (!function_exists('mb_ucfirst')) {   
310    function mb_ucfirst($string)
311    {
312        return mb_strtoupper(mb_substr($string, 0, 1)) . mb_substr($string, 1, mb_strlen($string));
313    }
314}
315
316/*
317* A substitution for the missing mb_strtr function.
318*
319* @access   public
320* @param    string  $string The string
321* @param    string  $from   String of characters to translate from
322* @param    string  $to     String of characters to translate to
323* @return   string          String with translated characters.
324* @author   Quinn Comendant <quinn@strangecode.com>
325* @version  1.0
326* @since    20 Jan 2013 12:33:26
327*/
328if (!function_exists('mb_strtr')) {   
329    function mb_strtr($string, $from, $to)
330    {
331        return str_replace(mb_split('.', $from), mb_split('.', $to), $string);
332    }
333}
334
335/**
336 * Return a human readable disk space measurement. Input value measured in bytes.
337 *
338 * @param       int    $size        Size in bytes.
339 * @param       int    $unit        The maximum unit
340 * @param       int    $format      The return string format
341 * @author      Aidan Lister <aidan@php.net>
342 * @author      Quinn Comendant <quinn@strangecode.com>
343 * @version     1.2.0
344 */
345function humanFileSize($size, $format='%01.2f %s', $max_unit=null, $multiplier=1024)
346{
347    // Units
348    $units = array('B', 'KB', 'MB', 'GB', 'TB');
349    $ii = count($units) - 1;
350
351    // Max unit
352    $max_unit = array_search((string) $max_unit, $units);
353    if ($max_unit === null || $max_unit === false) {
354        $max_unit = $ii;
355    }
356
357    // Loop
358    $i = 0;
359    while ($max_unit != $i && $size >= $multiplier && $i < $ii) {
360        $size /= $multiplier;
361        $i++;
362    }
363
364    return sprintf($format, $size, $units[$i]);
365}
366
367/*
368* Returns a human readable amount of time for the given amount of seconds.
369*
370* 45 seconds
371* 12 minutes
372* 3.5 hours
373* 2 days
374* 1 week
375* 4 months
376*
377* Months are calculated using the real number of days in a year: 365.2422 / 12.
378*
379* @access   public
380* @param    int $seconds Seconds of time.
381* @param    string $max_unit Key value from the $units array.
382* @param    string $format Sprintf formatting string.
383* @return   string Value of units elapsed.
384* @author   Quinn Comendant <quinn@strangecode.com>
385* @version  1.0
386* @since    23 Jun 2006 12:15:19
387*/
388function humanTime($seconds, $max_unit=null, $format='%01.1f')
389{
390    // Units: array of seconds in the unit, singular and plural unit names.
391    $units = array(
392        'second' => array(1, _("second"), _("seconds")),
393        'minute' => array(60, _("minute"), _("minutes")),
394        'hour' => array(3600, _("hour"), _("hours")),
395        'day' => array(86400, _("day"), _("days")),
396        'week' => array(604800, _("week"), _("weeks")),
397        'month' => array(2629743.84, _("month"), _("months")),
398        'year' => array(31556926.08, _("year"), _("years")),
399        'decade' => array(315569260.8, _("decade"), _("decades")),
400        'century' => array(3155692608, _("century"), _("centuries")),
401    );
402   
403    // Max unit to calculate.
404    $max_unit = isset($units[$max_unit]) ? $max_unit : 'year';
405
406    $final_time = $seconds;
407    $final_unit = 'second';
408    foreach ($units as $k => $v) {
409        if ($seconds >= $v[0]) {
410            $final_time = $seconds / $v[0];
411            $final_unit = $k;
412        }
413        if ($max_unit == $final_unit) {
414            break;
415        }
416    }
417    $final_time = sprintf($format, $final_time);
418    return sprintf('%s %s', $final_time, (1 == $final_time ? $units[$final_unit][1] : $units[$final_unit][2]));   
419}
420
421/**
422 * Tests the existence of a file anywhere in the include path.
423 *
424 * @param   string  $file   File in include path.
425 * @return  mixed           False if file not found, the path of the file if it is found.
426 * @author  Quinn Comendant <quinn@strangecode.com>
427 * @since   03 Dec 2005 14:23:26
428 */
429function fileExistsIncludePath($file)
430{
431    $app =& App::getInstance();
432   
433    foreach (explode(PATH_SEPARATOR, get_include_path()) as $path) {
434        $fullpath = $path . DIRECTORY_SEPARATOR . $file;
435        if (file_exists($fullpath)) {
436            $app->logMsg(sprintf('Found file "%s" at path: %s', $file, $fullpath), LOG_DEBUG, __FILE__, __LINE__);
437            return $fullpath;
438        } else {
439            $app->logMsg(sprintf('File "%s" not found in include_path: %s', $file, get_include_path()), LOG_DEBUG, __FILE__, __LINE__);
440            return false;
441        }
442    }
443}
444
445/**
446 * Returns stats of a file from the include path.
447 *
448 * @param   string  $file   File in include path.
449 * @param   mixed   $stat   Which statistic to return (or null to return all).
450 * @return  mixed           Value of requested key from fstat(), or false on error.
451 * @author  Quinn Comendant <quinn@strangecode.com>
452 * @since   03 Dec 2005 14:23:26
453 */
454function statIncludePath($file, $stat=null)
455{
456    // Open file pointer read-only using include path.
457    if ($fp = fopen($file, 'r', true)) {
458        // File opened successfully, get stats.
459        $stats = fstat($fp);
460        fclose($fp);
461        // Return specified stats.
462        return is_null($stat) ? $stats : $stats[$stat];
463    } else {
464        return false;
465    }
466}
467
468/*
469* Writes content to the specified file. This function emulates the functionality of file_put_contents from PHP 5.
470* It makes an exclusive lock on the file while writing.
471*
472* @access   public
473* @param    string  $filename   Path to file.
474* @param    string  $content    Data to write into file.
475* @return   bool                Success or failure.
476* @author   Quinn Comendant <quinn@strangecode.com>
477* @since    11 Apr 2006 22:48:30
478*/
479function filePutContents($filename, $content)
480{
481    $app =& App::getInstance();
482
483    // Open file for writing and truncate to zero length.
484    if ($fp = fopen($filename, 'w')) {
485        if (flock($fp, LOCK_EX)) {
486            if (!fwrite($fp, $content, mb_strlen($content))) {
487                $app->logMsg(sprintf('Failed writing to file: %s', $filename), LOG_ERR, __FILE__, __LINE__);
488                fclose($fp);
489                return false;
490            }
491            flock($fp, LOCK_UN);
492        } else {
493            $app->logMsg(sprintf('Could not lock file for writing: %s', $filename), LOG_ERR, __FILE__, __LINE__);
494            fclose($fp);
495            return false;
496        }
497        fclose($fp);
498        // Success!
499        $app->logMsg(sprintf('Wrote to file: %s', $filename), LOG_DEBUG, __FILE__, __LINE__);
500        return true;
501    } else {
502        $app->logMsg(sprintf('Could not open file for writing: %s', $filename), LOG_ERR, __FILE__, __LINE__);
503        return false;
504    }
505}
506
507/**
508 * If $var is net set or null, set it to $default. Otherwise leave it alone.
509 * Returns the final value of $var. Use to find a default value of one is not available.
510 *
511 * @param  mixed $var       The variable that is being set.
512 * @param  mixed $default   What to set it to if $val is not currently set.
513 * @return mixed            The resulting value of $var.
514 */
515function setDefault(&$var, $default='')
516{
517    if (!isset($var)) {
518        $var = $default;
519    }
520    return $var;
521}
522
523/**
524 * Like preg_quote() except for arrays, it takes an array of strings and puts
525 * a backslash in front of every character that is part of the regular
526 * expression syntax.
527 *
528 * @param  array $array    input array
529 * @param  array $delim    optional character that will also be escaped.
530 * @return array    an array with the same values as $array1 but shuffled
531 */
532function pregQuoteArray($array, $delim='/')
533{
534    if (!empty($array)) {
535        if (is_array($array)) {
536            foreach ($array as $key=>$val) {
537                $quoted_array[$key] = preg_quote($val, $delim);
538            }
539            return $quoted_array;
540        } else {
541            return preg_quote($array, $delim);
542        }
543    }
544}
545
546/**
547 * Converts a PHP Array into encoded URL arguments and return them as an array.
548 *
549 * @param  mixed $data        An array to transverse recursively, or a string
550 *                            to use directly to create url arguments.
551 * @param  string $prefix     The name of the first dimension of the array.
552 *                            If not specified, the first keys of the array will be used.
553 * @return array              URL with array elements as URL key=value arguments.
554 */
555function urlEncodeArray($data, $prefix='', $_return=true)
556{
557    // Data is stored in static variable.
558    static $args;
559
560    if (is_array($data)) {
561        foreach ($data as $key => $val) {
562            // If the prefix is empty, use the $key as the name of the first dimension of the "array".
563            // ...otherwise, append the key as a new dimension of the "array".
564            $new_prefix = ('' == $prefix) ? urlencode($key) : $prefix . '[' . urlencode($key) . ']';
565            // Enter recursion.
566            urlEncodeArray($val, $new_prefix, false);
567        }
568    } else {
569        // We've come to the last dimension of the array, save the "array" and its value.
570        $args[$prefix] = urlencode($data);
571    }
572
573    if ($_return) {
574        // This is not a recursive execution. All recursion is complete.
575        // Reset static var and return the result.
576        $ret = $args;
577        $args = array();
578        return is_array($ret) ? $ret : array();
579    }
580}
581
582/**
583 * Converts a PHP Array into encoded URL arguments and return them in a string.
584 *
585 * @param  mixed $data        An array to transverse recursively, or a string
586 *                            to use directly to create url arguments.
587 * @param  string $prefix     The name of the first dimension of the array.
588 *                            If not specified, the first keys of the array will be used.
589 * @return string url         A string ready to append to a url.
590 */
591function urlEncodeArrayToString($data, $prefix='')
592{
593
594    $array_args = urlEncodeArray($data, $prefix);
595    $url_args = '';
596    $delim = '';
597    foreach ($array_args as $key=>$val) {
598        $url_args .= $delim . $key . '=' . $val;
599        $delim = ini_get('arg_separator.output');
600    }
601    return $url_args;
602}
603
604/**
605 * Fills an array with the result from a multiple ereg search.
606 * Courtesy of Bruno - rbronosky@mac.com - 10-May-2001
607 *
608 * @param  mixed $pattern   regular expression needle
609 * @param  mixed $string   haystack
610 * @return array    populated with each found result
611 */
612function eregAll($pattern, $string)
613{
614    do {
615        if (!mb_ereg($pattern, $string, $temp)) {
616             continue;
617        }
618        $string = str_replace($temp[0], '', $string);
619        $results[] = $temp;
620    } while (mb_ereg($pattern, $string, $temp));
621    return $results;
622}
623
624/**
625 * Prints the word "checked" if a variable is set, and optionally matches
626 * the desired value, otherwise prints nothing,
627 * used for printing the word "checked" in a checkbox form input.
628 *
629 * @param  mixed $var     the variable to compare
630 * @param  mixed $value   optional, what to compare with if a specific value is required.
631 */
632function frmChecked($var, $value=null)
633{
634    if (func_num_args() == 1 && $var) {
635        // 'Checked' if var is true.
636        echo ' checked="checked" ';
637    } else if (func_num_args() == 2 && $var == $value) {
638        // 'Checked' if var and value match.
639        echo ' checked="checked" ';
640    } else if (func_num_args() == 2 && is_array($var)) {
641        // 'Checked' if the value is in the key or the value of an array.
642        if (isset($var[$value])) {
643            echo ' checked="checked" ';
644        } else if (in_array($value, $var)) {
645            echo ' checked="checked" ';
646        }
647    }
648}
649
650/**
651 * prints the word "selected" if a variable is set, and optionally matches
652 * the desired value, otherwise prints nothing,
653 * otherwise prints nothing, used for printing the word "checked" in a
654 * select form input
655 *
656 * @param  mixed $var     the variable to compare
657 * @param  mixed $value   optional, what to compare with if a specific value is required.
658 */
659function frmSelected($var, $value=null)
660{
661    if (func_num_args() == 1 && $var) {
662        // 'selected' if var is true.
663        echo ' selected="selected" ';
664    } else if (func_num_args() == 2 && $var == $value) {
665        // 'selected' if var and value match.
666        echo ' selected="selected" ';
667    } else if (func_num_args() == 2 && is_array($var)) {
668        // 'selected' if the value is in the key or the value of an array.
669        if (isset($var[$value])) {
670            echo ' selected="selected" ';
671        } else if (in_array($value, $var)) {
672            echo ' selected="selected" ';
673        }
674    }
675}
676
677/**
678 * Adds slashes to values of an array and converts the array to a comma
679 * delimited list. If value provided is a string return the string
680 * escaped.  This is useful for putting values coming in from posted
681 * checkboxes into a SET column of a database.
682 *
683 *
684 * @param  array $in      Array to convert.
685 * @return string         Comma list of array values.
686 */
687function escapedList($in, $separator="', '")
688{
689    $db =& DB::getInstance();
690   
691    if (is_array($in) && !empty($in)) {
692        return join($separator, array_map(array($db, 'escapeString'), $in));
693    } else {
694        return $db->escapeString($in);
695    }
696}
697
698/**
699 * Converts a human string date into a SQL-safe date.  Dates nearing
700 * infinity use the date 2038-01-01 so conversion to unix time format
701 * remain within valid range.
702 *
703 * @param  array $date     String date to convert.
704 * @param  array $format   Date format to pass to date().
705 *                         Default produces MySQL datetime: 0000-00-00 00:00:00.
706 * @return string          SQL-safe date.
707 */
708function strToSQLDate($date, $format='Y-m-d H:i:s')
709{
710    // Translate the human string date into SQL-safe date format.
711    if (empty($date) || mb_strpos($date, '0000-00-00') !== false || strtotime($date) === -1 || strtotime($date) === false) {
712        // Return a string of zero time, formatted the same as $format.
713        return strtr($format, array(
714            'Y' => '0000',
715            'm' => '00',
716            'd' => '00',
717            'H' => '00',
718            'i' => '00',
719            's' => '00',
720        ));
721    } else {
722        return date($format, strtotime($date));
723    }
724}
725
726/**
727 * If magic_quotes_gpc is in use, run stripslashes() on $var. If $var is an
728 * array, stripslashes is run on each value, recursively, and the stripped
729 * array is returned.
730 *
731 * @param  mixed $var   The string or array to un-quote, if necessary.
732 * @return mixed        $var, minus any magic quotes.
733 */
734function dispelMagicQuotes($var)
735{
736    static $magic_quotes_gpc;
737
738    if (!isset($magic_quotes_gpc)) {
739        $magic_quotes_gpc = get_magic_quotes_gpc();
740    }
741
742    if ($magic_quotes_gpc) {
743        if (!is_array($var)) {
744            $var = stripslashes($var);
745        } else {
746            foreach ($var as $key=>$val) {
747                if (is_array($val)) {
748                    $var[$key] = dispelMagicQuotes($val);
749                } else {
750                    $var[$key] = stripslashes($val);
751                }
752            }
753        }
754    }
755    return $var;
756}
757
758/**
759 * Get a form variable from GET or POST data, stripped of magic
760 * quotes if necessary.
761 *
762 * @param string $var (optional) The name of the form variable to look for.
763 * @param string $default (optional) The value to return if the
764 *                                   variable is not there.
765 * @return mixed      A cleaned GET or POST if no $var specified.
766 * @return string     A cleaned form $var if found, or $default.
767 */
768function getFormData($var=null, $default=null)
769{
770    if ('POST' == getenv('REQUEST_METHOD') && is_null($var)) {
771        return dispelMagicQuotes($_POST);
772    } else if ('GET' == getenv('REQUEST_METHOD') && is_null($var)) {
773        return dispelMagicQuotes($_GET);
774    }
775    if (isset($_POST[$var])) {
776        return dispelMagicQuotes($_POST[$var]);
777    } else if (isset($_GET[$var])) {
778        return dispelMagicQuotes($_GET[$var]);
779    } else {
780        return $default;
781    }
782}
783function getPost($var=null, $default=null)
784{
785    if (is_null($var)) {
786        return dispelMagicQuotes($_POST);
787    }
788    if (isset($_POST[$var])) {
789        return dispelMagicQuotes($_POST[$var]);
790    } else {
791        return $default;
792    }
793}
794function getGet($var=null, $default=null)
795{
796    if (is_null($var)) {
797        return dispelMagicQuotes($_GET);
798    }
799    if (isset($_GET[$var])) {
800        return dispelMagicQuotes($_GET[$var]);
801    } else {
802        return $default;
803    }
804}
805
806/*
807* Sets a $_GET or $_POST variable.
808*
809* @access   public
810* @param    string  $key    The key of the request array to set.
811* @param    mixed   $val    The value to save in the request array.
812* @return   void
813* @author   Quinn Comendant <quinn@strangecode.com>
814* @version  1.0
815* @since    01 Nov 2009 12:25:29
816*/
817function putFormData($key, $val)
818{
819    if ('POST' == getenv('REQUEST_METHOD')) {
820        $_POST[$key] = $val;
821    } else if ('GET' == getenv('REQUEST_METHOD')) {
822        $_GET[$key] = $val;
823    }
824}
825
826/**
827 * Signs a value using md5 and a simple text key. In order for this
828 * function to be useful (i.e. secure) the key must be kept secret, which
829 * means keeping it as safe as database credentials. Putting it into an
830 * environment variable set in httpd.conf is a good place.
831 *
832 * @access  public
833 * @param   string  $val    The string to sign.
834 * @param   string  $salt   (Optional) A text key to use for computing the signature.
835 * @param   string  $length (Optional) The length of the added signature. Longer signatures are safer. Must match the length passed to verifySignature() for the signatures to match.
836 * @return  string  The original value with a signature appended.
837 */
838function addSignature($val, $salt=null, $length=18)
839{
840    $app =& App::getInstance();
841   
842    if ('' == trim($val)) {
843        $app->logMsg(sprintf('Cannot add signature to an empty string.', null), LOG_INFO, __FILE__, __LINE__);
844        return '';
845    }
846
847    if (!isset($salt)) {
848        $salt = $app->getParam('signing_key');
849    }
850   
851    // TODO: consider using more bits-per-character, such as done with:
852    // http://www.php.net/manual/en/function.sha1.php#86239
853    // http://blog.kevburnsjr.com/php-unique-hash
854    return $val . '-' . mb_strtolower(mb_substr(md5($salt . md5($val . $salt)), 0, $length));
855}
856
857/**
858 * Strips off the signature appended by addSignature().
859 *
860 * @access  public
861 * @param   string  $signed_val     The string to sign.
862 * @return  string  The original value with a signature removed.
863 */
864function removeSignature($signed_val)
865{
866    if (empty($signed_val) || mb_strpos($signed_val, '-') === false) {
867        return '';
868    }
869    return mb_substr($signed_val, 0, mb_strrpos($signed_val, '-'));
870}
871
872/**
873 * Verifies a signature appened to a value by addSignature().
874 *
875 * @access  public
876 * @param   string  $signed_val A value with appended signature.
877 * @param   string  $salt       (Optional) A text key to use for computing the signature.
878 * @return  bool    True if the signature matches the var.
879 */
880function verifySignature($signed_val, $salt=null, $length=18)
881{
882    // All comparisons are done using lower-case strings.
883    $signed_val = mb_strtolower($signed_val);
884    // Strip the value from the signed value.
885    $val = removeSignature($signed_val);
886    // If the signed value matches the original signed value we consider the value safe.
887    if ($signed_val == addSignature($val, $salt, $length)) {
888        // Signature verified.
889        return true;
890    } else {
891        return false;
892    }
893}
894
895/**
896 * Sends empty output to the browser and flushes the php buffer so the client
897 * will see data before the page is finished processing.
898 */
899function flushBuffer()
900{
901    echo str_repeat('          ', 205);
902    flush();
903}
904
905/**
906 * Adds email address to mailman mailing list. Requires /etc/sudoers entry for apache to sudo execute add_members.
907 * Don't forget to allow php_admin_value open_basedir access to "/var/mailman/bin".
908 *
909 * @access  public
910 * @param   string  $email     Email address to add.
911 * @param   string  $list      Name of list to add to.
912 * @param   bool    $send_welcome_message   True to send welcome message to subscriber.
913 * @return  bool    True on success, false on failure.
914 */
915function mailmanAddMember($email, $list, $send_welcome_message=false)
916{
917    $app =& App::getInstance();
918   
919    $add_members = '/usr/lib/mailman/bin/add_members';
920    /// FIXME: checking of executable is disabled.
921    if (true || is_executable($add_members) && is_readable($add_members)) {
922        $welcome_msg = $send_welcome_message ? 'y' : 'n';
923        exec(sprintf("/bin/echo '%s' | /usr/bin/sudo %s -r - --welcome-msg=%s --admin-notify=n '%s'", escapeshellarg($email), escapeshellarg($add_members), $welcome_msg, escapeshellarg($list)), $stdout, $return_code);
924        if (0 == $return_code) {
925            $app->logMsg(sprintf('Mailman add member success for list: %s, user: %s', $list, $email), LOG_INFO, __FILE__, __LINE__);
926            return true;
927        } else {
928            $app->logMsg(sprintf('Mailman add member failed for list: %s, user: %s, with message: %s', $list, $email, getDump($stdout)), LOG_WARNING, __FILE__, __LINE__);
929            return false;
930        }
931    } else {
932        $app->logMsg(sprintf('Mailman add member program not executable: %s', $add_members), LOG_ALERT, __FILE__, __LINE__);
933        return false;
934    }
935}
936
937/**
938 * Removes email address from mailman mailing list. Requires /etc/sudoers entry for apache to sudo execute add_members.
939 * Don't forget to allow php_admin_value open_basedir access to "/var/mailman/bin".
940 *
941 * @access  public
942 * @param   string  $email     Email address to add.
943 * @param   string  $list      Name of list to add to.
944 * @param   bool    $send_user_ack   True to send goodbye message to subscriber.
945 * @return  bool    True on success, false on failure.
946 */
947function mailmanRemoveMember($email, $list, $send_user_ack=false)
948{
949    $app =& App::getInstance();
950   
951    $remove_members = '/usr/lib/mailman/bin/remove_members';
952    /// FIXME: checking of executable is disabled.
953    if (true || is_executable($remove_members) && is_readable($remove_members)) {
954        $userack = $send_user_ack ? '' : '--nouserack';
955        exec(sprintf("/usr/bin/sudo %s %s --noadminack '%s' '%s'", escapeshellarg($remove_members), $userack, escapeshellarg($list), escapeshellarg($email)), $stdout, $return_code);
956        if (0 == $return_code) {
957            $app->logMsg(sprintf('Mailman remove member success for list: %s, user: %s', $list, $email), LOG_INFO, __FILE__, __LINE__);
958            return true;
959        } else {
960            $app->logMsg(sprintf('Mailman remove member failed for list: %s, user: %s, with message: %s', $list, $email, $stdout), LOG_WARNING, __FILE__, __LINE__);
961            return false;
962        }
963    } else {
964        $app->logMsg(sprintf('Mailman remove member program not executable: %s', $remove_members), LOG_ALERT, __FILE__, __LINE__);
965        return false;
966    }
967}
968
969/**
970 * Returns the remote IP address, taking into consideration proxy servers.
971 *
972 * @param  bool $dolookup   If true we resolve to IP to a host name,
973 *                          if false we don't.
974 * @return string    IP address if $dolookup is false or no arg
975 *                   Hostname if $dolookup is true
976 */
977function getRemoteAddr($dolookup=false)
978{
979    $ip = getenv('HTTP_CLIENT_IP');
980    if (in_array($ip, array('', 'unknown', 'localhost', '127.0.0.1'))) {
981        $ip = getenv('HTTP_X_FORWARDED_FOR');
982        if (mb_strpos($ip, ',') !== false) {
983            // If HTTP_X_FORWARDED_FOR returns a comma-delimited list of IPs then return the first one (assuming the first is the original).
984            $ips = explode(',', $ip, 2);
985            $ip = $ips[0];
986        }
987        if (in_array($ip, array('', 'unknown', 'localhost', '127.0.0.1'))) {
988            $ip = getenv('REMOTE_ADDR');
989        }
990    }
991    return $dolookup && '' != $ip ? gethostbyaddr($ip) : $ip;
992}
993
994/**
995 * Tests whether a given IP address can be found in an array of IP address networks.
996 * Elements of networks array can be single IP addresses or an IP address range in CIDR notation
997 * See: http://en.wikipedia.org/wiki/Classless_inter-domain_routing
998 *
999 * @access  public
1000 * @param   string  IP address to search for.
1001 * @param   array   Array of networks to search within.
1002 * @return  mixed   Returns the network that matched on success, false on failure.
1003 */
1004function ipInRange($ip, $networks)
1005{
1006    if (!is_array($networks)) {
1007        $networks = array($networks);
1008    }
1009
1010    $ip_binary = sprintf('%032b', ip2long($ip));
1011    foreach ($networks as $network) {
1012        if (preg_match('![\d\.]{7,15}/\d{1,2}!', $network)) {
1013            // IP is in CIDR notation.
1014            list($cidr_ip, $cidr_bitmask) = explode('/', $network);
1015            $cidr_ip_binary = sprintf('%032b', ip2long($cidr_ip));
1016            if (mb_substr($ip_binary, 0, $cidr_bitmask) === mb_substr($cidr_ip_binary, 0, $cidr_bitmask)) {
1017               // IP address is within the specified IP range.
1018               return $network;
1019            }
1020        } else {
1021            if ($ip === $network) {
1022               // IP address exactly matches.
1023               return $network;
1024            }
1025        }
1026    }
1027
1028    return false;
1029}
1030
1031/**
1032 * If the given $url is on the same web site, return true. This can be used to
1033 * prevent from sending sensitive info in a get query (like the SID) to another
1034 * domain.
1035 *
1036 * @param  string $url    the URI to test.
1037 * @return bool True if given $url is our domain or has no domain (is a relative url), false if it's another.
1038 */
1039function isMyDomain($url)
1040{
1041    static $urls = array();
1042
1043    if (!isset($urls[$url])) {
1044        if (!preg_match('|https?://[\w.]+/|', $url)) {
1045            // If we can't find a domain we assume the URL is local (i.e. "/my/url/path/" or "../img/file.jpg").
1046            $urls[$url] = true;
1047        } else {
1048            $urls[$url] = preg_match('|https?://[\w.]*' . preg_quote(getenv('HTTP_HOST'), '|') . '|i', $url);
1049        }
1050    }
1051    return $urls[$url];
1052}
1053
1054/**
1055 * Takes a URL and returns it without the query or anchor portion
1056 *
1057 * @param  string $url   any kind of URI
1058 * @return string        the URI with ? or # and everything after removed
1059 */
1060function stripQuery($url)
1061{
1062    return preg_replace('/[?#].*$/', '', $url);
1063}
1064
1065/**
1066 * Returns a fully qualified URL to the current script, including the query.
1067 *
1068 * @return string    a full url to the current script
1069 */
1070function absoluteMe()
1071{
1072    $protocol = ('on' == getenv('HTTPS')) ? 'https://' : 'http://';
1073    return $protocol . getenv('HTTP_HOST') . getenv('REQUEST_URI');
1074}
1075
1076/**
1077 * Compares the current url with the referring url.
1078 *
1079 * @param  bool $exclude_query  Remove the query string first before comparing.
1080 * @return bool                 True if the current URL is the same as the referring URL, false otherwise.
1081 */
1082function refererIsMe($exclude_query=false)
1083{
1084    if ($exclude_query) {
1085        return (stripQuery(absoluteMe()) == stripQuery(getenv('HTTP_REFERER')));
1086    } else {
1087        return (absoluteMe() == getenv('HTTP_REFERER'));
1088    }
1089}
Note: See TracBrowser for help on using the repository browser.