3 This include() script adds missing PHP functions to earlier interpreter
4 versions, so you can make downwards compatible scripts without having
5 to stick to the least common denominator. It only defines the ones that
6 are really missing - the faster native functions will be used whenever
9 - many of the emulation functions are one-liners
10 - a few features have been added that never made it into one of the
11 official versions (CVS code and the ever-absent "gzdecode" and
12 "file_put_contents" for example)
13 - a few very extravagant functions (array_u?diff*_u*assoc?) and other
14 extensions have been separated out into ext/
15 - the advanced OO-capabilities and language syntax extensions of PHP5
16 and ZE2 cannot seriously be emulated here, this script only takes care
17 of procedural interfaces
18 - with only this part loaded, you get "PHP 4.1 COMPATIBILITY"
19 - this is PuplicDomain (no copyright, no license, no warranty) so you
20 can melt it into anything, regardless of your preferred license (you
21 may strip this paragraph and turn it all into GPL, BSD, GNU LGPL,
22 Artistic, MPL, PHP license, M$ EULA, or whatever you like best)
24 Get update notes via "http://freshmeat.net/projects/upgradephp" or
25 google for it. Any contribution is appreciated. <milky*users·sf·net>
30 #------------------------------------------------------------------ CVS ---
31 // most of this appeared in 5.0
37 #------------------------------------------------------------------ 6.0 ---
38 // following functions were never implemented in PHP
41 #-- inflates a string enriched with gzip headers
42 # (this is the logical counterpart to gzencode(), but don't tell anyone!)
43 if (!function_exists("gzdecode")) {
44 function gzdecode($data, $maxlen=NULL) {
51 $head = substr($data, 0, 10);
52 $head = unpack("n1id/C1cm/C1flg/V1mtime/C1xfl/C1os", $head);
53 list($ID, $CM, $FLG, $MTIME, $XFL, $OS) = array_values($head);
59 $head = unpack("V1crc/V1isize", substr($data, $len-8, 8));
60 list($CRC32, $ISIZE) = array_values($head);
62 #-- check gzip stream identifier
64 trigger_error("gzdecode: not in gzip format", E_USER_WARNING);
67 #-- check for deflate algorithm
69 trigger_error("gzdecode: cannot decode anything but deflated streams", E_USER_WARNING);
73 #-- start of data, skip bonus fields
79 $s = strpos($data, "\000", $s) + 1;
81 if ($FLG & $FCOMMENT) {
82 $s = strpos($data, "\000", $s) + 1;
85 $s += 2; // cannot check
88 #-- get data, uncompress
89 $data = substr($data, $s, $len-$s);
91 $data = gzinflate($data, $maxlen);
92 return($data); // no checks(?!)
95 $data = gzinflate($data);
100 if ($CRC32 != $chk) {
101 trigger_error("gzdecode: checksum failed (real$chk != comp$CRC32)", E_USER_WARNING);
103 elseif ($ISIZE != strlen($data)) {
104 trigger_error("gzdecode: stream size mismatch", E_USER_WARNING);
113 #-- get all already made headers(),
114 # CANNOT be emulated, because output buffering functions
115 # already swallow up any sent http header
116 if (!function_exists("ob_get_headers")) {
117 function ob_get_headers() {
123 #-- encodes required named XML entities, like htmlentities(),
124 # but does not re-encode numeric &#xxxx; character references
125 # - could screw up scripts which then implement this themselves
126 # - doesn't fix bogus or invalid numeric entities
127 if (!function_exists("xmlentities")) {
128 function xmlentities($str) {
129 return strtr($str, array(
130 "&#"=>"&#", "&"=>"&", "'"=>"'",
131 "<"=>"<", ">"=>">", "\""=>""",
138 #------------------------------------------------------------------ 5.0 ---
139 # set_exception_handler - unimpl.
140 # restore_exception_handler - unimpl.
141 # debug_print_backtrace - unimpl.
142 # class_implements - unimplementable
143 # proc_terminate - unimpl?
144 # proc_get_status - unimpl.
148 # date_sunrise - undoc.
149 # date_sunset - undoc.
153 #-- constant: end of line
154 if (!defined("PHP_EOL")) {
155 define("PHP_EOL", ( (DIRECTORY_SEPARATOR == "\\") ?"\015\012" :(strncmp(PHP_OS,"D",1)?"\012":"\015") ) ); #"
159 #-- case-insensitive string search function,
160 # - finds position of first occourence of a string c-i
161 # - parameters identical to strpos()
162 if (!function_exists("stripos")) {
163 function stripos($haystack, $needle, $offset=NULL) {
165 #-- simply lowercase args
166 $haystack = strtolower($haystack);
167 $needle = strtolower($needle);
170 $pos = strpos($haystack, $needle, $offset);
176 #-- case-insensitive string search function
177 # - but this one starts from the end of string (right to left)
178 # - offset can be negative or positive
179 if (!function_exists("strripos")) {
180 function strripos($haystack, $needle, $offset=NULL) {
182 #-- lowercase incoming strings
183 $haystack = strtolower($haystack);
184 $needle = strtolower($needle);
186 #-- [-]$offset tells to ignore a few string bytes,
187 # we simply cut a bit from the right
188 if (isset($offset) && ($offset < 0)) {
189 $haystack = substr($haystack, 0, strlen($haystack) - 1);
193 $pos = strrpos($haystack, $needle);
195 #-- [+]$offset => ignore left haystack bytes
196 if (isset($offset) && ($offset > 0) && ($pos > $offset)) {
206 #-- case-insensitive version of str_replace
207 if (!function_exists("str_ireplace")) {
208 function str_ireplace($search, $replace, $subject, $count=NULL) {
210 #-- call ourselves recursively, if parameters are arrays/lists
211 if (is_array($search)) {
212 $replace = array_values($replace);
213 foreach (array_values($search) as $i=>$srch) {
214 $subject = str_ireplace($srch, $replace[$i], $subject);
218 #-- sluice replacement strings through the Perl-regex module
219 # (faster than doing it by hand)
221 $replace = addcslashes($replace, "$\\");
222 $search = "{" . preg_quote($search) . "}i";
223 $subject = preg_replace($search, $replace, $subject);
232 #-- performs a http HEAD request
233 if (!function_exists("get_headers")) {
234 function get_headers($url, $parse=0) {
236 #-- extract URL parts ($host, $port, $path, ...)
237 $c = parse_url($url);
243 #-- try to open TCP connection
244 $f = fsockopen($host, $port, $errno, $errstr, $timeout=15);
249 #-- send request header
250 socket_set_blocking($f, true);
251 fwrite($f, "HEAD $path HTTP/1.0\015\012"
252 . "Host: $host\015\012"
253 . "Connection: close\015\012"
254 . "Accept: */*, xml/*\015\012"
255 . "User-Agent: ".trim(ini_get("user_agent"))."\015\012"
258 #-- read incoming lines
260 while ( !feof($f) && ($line = trim(fgets($f, 1<<16))) ) {
262 #-- read header names to make result an hash (names in array index)
264 if ($l = strpos($line, ":")) {
265 $name = substr($line, 0, $l);
266 $value = trim(substr($line, $l + 1));
268 if (isset($ls[$name])) {
269 $ls[$name] .= ", $value";
275 #-- HTTP response status header as result[0]
281 #-- unparsed header list (numeric indices)
287 #-- close TCP connection and give result
294 #-- list of already/potentially sent HTTP responsee headers(),
295 # CANNOT be implemented (except for Apache module maybe)
296 if (!function_exists("headers_list")) {
297 function headers_list() {
298 trigger_error("headers_list(): not supported by this PHP version", E_USER_WARNING);
304 #-- write formatted string to stream/file,
305 # arbitrary numer of arguments
306 if (!function_exists("fprintf")) {
307 function fprintf(/*...*/) {
308 $args = func_get_args();
309 $stream = array_shift($args);
310 return fwrite($stream, call_user_func_array("sprintf", $args));
315 #-- write formatted string to stream, args array
316 if (!function_exists("vfprintf")) {
317 function vfprintf($stream, $format, $args=NULL) {
318 return fwrite($stream, vsprintf($format, $args));
323 #-- splits a string in evenly sized chunks
324 # and returns this as array
325 if (!function_exists("str_split")) {
326 function str_split($str, $chunk=1) {
329 #-- return back as one chunk completely, if size chosen too low
334 #-- add substrings to result array until subject strings end reached
337 for ($n=0; $n<$len; $n+=$chunk) {
338 $r[] = substr($str, $n, $chunk);
346 #-- constructs a QUERY_STRING (application/x-www-form-urlencoded format, non-raw)
347 # from a nested array/hash with name=>value pairs
348 # - only first two args are part of the original API - rest used for recursion
349 if (!function_exists("http_build_query")) {
350 function http_build_query($data, $int_prefix="", $subarray_pfix="", $level=0) {
352 #-- empty starting string
354 ($SEP = ini_get("arg_separator.output")) or ($SEP = "&");
356 #-- traverse hash/array/list entries
357 foreach ($data as $index=>$value) {
359 #-- add sub_prefix for subarrays (happens for recursed innovocation)
360 if ($subarray_pfix) {
362 $index = "[" . $index . "]";
364 $index = $subarray_pfix . $index;
366 #-- add user-specified prefix for integer-indices
367 elseif (is_int($index) && strlen($int_prefix)) {
368 $index = $int_prefix . $index;
371 #-- recurse for sub-arrays
372 if (is_array($value)) {
373 $s .= http_build_query($value, "", $index, $level + 1);
375 else { // or just literal URL parameter
376 $s .= $SEP . $index . "=" . urlencode($value);
380 #-- remove redundant "&" from first round (-not checked above to simplifiy loop)
381 if (!$subarray_pfix) {
382 $s = substr($s, strlen($SEP));
385 #-- return result / to previous array level and iteration
391 #-- transform into 3to4 uuencode
392 # - this is the bare encoding, not the uu file format
393 if (!function_exists("convert_uuencode")) {
394 function convert_uuencode($data) {
399 $len = strlen($data);
400 # $data .= "\252\252\252"; // PHP and uuencode(1) use some special garbage??, looks like "\000"* and "`\n`" simply appended
402 #-- canvass source string
403 for ($n=0; $n<$len; ) {
405 #-- make 24-bit integer from first three bytes
406 $x = (ord($data[$n++]) << 16)
407 + (ord($data[$n++]) << 8)
408 + (ord($data[$n++]) << 0);
410 #-- disperse that into 4 ascii characters
411 $line .= chr( 32 + (($x >> 18) & 0x3f) )
412 . chr( 32 + (($x >> 12) & 0x3f) )
413 . chr( 32 + (($x >> 6) & 0x3f) )
414 . chr( 32 + (($x >> 0) & 0x3f) );
416 #-- cut lines, inject count prefix before each
417 if (($n % 45) == 0) {
418 $out .= chr(32 + 45) . "$line\n";
423 #-- throw last line, +length prefix
424 if ($trail = ($len % 45)) {
425 $out .= chr(32 + $trail) . "$line\n";
428 // uuencode(5) doesn't tell so, but spaces are replaced with the ` char in most implementations
429 $out = strtr("$out \n", " ", "`");
435 #-- decodes uuencoded() data again
436 if (!function_exists("convert_uudecode")) {
437 function convert_uudecode($data) {
441 $data = strtr($data, "`", " ");
444 foreach(explode("\n", ltrim($data)) as $line) {
445 if (!strlen($line)) {
446 break; // end reached
449 #-- current line length prefix
451 $num = ord($line{0}) - 32;
452 if (($num <= 0) || ($num > 62)) { // 62 is the maximum line length
453 break; // according to uuencode(5), so we stop here too
455 $line = substr($line, 1);
457 #-- prepare to decode 4-char chunks
459 for ($n=0; strlen($add)<$num; ) {
461 #-- merge 24 bit integer from the 4 ascii characters (6 bit each)
462 $x = ((ord($line[$n++]) - 32) << 18)
463 + ((ord($line[$n++]) - 32) << 12) // were saner with "& 0x3f"
464 + ((ord($line[$n++]) - 32) << 6)
465 + ((ord($line[$n++]) - 32) << 0);
467 #-- reconstruct the 3 original data chars
468 $add .= chr( ($x >> 16) & 0xff )
469 . chr( ($x >> 8) & 0xff )
470 . chr( ($x >> 0) & 0xff );
473 #-- cut any trailing garbage (last two decoded chars may be wrong)
474 $out .= substr($add, 0, $num);
483 #-- return array of filenames in a given directory
484 # (only works for local files)
485 if (!function_exists("scandir")) {
486 function scandir($dirname, $desc=0) {
488 #-- check for file:// protocol, others aren't handled
489 if (strpos($dirname, "file://") === 0) {
490 $dirname = substr($dirname, 7);
491 if (strpos($dirname, "localh") === 0) {
492 $dirname = substr($dirname, strpos($dirname, "/"));
496 #-- directory reading handle
497 if ($dh = opendir($dirname)) {
499 while ($fn = readdir($dh)) {
500 $ls[] = $fn; // add to array
520 #-- like date(), but returns an integer for given one-letter format parameter
521 if (!function_exists("idate")) {
522 function idate($formatchar, $timestamp=NULL) {
524 #-- reject non-simple type parameters
525 if (strlen($formatchar) != 1) {
529 #-- get current time, if not given
530 if (!isset($timestamp)) {
534 #-- get and turn into integer
535 $str = date($formatchar, $timestamp);
542 #-- combined sleep() and usleep()
543 if (!function_exists("time_nanosleep")) {
544 function time_nanosleep($sec, $nano) {
552 #-- search first occourence of any of the given chars, returns rest of haystack
553 # (char_list must be a string for compatibility with the real PHP func)
554 if (!function_exists("strpbrk")) {
555 function strpbrk($haystack, $char_list) {
558 $len = strlen($char_list);
559 $min = strlen($haystack);
561 #-- check with every symbol from $char_list
562 for ($n = 0; $n < $len; $n++) {
563 $l = strpos($haystack, $char_list{$n});
565 #-- get left-most occourence
566 if (($l !== false) && ($l < $min)) {
573 return(substr($haystack, $min));
583 #-- logo image activation URL query strings (gaga feature)
584 if (!function_exists("php_real_logo_guid")) {
585 function php_real_logo_guid() { return php_logo_guid(); }
586 function php_egg_logo_guid() { return zend_logo_guid(); }
590 #-- no need to implement this
591 # (there aren't interfaces in PHP4 anyhow)
592 if (!function_exists("get_declared_interfaces")) {
593 function get_declared_interfaces() {
594 trigger_error("get_declared_interfaces(): Current script won't run reliably with PHP4.", E_USER_WARNING);
595 return( (array)NULL );
600 #-- creates an array from lists of $keys and $values
601 # (both should have same number of entries)
602 if (!function_exists("array_combine")) {
603 function array_combine($keys, $values) {
605 #-- convert input arrays into lists
606 $keys = array_values($keys);
607 $values = array_values($values);
611 foreach ($values as $i=>$val) {
612 if ($key = $keys[$i]) {
616 $r[] = $val; // useless, PHP would have long aborted here
624 #-- apply userfunction to each array element (descending recursively)
625 # use it like: array_walk_recursive($_POST, "stripslashes");
626 # - $callback can be static function name or object/method, class/method
627 if (!function_exists("array_walk_recursive")) {
628 function array_walk_recursive(&$input, $callback, $userdata=NULL) {
630 foreach ($input as $key=>$value) {
632 #-- recurse for sub-arrays
633 if (is_array($value)) {
634 array_walk_recursive($input[$key], $callback, $userdata);
637 #-- $callback handles scalars
639 call_user_func_array($callback, array(&$input[$key], $key, $userdata) );
648 #-- complicated wrapper around substr() and and strncmp()
649 if (!function_exists("substr_compare")) {
650 function substr_compare($haystack, $needle, $offset=0, $len=0, $ci=0) {
653 if ($len <= 0) { // not well documented
654 $len = strlen($needle);
655 if (!$len) { return(0); }
658 if ($len + $offset >= strlen($haystack)) {
659 trigger_error("substr_compare: given length exceeds main_str", E_USER_WARNING);
665 $haystack = substr($haystack, $offset, $len);
667 #-- case-insensitivity
669 $haystack = strtolower($haystack);
670 $needle = strtolower($needle);
674 return(strncmp($haystack, $needle, $len));
679 #-- stub, returns empty list as usual;
680 # you must load "ext/spl.php" beforehand to get this
681 if (!function_exists("spl_classes")) {
682 function spl_classes() {
683 trigger_error("spl_classes(): not built into this PHP version");
690 #-- gets you list of class names the given objects class was derived from, slow
691 if (!function_exists("class_parents")) {
692 function class_parents($obj) {
694 #-- first get full list
695 $all = get_declared_classes();
699 foreach ($all as $potential_parent) {
700 if (is_subclass_of($obj, $potential_parent)) {
701 $r[$potential_parent] = $potential_parent;
710 if (!function_exists("session_commit") && function_exists("session_write_close")) {
711 function session_commit() {
713 session_write_close();
719 if (!function_exists("dns_check_record")) {
720 function dns_check_record($host, $type=NULL) {
722 return checkdnsrr($host, $type);
725 if (!function_exists("dns_get_mx")) {
726 function dns_get_mx($host, $mx) {
727 $args = func_get_args();
728 // simple alias - except the optional, but referenced third parameter
735 return getmxrr($host, $mx, $w);
741 # can this be emulated 100% exactly?
742 if (!function_exists("setrawcookie")) {
743 // we output everything directly as HTTP header(), PHP doesn't seem
744 // to manage an internal cookie list anyhow
745 function setrawcookie($name, $value=NULL, $expire=NULL, $path=NULL, $domain=NULL, $secure=0) {
746 if (isset($value) && strpbrk($value, ",; \r\t\n\f\014\013")) {
747 trigger_error("setrawcookie: value may not contain any of ',; \r\n' and some other control chars; thrown away", E_USER_WARNING);
750 $h = "Set-Cookie: $name=$value"
751 . ($expire ? "; expires=" . gmstrftime("%a, %d-%b-%y %H:%M:%S %Z", $expire) : "")
752 . ($path ? "; path=$path": "")
753 . ($domain ? "; domain=$domain" : "")
754 . ($secure ? "; secure" : "");
761 #-- write-at-once file access (counterpart to file_get_contents)
762 if (!function_exists("file_put_contents")) {
763 function file_put_contents($filename, $data, $flags=0, $resource=NULL) {
766 $mode = ($flags & FILE_APPEND ? "a" : "w" ) ."b";
767 $incl = $flags & FILE_USE_INCLUDE_PATH;
768 $length = strlen($data);
771 $f = fopen($filename, $mode, $incl);
773 $written = fwrite($f, $data);
776 #-- only report success, if completely saved
777 return($length == $written);
783 #-- file-related constants
784 if (!defined("FILE_APPEND")) {
785 define("FILE_USE_INCLUDE_PATH", 1);
786 define("FILE_IGNORE_NEW_LINES", 2);
787 define("FILE_SKIP_EMPTY_LINES", 4);
788 define("FILE_APPEND", 8);
789 define("FILE_NO_DEFAULT_CONTEXT", 16);
793 #-- more new constants for 5.0
794 if (!defined("E_STRICT")) {
795 define("E_STRICT", 2048); // _STRICT is a special case of _NOTICE (_DEBUG)
796 # PHP_CONFIG_FILE_SCAN_DIR
800 #-- array count_recursive()
801 if (!defined("COUNT_RECURSIVE")) {
802 define("COUNT_NORMAL", 0); // count($array, 0);
803 define("COUNT_RECURSIVE", 1); // not supported
807 #-- we introduce a new function, because we cannot emulate the
808 # newly introduced second parameter to count()
809 if (!function_exists("count_recursive")) {
810 function count_recursive($array, $mode=1) {
812 return(count($array));
816 foreach ($array as $sub) {
817 if (is_array($sub)) {
818 $c += count_recursive($sub);
832 #------------------------------------------------------------------ 4.3 ---
833 # money_format - unimpl?
834 # sha1, sha1_file - too much code to pack it into here; and this
835 # has already been implemented elsewhere, btw
838 #-- simplified file read-at-once function
839 if (!function_exists("file_get_contents")) {
840 function file_get_contents($filename, $use_include_path=1) {
842 #-- open file, let fopen() report error
843 $f = fopen($filename, "rb", $use_include_path);
847 $content = fread($f, 1<<21);
855 #-- shell-like filename matching (* and ? globbing characters)
856 if (!function_exists("fnmatch")) {
858 #-- associated constants
859 define("FNM_PATHNAME", 1<<0); // no wildcard ever matches a "/"
860 define("FNM_NOESCAPE", 1<<1); // backslash can't escape meta chars
861 define("FNM_PERIOD", 1<<2); // leading dot must be given explicit
862 define("FNM_LEADING_DIR", 1<<3); // not in PHP
863 define("FNM_CASEFOLD", 0x50); // match case-insensitive
864 define("FNM_EXTMATCH", 1<<5); // not in PHP
867 function fnmatch($pattern, $str, $flags=0x0000) {
870 if ($flags & FNM_PERIOD) {
871 if (($str[0] == ".") && ($pattern[0] != ".")) {
872 return(false); // abort early
876 #-- case-insensitivity
878 if ($flags & FNM_CASEFOLD) {
881 #-- handline of pathname separators (/)
883 if ($flags & FNM_PATHNAME) {
884 $wild = "[^/".DIRECTORY_SEPARATOR.DIRECTORY_SEPARATOR."]";
887 #-- check for cached regular expressions
888 static $cmp = array();
889 if (isset($cmp["$pattern+$flags"])) {
890 $rx = $cmp["$pattern+$flags"];
893 #-- convert filename globs into regex
895 $rx = preg_quote($pattern);
896 $rx = strtr($rx, array(
897 "\\*"=>"$wild*?", "\\?"=>"$wild", "\\["=>"[", "\\]"=>"]",
899 $rx = "{^" . $rx . "$}" . $rxci;
902 if (count($cmp) >= 50) {
903 $cmp = array(); // free
905 $cmp["$pattern+$flags"] = $rx;
909 return(preg_match($rx, $str));
914 #-- file search and name matching (with shell patterns)
915 if (!function_exists("glob")) {
917 #-- introduced constants
918 define("GLOB_MARK", 1<<0);
919 define("GLOB_NOSORT", 1<<1);
920 define("GLOB_NOCHECK", 1<<2);
921 define("GLOB_NOESCAPE", 1<<3);
922 define("GLOB_BRACE", 1<<4);
923 define("GLOB_ONLYDIR", 1<<5);
924 define("GLOB_NOCASE", 1<<6);
925 define("GLOB_DOTS", 1<<7);
926 // unlikely to work under Win(?), without replacing the explode() with
927 // a preg_split() incorporating the native DIRECTORY_SEPARATOR as well
930 function glob($pattern, $flags=0x0000) {
932 $rxci = ($flags & GLOB_NOCASE) ? "i" : "";
933 #echo "\n=> glob($pattern)...\n";
935 #-- transform glob pattern into regular expression
936 # (similar to fnmatch() but still different enough to require a second func)
939 #-- look at each directory/fn spec part separately
940 $parts2 = explode("/", $pattern);
941 $pat = preg_quote($pattern);
942 $pat = strtr($pat, array("\\*"=>".*?", "\\?"=>".?"));
943 if ($flags ^ GLOB_NOESCAPE) {
944 // uh, oh, ouuch - the above is unclean enough...
946 if ($flags ^ GLOB_BRACE) {
947 $pat = preg_replace("/\{(.+?)\}/e", 'strtr("[$1]", ",", "")', $pat);
949 $parts = explode("/", $pat);
950 #echo "parts == ".implode(" // ", $parts) . "\n";
951 $lasti = count($parts) - 1;
953 foreach ($parts as $i=>$p) {
955 #-- basedir included (yet no pattern matching necessary)
956 if (!strpos($p, "*?") && (strpos($p, ".?")===false)) {
957 $dn .= $parts2[$i] . ($i!=$lasti ? "/" : "");
958 #echo "skip:$i, cause no pattern matching char found -> only a basedir spec\n";
962 #-- start reading dir + match filenames against current pattern
963 if ($dh = opendir($dn ?$dn:'.')) {
964 $with_dot = ($p[1]==".") || ($flags & GLOB_DOTS);
965 #echo "part:$i:$p\n";
966 #echo "reading dir \"$dn\"\n";
967 while ($fn = readdir($dh)) {
968 if (preg_match("\007^$p$\007$rxci", $fn)) {
970 #-- skip over 'hidden' files
971 if (($fn[0] == ".") && !$with_dot) {
975 #-- add filename only if last glob/pattern part
977 if (is_dir("$dn$fn")) {
978 if ($flags & GLOB_ONLYDIR) {
981 if ($flags & GLOB_MARK) {
985 #echo "adding '$fn' for dn=$dn to list\n";
989 #-- initiate a subsearch, merge result list in
990 elseif (is_dir("$dn$fn")) {
991 // add reamaining search patterns to current basedir
992 $remaind = implode("/", array_slice($parts2, $i+1));
993 $ls = array_merge($ls, glob("$dn$fn/$remaind", $flags));
999 #-- prevent scanning a 2nd part/dir in same glob() instance:
1003 #-- given dirname doesn't exist
1011 #-- return result list
1012 if (!$ls && ($flags & GLOB_NOCHECK)) {
1015 if ($flags ^ GLOB_NOSORT) {
1022 } //@FIX: fully comment, remove debugging code (- as soon as it works ;)
1025 #-- redundant alias for isset()
1026 if (!function_exists("array_key_exists")) {
1027 function array_key_exists($key, $search) {
1028 return isset($search[$key]);
1033 #-- who could need that?
1034 if (!function_exists("array_intersect_assoc")) {
1035 function array_intersect_assoc( /*array, array, array...*/ ) {
1037 #-- parameters, prepare
1038 $in = func_get_args();
1040 $whatsleftover = array();
1042 #-- walk through each array pair
1043 # (take first as checklist)
1044 foreach ($in[0] as $i => $v) {
1045 for ($c = 1; $c < $cmax; $c++) {
1046 #-- remove entry, as soon as it isn't present
1047 # in one of the other arrays
1048 if (!isset($in[$c][$i]) || (@$in[$c][$i] !== $v)) {
1052 #-- it was found in all other arrays
1053 $whatsleftover[$i] = $v;
1055 return $whatsleftover;
1060 #-- the opposite of the above
1061 if (!function_exists("array_diff_assoc")) {
1062 function array_diff_assoc( /*array, array, array...*/ ) {
1065 $in = func_get_args();
1068 #-- compare each array with primary/first
1069 foreach ($in[0] as $i=>$v) {
1070 for ($c=1; $c<count($in); $c++) {
1071 #-- skip as soon as it matches with entry in another array
1072 if (isset($in[$c][$i]) && ($in[$c][$i] == $v)) {
1084 #-- opposite of htmlentities
1085 if (!function_exists("html_entity_decode")) {
1086 function html_entity_decode($string, $quote_style=ENT_COMPAT, $charset="ISO-8859-1") {
1087 //@FIX: we fall short on anything other than Latin-1
1088 $y = array_flip(get_html_translation_table(HTML_ENTITIES, $quote_style));
1089 return strtr($string, $y);
1094 #-- extracts single words from a string
1095 if (!function_exists("str_word_count")) {
1096 function str_word_count($string, $result=0) {
1098 #-- let someone else do the work
1099 preg_match_all('/([\w](?:[-\'\w]?[\w]+)*)/', $string, $uu);
1101 #-- return full word list
1106 #-- array() of $pos=>$word entries
1107 elseif ($result >= 2) {
1110 foreach ($uu[1] as $word) {
1111 $l = strpos($string, $word, $l);
1113 $l += strlen($word); // speed up next search
1120 return(count($uu[1]));
1126 #-- creates a permutation of the given strings characters
1127 # (let's hope the random number generator was alread initialized)
1128 if (!function_exists("str_shuffle")) {
1129 function str_shuffle($str) {
1132 #-- cut string down with every iteration
1133 while (strlen($str)) {
1134 $n = strlen($str) - 1;
1136 $n = rand(0, $n); // glibcs` rand is ok since 2.1 at least
1139 #-- cut out elected char, add to result string
1141 $str = substr($str, 0, $n) . substr($str, $n + 1);
1148 #-- simple shorthands
1149 if (!function_exists("get_include_path")) {
1150 function get_include_path() {
1151 return(get_cfg_var("include_path"));
1153 function set_include_path($new) {
1154 return ini_set("include_path", $new);
1156 function restore_include_path() {
1157 ini_restore("include_path");
1162 #-- constants for 4.3
1163 if (!defined("PATH_SEPARATOR")) {
1164 define("PATH_SEPARATOR", ((DIRECTORY_SEPARATOR=='\\') ? ';' :':'));
1165 define("PHP_SHLIB_SUFFIX", ((DIRECTORY_SEPARATOR=='\\') ? 'dll' :'so'));
1167 if (!defined("PHP_SAPI")) {
1168 define("PHP_SAPI", php_sapi_name());
1172 #-- not identical to what PHP reports (it seems to `which` for itself)
1173 if (!defined("PHP_PREFIX") && isset($_ENV["_"])) {
1174 define("PHP_PREFIX", substr($_ENV["_"], 0, strpos($_ENV["_"], "bin/")));
1182 #------------------------------------------------------------------ 4.2 ---
1186 #-- shy away from this one - it was broken in all real PHP4.2 versions, and
1187 # this function emulation script won't change that
1188 if (!function_exists("str_rot13")) {
1189 function str_rot13($str) {
1190 static $from = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
1191 static $to = "NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm";
1192 return strtr($str, $from, $to);
1197 #-- well, if you need it
1198 if (!function_exists("array_change_key_case")) {
1200 #-- introduced constants
1201 define("CASE_LOWER", 0);
1202 define("CASE_UPPER", 1);
1205 function array_change_key_case($array, $case=CASE_LOWER) {
1208 foreach ($array as $i=>$v) {
1209 #-- do anything for strings only
1210 if (is_string($i)) {
1212 $i = ($case==CASE_LOWER) ? strtolower($i) : strtoupper($i);
1222 #-- create fixed-length array made up of $value data
1223 if (!function_exists("array_fill")) {
1224 function array_fill($start_index, $num, $value) {
1229 $end = $num + $start_index;
1232 for (; $i < $end; $i++)
1241 #-- split an array into evenly sized parts
1242 if (!function_exists("array_chunk")) {
1243 function array_chunk($input, $size, $preserve_keys=false) {
1245 #-- array for chunked output
1247 $n = -1; // chunk index
1249 #-- enum input array blocks
1250 foreach ($input as $i=>$v) {
1253 if (($n < 0) || (count($r[$n]) == $size)) {
1258 #-- add input value into current [$n] chunk
1259 if ($preserve_keys) {
1271 #-- convenience wrapper
1272 if (!function_exists("md5_file")) {
1273 function md5_file($filename, $raw_output=false) {
1275 #-- read file, apply hash function
1276 $data = file_get_contents($filename, "rb");
1280 #-- transform? and return
1282 $r = pack("H*", $r);
1289 #-- object type checking
1290 if (!function_exists("is_a")) {
1291 function is_a($obj, $classname) {
1293 #-- lowercase everything for comparison
1294 $classnaqme = strtolower($classname);
1295 $obj_class = strtolower(get_class($obj));
1297 #-- two possible checks
1298 return ($obj_class == $classname) or is_subclass_of($obj, $classname);
1303 #-- floating point modulo
1304 if (!function_exists("fmod")) {
1305 function fmod($x, $y) {
1314 #-- makes float variable from string
1315 if (!function_exists("floatval")) {
1316 function floatval($str) {
1324 if (!function_exists("is_infinite")) {
1327 define("NAN", "NAN");
1328 define("INF", "INF"); // there is also "-INF"
1331 function is_infinite($f) {
1333 return( ($s=="INF") || ($s=="-INF") );
1335 function is_nan($f) {
1337 return( $s=="NAN" );
1339 function is_finite($f) {
1341 return( !strpos($s, "N") );
1346 #-- throws value-instantiation PHP-code for given variable
1347 # (a bit different from the standard, was intentional for its orig use)
1348 if (!function_exists("var_export")) {
1349 function var_export($var, $return=false, $indent="", $output="") {
1351 #-- output as in-class variable definitions
1352 if (is_object($var)) {
1353 $output = "class " . get_class($var) . " {\n";
1354 foreach (((array)$var) as $id=>$var) {
1355 $output .= " var \$$id = " . var_export($var, true) . ";\n";
1360 #-- array constructor
1361 elseif (is_array($var)) {
1362 foreach ($var as $id=>$next) {
1363 if ($output) $output .= ",\n";
1364 else $output = "array(\n";
1365 $output .= $indent . ' '
1366 . (is_numeric($id) ? $id : '"'.addslashes($id).'"')
1367 . ' => ' . var_export($next, true, "$indent ");
1369 if (empty($output)) $output = "array(";
1370 $output .= "\n{$indent})";
1371 #if ($indent == "") $output .= ";";
1375 elseif (is_numeric($var)) {
1378 elseif (is_bool($var)) {
1379 $output = $var ? "true" : "false";
1382 $output = "'" . preg_replace("/([\\\\\'])/", '\\\\$1', $var) . "'";
1396 #-- strcmp() variant that respects locale setting,
1397 # existed since PHP 4.0.5, but under Win32 first since 4.3.2
1398 if (!function_exists("strcoll")) {
1399 function strcoll($str1, $str2) {
1400 return strcmp($str1, $str2);
1408 #------------------------------------------------------------------ 4.1 ---
1409 # nl_langinfo - unimpl?
1413 # See also "ext/math41.php" for some more (rarely used mathematical funcs).
1418 #-- aliases (an earlier fallen attempt to unify PHP function names)
1419 if (!function_exists("diskfreespace")) {
1420 function diskfreespace() {
1421 return disk_free_sapce();
1423 function disktotalspace() {
1424 return disk_total_sapce();
1429 #-- variable count of arguments (in array list) printf variant
1430 if (!function_exists("vprintf")) {
1431 function vprintf($format, $args=NULL) {
1432 call_user_func_array("fprintf", get_func_args());
1437 #-- same as above, but doesn't output directly and returns formatted string
1438 if (!function_exists("vsprintf")) {
1439 function vsprintf($format, $args=NULL) {
1440 $args = array_merge(array($format), array_values((array)$args));
1441 return call_user_func_array("sprintf", $args);
1446 #-- can be used to simulate a register_globals=on environment
1447 if (!function_exists("import_request_variables")) {
1448 function import_request_variables($types="GPC", $pfix="") {
1450 #-- associate abbreviations to global var names
1455 "S" => "_SERVER", // non-standard
1456 "E" => "_ENV", // non-standard
1458 #-- alias long names (PHP < 4.0.6)
1459 if (!isset($_REQUEST)) {
1460 $_GET = & $HTTP_GET_VARS;
1461 $_POST = & $HTTP_POST_VARS;
1462 $_COOKIE = & $HTTP_COOKIE_VARS;
1466 for ($i=0; $i<strlen($types); $i++) {
1467 if ($FROM = $alias[strtoupper($c)]) {
1468 foreach ($$FROM as $key=>$val) {
1469 if (!isset($GLOBALS[$pfix.$key])) {
1470 $GLOBALS[$pfix . $key] = $val;
1480 // a few mathematical functions follow
1481 // (wether we should really emulate them is a different question)
1483 #-- me has no idea what this function means
1484 if (!function_exists("hypot")) {
1485 function hypot($num1, $num2) {
1486 return sqrt($num1*$num1 + $num2*$num2); // as per PHP manual ;)
1490 #-- more accurate logarithm func, but we cannot simulate it
1491 # (too much work, too slow in PHP)
1492 if (!function_exists("log1p")) {
1493 function log1p($x) {
1494 return( log(1+$x) );
1497 function expm1($x) {
1498 return( exp($x)-1 );
1502 #-- as per PHP manual
1503 if (!function_exists("sinh")) {
1505 return( (exp($f) - exp(-$f)) / 2 );
1508 return( (exp($f) + exp(-$f)) / 2 );
1511 return( sinh($f) / cosh($f) ); // ok, that one makes sense again :)
1515 #-- these look a bit more complicated
1516 if (!function_exists("asinh")) {
1517 function asinh($x) {
1518 return( log($x + sqrt($x*$x+1)) );
1520 function acosh($x) {
1521 return( log($x + sqrt($x*$x-1)) );
1523 function atanh($x) {
1524 return( log1p( 2*$x / (1-$x) ) / 2 );
1529 #-- HMAC from RFC2104, but see also PHP_Compat and Crypt_HMAC
1530 if (!function_exists("mhash")) {
1533 define("MHASH_CRC32", 0);
1534 define("MHASH_MD5", 1); // RFC1321
1535 define("MHASH_SHA1", 2); // RFC3174
1536 define("MHASH_TIGER", 7);
1537 define("MHASH_MD4", 16); // RFC1320
1538 define("MHASH_SHA256", 17);
1539 define("MHASH_ADLER32", 18);
1542 function mhash($hashtype, $text, $key) {
1545 static $hash_funcs = array(
1546 MHASH_CRC32 => "crc32", // needs dechex()ing here
1548 MHASH_SHA1 => "sha1",
1550 if (!($func = $hash_funcs[$hashtype]) || !function_exists($func)) {
1551 return trigger_error("mhash: cannot use hash algorithm #$hashtype/$func", E_USER_ERROR);
1554 trigger_error("mhash: called without key", E_USER_WARNING);
1558 $bsize = 64; // fixed size
1561 if (strlen($key) > $bsize) { // hash key, when it's too long
1563 $key = pack("H*", $key); // binarify
1565 $key = str_pad($key, $bsize, "\0"); // fill up with NULs (1)
1567 #-- prepare inner and outer padding stream
1568 $ipad = str_pad("", $bsize, "6"); // %36
1569 $opad = str_pad("", $bsize, "\\"); // %5C
1571 #-- call hash func // php can XOR strings for us
1572 $dgst = pack("H*", $func( ($key ^ $ipad) . $text )); // (2,3,4)
1573 $dgst = pack("H*", $func( ($key ^ $opad) . $dgst )); // (5,6,7)
1589 // no need to implement anything below that, because such old versions
1590 // will be incompatbile anyhow (- none of the newer superglobals known),
1591 // but see also "ext/old"