Check-in [bcf7d8cbab]
Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Comment: | upgradephp-12 |
---|---|
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
bcf7d8cbab53b6c9dac3c0a1ab6418a4 |
User & Date: | mario 2010-06-22 16:59:47 |
2010-06-22
| ||
17:03 | upgradephp-13 check-in: b5c10771ec user: mario tags: trunk | |
16:59 | upgradephp-12 check-in: bcf7d8cbab user: mario tags: trunk | |
16:46 | upgradephp-11 check-in: 8c74990127 user: mario tags: trunk | |
Changes to README.
1 2 3 4 5 6 | PHP downwards compatibility functions ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ Because web hosters often run outdated PHP interpreter versions, there are regularily functions missing. This can prevent certain scripts from running, if those were written with later interpeter | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | PHP downwards compatibility functions ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ Because web hosters often run outdated PHP interpreter versions, there are regularily functions missing. This can prevent certain scripts from running, if those were written with later interpeter versions in mind. Sourceforge.net still makes a good example. The include script presented here emulates most such functions, if it detects that something is missing. You can therefore now reliably use a few of the advanced (later introduced) PHP core functions, by simply loading this script. This effectively frees you from wasting time with backwards compatibility problems and even avoiding certain useful additions from newer PHP |
︙ | ︙ | |||
29 30 31 32 33 34 35 | Some of the functions that get defined here, are just simple stubs; sometimes only there to prevent E_FATAL errors. The emulated functions sometimes run slower than the native variant would, but it generally shouldn't be slower than any workaround you used for the [advanced but not widely available] functions until | | > > | | | | | > | | | | | | | | 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 | Some of the functions that get defined here, are just simple stubs; sometimes only there to prevent E_FATAL errors. The emulated functions sometimes run slower than the native variant would, but it generally shouldn't be slower than any workaround you used for the [advanced but not widely available] functions until now. Most emulation functions leave the error reporting up to the called parent functions (fopen, fwrite and call_user_func_array for example). PEAR::PHP_Compat ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ Only after finishing release 5 of this library I found out, that such a thing already exists. You should fetch the PEAR package "PHP_Compat" (by Aidan Lister & Co.) from [http://pear.php.net/], and give that a try also. Because it existed a while longer, it should be free of bugs meanwhile. It btw, provides more functions than "upgrade.php" in some areas (4.0.x emulations for example), and it is more accurate in simulating PHPs warning messages and correctly checking or sanitizing parameters, comes under the PHP license and has more precise inline comments. You could get something similar to this "upgrade.php" script by simply unpacking the PHP_Compat tarball and running: cat .../PHP_Compat-1.4.1/Compat/*/*.php > phpcompat.php This then was as easy to use (simply one include script) like the "upgrade.php" library as described here (and you could even load both). You may want to rip out the then so multipled license comments using `php -w` if you generate such an include script from PHP_Compat. But don't forget to mention that it comes under the PHP license, if you then repackage this with any application or script you are distributing. And, btw IMO, in this case it was simply the drawback of the PEAR coding standards, that PHP_Compat looks a bit shattered at first - it just had to be made a bit "OO", because that's the magic entry ticket buzzword for the PEAR repository. And before someone complains: No code from PHP_Compat has been used to produce "upgrade.php", but I'll happily take ideas from there, and especially the function-introduction/version data from it and PEAR::PHP_CompatInfo will help finishing this library (apparantly contains more accurate hints than the PHP manual). |
︙ | ︙ | |||
84 85 86 87 88 89 90 | You could additionally check the PHP_VERSION (by using the function version_compare() for example), and only include the emulation wrapper if you depend on features from a certain PHP interpreter release: <?example | | | 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | You could additionally check the PHP_VERSION (by using the function version_compare() for example), and only include the emulation wrapper if you depend on features from a certain PHP interpreter release: <?example if (PHP_VERSION < "4.3.0") { include(".../upgrade.php"); } ?> Currently following functions can be emulated: · gzdecode · ob_get_headers · xmlentities · stripos |
︙ | ︙ | |||
108 109 110 111 112 113 114 | · convert_uudecode · scandir · idate · time_nanosleep · strpbrk · php_real_logo_guid · php_egg_logo_guid | < < > | 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 | · convert_uudecode · scandir · idate · time_nanosleep · strpbrk · php_real_logo_guid · php_egg_logo_guid · get_declared_interfaces · array_combine · array_walk_recursive · substr_compare · spl_classes · class_parents · session_commit · dns_check_record · dns_get_mx · setrawcookie · file_put_contents · count_recursive · file_get_contents · fnmatch · glob · array_key_exists · array_intersect_assoc · array_diff_assoc · html_entity_decode |
︙ | ︙ | |||
160 161 162 163 164 165 166 167 168 169 170 171 172 173 | · expm1 · sinh · cosh · tanh · asinh · acosh · atanh · array_udiff_uassoc · array_udiff_assoc · array_diff_uassoc · array_udiff · array_uintersect_uassoc · array_uintersect_assoc · array_uintersect | > | 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 | · expm1 · sinh · cosh · tanh · asinh · acosh · atanh · mhash · array_udiff_uassoc · array_udiff_assoc · array_diff_uassoc · array_udiff · array_uintersect_uassoc · array_uintersect_assoc · array_uintersect |
︙ | ︙ | |||
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 | ext/ ¯¯¯¯ The ext/ subdirectory in here provides a few more or less useful emulations for various PHP extensions or function groups. · "ext/array" provides a few exotic array diff functions (for associative arrays and for using multiple callback functions) · "ext/ftp" emulates the ftp extension using only the bare socket and networking functions (should work anywhere), even has some features not found in the original · "ext/mime" simulates the mime_content_type() function, either by accessing PECL::fileinfo or reading and evaluating the magic.mime database itself (likely slower and a bit unclean of course) · "ext/dba" allows you to use scripts written for the dba module, if your interpreter only has dbm_*() functions; but only provides the minimum functionality | > > > < < < < < | 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 | ext/ ¯¯¯¯ The ext/ subdirectory in here provides a few more or less useful emulations for various PHP extensions or function groups. · "ext/array" provides a few exotic array diff functions (for associative arrays and for using multiple callback functions) · "ext/exotic" contains some rarely needed functions, which have been removed from the main file for that and other reasons · "ext/ftp" emulates the ftp extension using only the bare socket and networking functions (should work anywhere), even has some features not found in the original · "ext/mime" simulates the mime_content_type() function, either by accessing PECL::fileinfo or reading and evaluating the magic.mime database itself (likely slower and a bit unclean of course) · "ext/dba" allows you to use scripts written for the dba module, if your interpreter only has dbm_*() functions; but only provides the minimum functionality · "ext/gettext" simulates most of what gettext/libintl provides, and seems to read .mo data files correctly - plural support is however weak. There is also support for .po files, but since the libintl and original gettext functions don't normally read this, that's a useless feature (just for fun). You save 2K by ripping it out. A few snippets in there provide experimental features that aren't |
︙ | ︙ | |||
272 273 274 275 276 277 278 | dtools/ ¯¯¯¯¯¯¯ Please run the "updoc" script once to update your PHP manual, if you are planning to use the upgrade.php script. Create a symlink from your installed multi-file PHP manual to ease using this and the "doctests" utility: | | | | | | | | | | | | 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 | dtools/ ¯¯¯¯¯¯¯ Please run the "updoc" script once to update your PHP manual, if you are planning to use the upgrade.php script. Create a symlink from your installed multi-file PHP manual to ease using this and the "doctests" utility: · The "dtools/updoc" commandline script updates your local PHP documentation to carry hints about emulated functions. It'll simply add a small "EMU" on top of the supported functions` description pages (in the line typically listing the PHP versions). · "ckavail.php" was used to check for added functions between different PHP interpreter versions, purely a development script. · "dtools/doctests" greps your local PHP manual for function use examples, and executes them with the given PHP interpreter and the "upgrade.php" script loaded of course. This way you get live tests, but also see: tests/ ¯¯¯¯¯¯ Contains stupidly short scripts, that have been used to compare behaviour of the original functions to that of the emulated ones. |
︙ | ︙ | |||
309 310 311 312 313 314 315 | ¯¯¯¯¯¯¯¯ Holds a few library scripts, which are believed to be of higher quality than any of the PEAR counterparts. Probably inappropriate to place it in this tarball, but they usefully take advantage of the upgrade.php provided gzdecode(). (PEARs HTTP and XML-RPC classes don't even know about content-coding, btw). | | | | | | | | | | | | | | | | | | > > > > > > > > > > > > > > > | 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 | ¯¯¯¯¯¯¯¯ Holds a few library scripts, which are believed to be of higher quality than any of the PEAR counterparts. Probably inappropriate to place it in this tarball, but they usefully take advantage of the upgrade.php provided gzdecode(). (PEARs HTTP and XML-RPC classes don't even know about content-coding, btw). · "contrib/http" can be used to contact Web form scripts, or PHP code utilizing "ext/phprequest" more efficiently. It especially supports content-coding as per RFC2616 (HTTP standard) for saving a lot of bandwidth and getting answers faster. · "contrib/xmlrpc" likewise can compress output and is used to access XML-RPC and IETF XML+RPC Web services. It takes advantage of supported XML and EPI-XML-RPC extensions, but runs gracefully (not 100% exact XML parser) without. It was also made to provide downwards compatibility. Currently you shouldn't run it against old and not-HTTP standards-compliant servers and clients (=avoid compression unless you use it also as server or client at the other side). · "contrib/hiddenerrors" shows a nice way to hide all disturbing error messages from users, but keeping them available for development. It is especially useful, when premature _NOTICEs or _WARNINGs could garbage (XML or binary) output or if this could prevent sending any further/required HTTP headers(). · "contrib/fix.php" fights magic_quotes and register_globals (though here it's often better to let users of outdated PHP setups run into the open knife, or die() with an error message) Please also have a peek into the README files accompaning the script snippets distributed in this directory. Other Notes ¯¯¯¯¯¯¯¯¯¯¯ · Don't care about the *.meta files everywhere. They are used in other projects for plugin / include script management only and have little value else. · This script doesn't reside in any CVS/SVN reposititory currently because it is considered a too minor and small project. License ¯¯¯¯¯¯¯ Everything in here is Public Domain. There are no restrictions on how or where you could use it. You may redistribute it under any license as you wish, and you don't need to tell anyone where you got it from. |
︙ | ︙ |
Changes to contrib/README.http.
1 2 3 4 5 6 7 8 9 10 | http.php ¯¯¯¯¯¯¯¯ This script provides the easy to use "http_request" class ("http_query" is an alias). You can contact forms or simply retrieve files with it. Unlike fopen_wrappers, you get the response headers alongside and the received file will be decompressed on-the-fly (it should also be faster due to more supported compression methods). | > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | Note: This class and file will be renamed into "xhttp..." in the near feature, to prevent clashes with the old PEAR class. http.php ¯¯¯¯¯¯¯¯ This script provides the easy to use "http_request" class ("http_query" is an alias). You can contact forms or simply retrieve files with it. Unlike fopen_wrappers, you get the response headers alongside and the received file will be decompressed on-the-fly (it should also be faster due to more supported compression methods). There are some options, you can set before starting the request. Most important aspect is, that you can add form ->params[] one after the other for GET and POST requests. You can also use a proxy or include authentication passwords in the initially given url, and of course inject or override a few ->headers[] when it makes sense. |
︙ | ︙ |
Added contrib/fix.meta.
> > > > > > > | 1 2 3 4 5 6 7 | api: PHP type: intercept title: PHP fixes descriptions: removes bogus magic_quotes and left over superglobals priority: auto category: library conflicts: strike_register_globals, strip_wonderful_slashes |
Added contrib/fix.php.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | <?php /* Outdated and bogus PHP settings (register_globals and magic_quotes) are defended by this script, so code cannot be negatively impacted. It can always be loaded as it doesn't cause problems or speed disadvantages on correctly configured servers. THE "PHP.INI" SHOULD BE FIXED PREFERABLY. */ #-- strike register_globals (injected variables) if (ini_get("register_globals") == "1") { ewiki_recursive_unset($GLOBALS, $_REQUEST); ini_set("register_globals", 0); } #-- strip any \'s if magic_quotes (variable garbaging) is still enabled if (ini_get("magic_quotes_gpc") && get_magic_quotes_gpc()) { ewiki_recursive_stripslashes($_REQUEST); ewiki_recursive_stripslashes($_GET); ewiki_recursive_stripslashes($_POST); ewiki_recursive_stripslashes($_COOKIE); ewiki_recursive_stripslashes($_ENV); ewiki_recursive_stripslashes($_SERVER); ini_set("magic_quotes_gpc", 0); } #-- now that one is really dumb set_magic_quotes_runtime(0); #-- implementation function ewiki_recursive_unset(&$TO, $FROM) { foreach ($FROM as $var=>$value) { if (isset($TO[$var]) && ($TO[$var]==$FROM[$var])) { unset($TO[$var]); } } } function ewiki_recursive_stripslashes(&$var) { if (is_array($var)) { foreach ($var as $key=>$item) { ewiki_recursive_stripslashes($var[$key]); } } else { $var = stripslashes($var); } } ?> |
Changes to contrib/hiddenerrors.php.
1 2 3 4 | <?php /* The error handler provided here will feed all errors and warnings into HTTP headers of the form "X-Error-NNNNN: ...", so they can't | | | < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <?php /* The error handler provided here will feed all errors and warnings into HTTP headers of the form "X-Error-NNNNN: ...", so they can't disturb page output or make XML documents invalid. This allows to turn on complete error_reporting() without any functionality loss due to premature output. You of course need a good Web browser that can easily display all response headers then for developing. */ set_error_handler("ewiki_http_header_errors"); ini_set("html_errors", 0); function ewiki_http_header_errors($errno, $msg, $file, $line, $lvars) { |
︙ | ︙ |
Added contrib/http.meta.
> > > > > > > > > | 1 2 3 4 5 6 7 8 9 | api: PHP type: functions category: library priority: optional provides: http-request title: HTTP requests description: implements HTTP protocol, various request methods supported url: http://freshmeat.net/p/upgradephp version: 11.3 |
Changes to contrib/http.php.
︙ | ︙ | |||
46 47 48 49 50 51 52 | var $active_client = 1; // enables redirect-following var $redirects = 3; var $proxy = false; // set to "http://host:NN/" var $timeout = 15; #-- constructor | | > > > > | | | 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 | var $active_client = 1; // enables redirect-following var $redirects = 3; var $proxy = false; // set to "http://host:NN/" var $timeout = 15; #-- constructor function http_request($method="GET", $url="", $params=NULL) { $this->headers["User-Agent"] = "http_query/17.2 {$GLOBALS[ewiki_config][ua]}"; $this->headers["Accept"] = "text/html, application/xml;q=0.9, text/xml;q=0.7, xml/*;q=0.6, text/plain;q=0.5, text/*;q=0.1, image/png;q=0.8, image/*;q=0.4, */*+xml;q=0.3; application/x-msword;q=0.001, */*;q=0.075"; $this->headers["Accept-Language"] = "en, eo, es;q=0.2, fr;q=0.1, nl;q=0.1, de;q=0.1"; $this->headers["Accept-Charset"] = "iso-8859-1, utf-8"; $this->headers["Accept-Feature"] = "textonly, tables, !tcpa, !javascript, !activex, !graphic"; $this->headers["Accept-Encoding"] = "deflate, gzip, compress, x-gzip, x-bzip2"; //$this->headers["Referer"] = '$google'; $this->headers["TE"] = "identity, chunked, binary, base64"; $this->headers["Connection"] = "close"; //$this->headers["Content-Type"] = & $this->type; if (isset($params)) { $this->params = $params; } if (strpos($method, "://")) { $url = $method; # glue for incompat PEAR::Http_Request $method = "GET"; } $this->method($method); $this->setURL($url); } #-- sets request method function method($str = "GET") { $this->method = $str; } #-- special headers function setcookie($str="name=value", $add="") { $this->cookies[strtok($str,"=")] = strtok("\000").$add; } #-- deciphers URL into server+path and query string function setURL($url) { if ($this->method == "GET") { $this->url = strtok($url, "?"); |
︙ | ︙ | |||
377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 | $this->method("GET"); } $this->setURL($pri_url); $this->go(); } } } } class http_query extends http_request { /* this is just an alias */ } #-- every query result will be encoded in such an object -------------------- class http_response { var $status = 520; var $status_str = ""; var $headers_str = ""; var $headers = array(); var $len = 0; | > > > > > > > > > > > > > > > > > > > > > > > | | 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 | $this->method("GET"); } $this->setURL($pri_url); $this->go(); } } } #-- aliases for compatiblity to PEAR::HTTP_Request function sendRequest() { return $this->go(); } function setBasicAuth($user, $pw) { $this->url = preg_replace("#//(.+?@)?#", "//$user@$pw", $this->url); } function setMethod($m) { $this->method($m); } function setProxy($host, $port=8080, $user="", $pw="") { $auth = ($pw ? "$user:$pw@" : ($user ? "$user@" : "")); $this->proxy = "http://$auth$server:$port"; } function addHeader($h, $v) { $this->headers[$h] = $v; } function getResponseStatus() { $this->headers[$h] = $v; } } class http_query extends http_request { /* this is just an alias */ } #-- every query result will be encoded in such an object -------------------- class http_response { var $status = 520; var $status_str = ""; var $headers_str = ""; var $headers = array(); var $len = 0; var $type = "message/x-raw"; var $content = ""; function http_response() { } |
︙ | ︙ | |||
421 422 423 424 425 426 427 428 429 430 431 432 433 434 | $r = strpos($DATA, "\012\012"); if ($r && ($r<$l)) { $l = $r; $skip = 2; } if (!$l) { $l = strlen($DATA); } $this->headers_str = rtrim(substr($DATA, 0, $l), "\015"); $this->content = substr($DATA, $l + $skip); $this->body = & $this->content; $this->data = & $this->content; // aliases } #-- splits up the $headers_str into an array and normalizes header names function decodeHeaders() { #-- normalize linebreaks | > | 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 | $r = strpos($DATA, "\012\012"); if ($r && ($r<$l)) { $l = $r; $skip = 2; } if (!$l) { $l = strlen($DATA); } $this->headers_str = rtrim(substr($DATA, 0, $l), "\015"); $this->content = substr($DATA, $l + $skip); $this->body = & $this->content; $this->data = & $this->content; // aliases $this->ct = & $this->type; } #-- splits up the $headers_str into an array and normalizes header names function decodeHeaders() { #-- normalize linebreaks |
︙ | ︙ | |||
563 564 565 566 567 568 569 570 571 572 573 574 | return($r); } elseif ($t == "form") { // oh, not yet exactly } } } ?> | > > > > > > > > > > > > > > > > > > > > > | 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 | return($r); } elseif ($t == "form") { // oh, not yet exactly } } #-- aliases for compatiblity to PEAR::HTTP_Request function getResponseBody() { return $this->content; } function getResponseStatus() { return $this->status; } function getResponseCode() { return $this->status; } function getResponseHeader($i=NULL) { if (!isset($i)) { return $this->headers; } $i = strtolower($i); foreach ($this->headers as $h=>$v) { if (strtolower($h)==$i) { return $v; } } } } ?> |
Added contrib/http.txt.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | Note: This class and file will be renamed into "xhttp..." in the near feature, to prevent clashes with the old PEAR class. http.php ¯¯¯¯¯¯¯¯ This script provides the easy to use "http_request" class ("http_query" is an alias). You can contact forms or simply retrieve files with it. Unlike fopen_wrappers, you get the response headers alongside and the received file will be decompressed on-the-fly (it should also be faster due to more supported compression methods). There are some options, you can set before starting the request. Most important aspect is, that you can add form ->params[] one after the other for GET and POST requests. You can also use a proxy or include authentication passwords in the initially given url, and of course inject or override a few ->headers[] when it makes sense. usage ¯¯¯¯¯ It is really easy, you only must take care to always give the method parameter before the URL ("GET" or "POST" in most cases), look at the following: <?example #-- prepare $query = new http_request("GET", "http://example.com/form.php"); $query->params["q"] = "search-this-..."; #-- do request $result = $query->go(); #-- use result if ($result && ($result->status == 200)) { echo $result->content; } ?> Note, that we could have included the "q" parameter simply appended to the URL in such simple cases ("http://example.com/form.php?q=search-..."). You can also do "POST" requests (normal for forms), but that you than must decide about the encoding format. There are two for POST requests, the default is always urlencoding (like with GET requests) with <?example $query->type = "url"; // corresponds to "app/x-www-form-urlencoded" ?> but many bigger forms however require the MIME type for form-data: <?example $query->type = "form"; // translates to "multipart/form-data" ?> You see, there are easy to remember abbreviations for this. The form variables you want to transport are simply appended to the URL for GETs or "url"-coded requests, but you could use the $query->params[] array also here. If you do a "POST" request, you do likewise; or you could also just assign the $query->params a string blob to transfer as content (if the remote app can deal with it or expects that, or you already have encoded eveything into a valid form request). If you just want to add upload-files to a "POST" request, then do this as follows: <?example $query->params["fileformname"] = array( "filename" => "original-name.zip", "type" => "application/octet-stream", "content" => "$READ_FROM_FILE_DATA...", ); // or $query->params["2nd_file"] = array( "ct" => "x.ml/my-format", "name" => "../../where/is/it/from.txt", "data" => file_get_contents(".../from.txt"), ); ?> "body" is a third alias for the "content" field here. If you don't set the "type" or "ct" flag it will get "application/octet-stream" per default (this is a good default). You could simply load the "ext/mime" script to have the best possible MIME type here. start an request ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ Use the ->go() method to start a prepared HTTP request. The only alias existing today is ->start(); simply derive or edit this class to add your preferred name for this likewise (->do() cannot be used as it is a PHP reserved word, sorry ;) There are two options to ->go(), the first $force will override a few problems, and with the second ($asis) set to 1 or true, you won't get a result object, but the plain HTTP response blob (headers and response body as one large string variable). authentication ¯¯¯¯¯¯¯¯¯¯¯¯¯¯ If the remote site requires authentification, you would simply give this within the URL: <?example $query = new http_request("GET", "http://user:passw@example.com/..."); // or later: $query->setURL("http://username:pw2@server.../") // or even: $query->url = "http://name:password@localhost/form.php"; ?> proxy ¯¯¯¯¯ You can also acccess a form or remote file using a proxy server easily, just follow this: <?example $query = new http_request("PUT", "..."); $query->proxy = "http://servername.proxy.org:3219/"; // ... $result = $query->go(); ?> You could also give a password or username for your proxy server, if you need it (works the same as for above). reponses ¯¯¯¯¯¯¯¯ The $result value from the above examples should normally be an object, it will be a scalar (false) only if something went really wrong. It will have at least a ->status field, which is typically 200 for succeeded requests. Everything above 500 means an server error, values above 400 a transport and request error (= we did something wrong) and a 300 response status means a redirection was issued. For fulfilled requests you can access the returned file/data simply as "$result->content" or "$result->body" or even "$result->data" (two aliases again). You will also have a "$result->headers[]" array, which will hold all response HTTP headers in normalized form. Typically this means: <?example echo $result->headers["Content-Type"] . "\n"; echo $result->headers["Date"] . "\n"; echo $result->headers["Last-Modified"] . "\n"; echo $result->headers["Content-Length"] . "\n"; echo $result->headers["Etag"] . "\n"; // (beware of the lcased "t" !) echo $result->headers["Content-Encoding"] . "\n"; ... print_r($result->headers); // much better here ;) ?> [[ Elsewhere the field names would be completely lowercased or fully uppercase, we have CamelCase here, with the hyphens still in of course. ]] Please note, that a known "Content-Encoding" was already removed from the received ->content. And there is also a more correct "$result->len" and a "$result->type" shorthand. A few response types are understand as application data, and in this case you can call the $result->decode() function and get a PHP variable/array from the body. redirects ¯¯¯¯¯¯¯¯¯ If you expect HTTP redirects (->status codes from 300 till 375), then the default settings are ok for you, many will automatically be catched and the form data or file request will succeed at the replied URL. To tack/catch these cases yourself, simply disable that behaviour with: <?example $query->active_client = 0; ?> PHP-RPC ¯¯¯¯¯¯¯ Not yet! But this is probably what it will look like: If you control both ends of the Wire, you shouldn't use the slow and buggy (not everything works with everything else) XML-RPC protocol for calling remote functions, but instead use the high speed PHP serialize encoding to transfer data. The "http_request" class can natively encode values as such. The MIME type "application/vnd.php.serialized" has been registered explicitely for this purpose (as alternative to "multipart/form-data" encoding, and it is type-safe as opposed to the "/x-www-form-urlencoded" format). Perl and JS implementations exist (probably also one for Python), so plattform-independence should be given. PHP-RPC shall inherit (not yet negotiated) some structure from the old XML-RPC protocol. That is, a few names are identical. If you start an request you would therefore do following: <?php function phprpc($server, $function, $args=array()) { #-- init $query = new http_request("POST", $server); #-- set content $query->type = "php"; // here corresponds to "app/vnd.php.serialized" $query->params = array( "method" => $function, "params" => $args, ); #-- start $result = $query->go(); if ($result && ($result->status == 200)) { $r = $result->decode(); if ($good = $r["result"]) { return($good); } return($r); } } ?> You of course need a server part to make use of this. Simply try the "ext/phprequest", in which case you would do the following: <?php include("ext/phprequest.php") if (count($_POST) && ($method = $_POST["method"]) and ($params = $_POST["params"])) { #-- call known/registered functions $method = strtolower($method); if ($method == "my.func") { $r = call_user_func_array("my_func", $params); } elseif ($method == "system.time") { $r = time(); } elseif ($method == "sytem.listmethods") { $r = get_defined_functions(); $r = $r["user"]; } #-- if succeeded if ($r) { header("Content-Type: application/vnd.php.serialized"); header("Content-Encoding: deflate"); $r = array("result" => $r); die(gzdeflate(serialize($r)); } } #-- your normal script can go on here //... ?> You can inject this into anywhere as it only engages, if a PHP-RPC request was detected. |
Deleted contrib/upgrade.php.shortened.
|
| < |
Added contrib/xmlrpc.meta.
> > > > > > > > > | 1 2 3 4 5 6 7 8 9 | api: PHP type: api provides: rpc, xml-rpc version: 0.3.10 category: library priority: optional title: XML-RPC client and server description: serves remote procedure calls homepage: http://freshmeat.net/p/upgradephp |
Changes to contrib/xmlrpc.php.
|
| | | 1 2 3 4 5 6 7 8 | <?php define("XMLRPC_VERSION", "0.3.10"); # # Supports XML-RPC (text/xml) and XML+RPC (application/rpc+xml) compressed, # and can be used as client or server interface. Works without XMLRPC and # XML extensions, but utilizes them for optimal speed whenever available. # # XXXX XXXX MMM MMM LLL RRRRRRR PPPPPPP CCCCCCC # XXXX XXXX MMMM MMMM LLL +++ RRRRRRRR PPPPPPPP CCCCCCCCC |
︙ | ︙ | |||
37 38 39 40 41 42 43 | define("XMLRPC_MIME_OLD", "text/xml"); define("XMLRPC_MIME", XMLRPC_MIME_OLD); define("XMLRPC_ACCEPT", XMLRPC_MIME_NEW.", ".XMLRPC_MIME_OLD."; q=0.5"); define("XMLRPC_EPI", function_exists("xmlrpc_decode_request")); #-- init error_reporting(0); | > > | | 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | define("XMLRPC_MIME_OLD", "text/xml"); define("XMLRPC_MIME", XMLRPC_MIME_OLD); define("XMLRPC_ACCEPT", XMLRPC_MIME_NEW.", ".XMLRPC_MIME_OLD."; q=0.5"); define("XMLRPC_EPI", function_exists("xmlrpc_decode_request")); #-- init error_reporting(0); if (isset($_SERVER["HTTP_CONTENT_TYPE"]) && empty($_SERVER["CONTENT_TYPE"])) { $_SERVER["CONTENT_TYPE"] = $_SERVER["HTTP_CONTENT_TYPE"]; // older CGI implementations } ############################################################################ # # # client part # |
︙ | ︙ | |||
367 368 369 370 371 372 373 | $_SERVER[strtoupper(strtr("HTTP_$i", "-", "_"))] = $v; } } #-- check and get call $allowed = array( "REQUEST_METHOD" => array("POST", "PUT", "CALL"), | | | | 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 | $_SERVER[strtoupper(strtr("HTTP_$i", "-", "_"))] = $v; } } #-- check and get call $allowed = array( "REQUEST_METHOD" => array("POST", "PUT", "CALL"), "CONTENT_TYPE" => array(XMLRPC_MIME_NEW, XMLRPC_MIME_OLD), ); foreach ($allowed as $WHAT=>$WHICH) { if (!in_array(trim(strtok($WRONG=$_SERVER[$WHAT], ";,(")), $WHICH)) { header("Status: 400 Go Away, Stupid!"); if (!$WRONG) { $WRONG = "undefined"; } die("<h2>Error</h2>Your request was bogus, <b>$WHAT</b> must be <i>" . implode("</i> or <i>", $WHICH) . "</i>, but yours was '<tt>$WRONG</tt>'.\n"); } |
︙ | ︙ | |||
429 430 431 432 433 434 435 | #-- decode <methodCall> XML string into understandable chunks, # gives $params as return value and $method name via pass-by-ref function xmlrpc_request_unmarshall(&$xml_request, &$method) { #-- mangle charset if (XMLRPC_AUTO_UTF8) { | | | 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 | #-- decode <methodCall> XML string into understandable chunks, # gives $params as return value and $method name via pass-by-ref function xmlrpc_request_unmarshall(&$xml_request, &$method) { #-- mangle charset if (XMLRPC_AUTO_UTF8) { xmlrpc_decode_utf8xml($xml_request, $_SERVER["CONTENT_TYPE"].$_SERVER["HTTP_CONTENT_CHARSET"]); } #-- decode XML string into PHP arrays $call = xml2array($xml_request, 1); $xml_request = NULL; $call = $call["methodCall,0"]; |
︙ | ︙ | |||
605 606 607 608 609 610 611 | #-- error objects send itself (by calling _send_response() again ;-) if (is_object($r)) { $r->send(); } #-- answer XML-RPC and XML+RPC requests | | | 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 | #-- error objects send itself (by calling _send_response() again ;-) if (is_object($r)) { $r->send(); } #-- answer XML-RPC and XML+RPC requests $ct = trim(strtok(strtolower($_SERVER["CONTENT_TYPE"]), ";,(")); // from original request $cs = XMLRPC_CHARSET; header("Content-Type: $ct; charset=\"$cs\""); #-- make XML document from it if (is_array($r)) { $r = array2xml($r, 1, 'encoding="'.$cs.'" '); } |
︙ | ︙ |
Added contrib/xmlrpc.txt.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | XML-RPC is a "standard" (well, not yet exactly) for accessing remotely provided 'Web services'. More exactly it is just a complicated encoding standard for calling functions and procedures on a remote Web server (and getting its calculation or data request results of course). It is still in wide use for many interesting features like accessing database content, searching, data conversion, and so on. It started as a lightweight alternative to SOAP, which currently is more on the rise. While SOAP is much more bloated, also XML-RPC is not the quickest RPC format available, is not really standards-compliant (bogus specs over the time), and so has probably only a limited lifetime now. Therefore you should try to provide your services and access others` via vanilla HTTP requests (form or url encoding), when possible; use the "http.php" class for this. (There is also a faster PHP-RPC standard on the rise, which provides type-safe data transport over compressed and fast connections, without the encoding overhead and charset issues when using XML-RPC.) xmlrpc.php ¯¯¯¯¯¯¯¯¯¯ The 'xmlrpc.php' script implements the XML-RPC spec., but adds a few extensions, namely use of the (yet unregistered) "application/rpc+xml" MIME type and compressed HTTP transportation. It uses a builtin stupid XML parser (for the highly simplified XML-RPC message content) and thus is totally independent of any PHP extensions. It of course takes advantage of the XML extension where present (a lot faster), and it even can make use of Epinions XML-RPC extension for PHP (really fast than). It is mostly not object-oriented, but extremely easy to use for building XML-RPC servers or calling remote procedures. configuration ¯¯¯¯¯¯¯¯¯¯¯¯¯ There are a few constants and variables that the 'xmlrpc.php' script respects. XMLRPC_PLUS If set to 1 enables use of the "application/rpc+xml" MIME type and request compression per default (for server and client). In 2004 still not the recommended setting. XMLRPC_AUTO_TYPES Allows the request encoder to automatically determine the <base64> and <dateTime.iso8061> types, even if you just used them as scalar PHP values. Otherwise you had to use 'new xmlrpc_base64("STrinG==")' and 'new xmlrpc_datetime("20001020T00:00:00")' to prepare such values. XMLRPC_AUTO_UTF8 Takes care of transforming the complete RPC messages into/from UTF-8, what is useful if your scripts deal only with Latin1 and always expect this. <base64> are also de/encoded if you set this constant to 2. XMLRPC_CHARSET The whole script is currently optimized to produce UTF-8 and decode requests from/into Latin-1 for your scripts. XMLRPC_FAST Enables use of Epinions XML-RPC extension module for PHP automatically where available. You only want to disable this for debugging purposes. XMLRPC_OO Engages error result objects, else you had to use the two global vars "$xmlrpc_error" and "$xmlrpc_errorstr" to detect such cases. If you enable it you must however compare all xmlrpc_request() result values against being an object (what does not happen for succeeded XML-RPC requests). XMLRPC_AUTODISCOVERY If you create a "xmlrpc" or "xmlrpc_connection" object and this is enabled, you would get the object with function names of the automatically instantiated methods of the remotely provided service wrapped into one object (not yet), much like in the Python library for xmlrpc. XMLRPC_LOG Creates a log file for incoming requests to the _server() part of xmlrpc (whenerver you activate it with the _server() call). There are also a few automatically defined values, which you shouldn't care about: XMLRPC_MIME Contains the currently selected default MIME type for transport. XMLRPC_MIME_NEW Contains the newer MIME type value. Do not change. XMLRPC_MIME_OLD For compatibility with older XML-RPC clients and servers. Do not change. XMLRPC_ACCEPT Again the MIME Types wrapped into a HTTP Accept: header for requests and responses. XMLRPC_EPI Tells if the Epinions extension is available. server configuration ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ $xmlrpc_methods[] Every accessible method (for remote calls) must be defined here, for use with the xmlrpc_server(). There is a separate section on this one. making xmlrpc() requests ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ You can call a remote procedure by just using the short xmlrpc() call syntax: $result = xmlrpc("http://example.com/rpc.php", "the.function", 1, 2, 3); Where 1, 2 and 3 would be parameters to "the.function" on the remote server. The number of parameters is not limited, and you do not need to give one at all (if the remote procedure does not require them. The parameter values are automatically encoded into XML-RPC representations except for <base64> and <dateTime.iso8061> ones, for which you needed to create objects first. The $result of course recieved in ordinary PHP representation of the remote functions result value. xmlrpc_request() ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ Is basically the same as calling the xmlrpc() function, but that all parameters given to the remote function are now to be passed as array in the third parameter: $params = array( "param1", "param2", "param3" ); $r = xmlrpc_request("server.com:80", "remoteMethod", $params); Also a fourth parameter to xmlrpc_request (boolean) says if to use the old XML-RPC or the faster XML+RPC interface. But beware, that this could fail if you connect to an older server. xmlrpc_connection ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ You can also establish a 'connection' (this is purely virtual) to a remote XML-RPC server, using a xmlrpc_connection object as follows: $xc = new xmlrpc_connection("http://example.com/rpc.php"); Then you could regularily call remote functions on that server: $result1 = $xc->call("function1"); $result2 = $xc->call("function2", 2, $result1, 0x5F02); The xmlrpc_connection automatically chooses XML+RPC if available with the remote server. data types ¯¯¯¯¯¯¯¯¯¯ Unless XMLRPC_AUTO_TYPES was enabled (discouraged, because this is considered 'unreliable type guessing') you need to explicetely mark parameters passed to the xmlrpc() or xmlrpc_request() calls for their later XML-RPC type. To do so, you have the two class types 'xmlrpc_datetime' and 'xmlrpc_base64' availabe. Use them as follows: $param1 = new xmlrpc_base64( base64_encode($string1) ); $p2 = new xmlrpc_datetime( time() + 60*60*24*7 ); $r = xmlrpc("www.server.com/rpc/", "function1", $param1, $p2); Please note, that you needed to call base64_encode() yourself, and that the _datetime() can also use standard Unix timestamps as input. The XML-RPC <dateTime.iso8601> entites are, btw, automatically converted into Unix timestamps, if returned as result from xmlrpc() and xmlrpc_request() calls. This happens regardless of XMLRPC_AUTO_TYPES. If XMLRPC_AUTO_TYPES is set to 2, then even <base64> result values would be automatically converted into their plain (binary) string representation. "Bugs" ¯¯¯¯¯¯ pass-by-reference is not possible ;) xmlrpc_server() use ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ To make a set of functions available for remote calls, you would create an interface script and make its URL public. Assuming that you had a subdirectory "./myrpc" on your server, you would likely want to create the file "./myrpc/index.php" with following content: <?php $xmlrpc_methods = array( "myFunction", "mySecondOne", ); include("xmlrpc.php"); xmlrpc_server(); ?> So, by calling the xmlrpc_server() you make all registered functions ($xmlrpc_methods) available with the URL "xml+rpc://example.com/myrpc/" for remote calls. $xmlrpc_methods[] ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ All function names you list in this array (before calling the xmlrpc_server() function) will be available for remote calls. The function names are mapped to remote method names by having the _ underscore as alias the the . dot, which is commonly used. So a function whose name was "tools_register" was available as remotely callable method "tools_register" or "tools.register". Also with xmlrpc_server() it is possible to register member methods of object classes as remotely callable methods. All you needed to do is list your class in $xmlrpc_methods[]. You can also give aliases, both for function names and for object classes: $xmlrpc_methods["callable.methodname"] = "here_function_name"; $xmlrpc_methods["section"] = "here_class_name"; The member methods of a class cannot be aliased however. xmlrpc_server() ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ Just fetches the current request, decodes it and executes the destination method (PHP function) if listed in the global $xmlrpc_methods[] variable. It automatically exits after sending the response or an error. So this is the last command in your xmlrpc wrapper script. xmlrpc_fetch_post_chunk() ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ Begs PHP for the complete POST data stream. It only has two options to do so and may fail with some Webservers and earlier PHP versions. In either case try to set the "always_populate_raw_post_data" option in php.ini or from within a .htaccess file. To allow the server part to receive the XML-RPC message, you either need PHP 4.3 or later, or configure your PHP interpreter specifically to pass in the POSTed data stream. In you php.ini ([PHP] section) add: always_populate_raw_post_data = 1 Or following in a .htaccess per-dir configuration file for Apache: php_option always_populate_raw_post_data=1 xmlrpc_send_response() ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ Is called from within xmlrpc_server() to send the response for the processed request (also sends error responses). xmlrpc_error() ¯¯¯¯¯¯¯¯¯¯¯¯¯¯ Creates a XML-RPC error result array. --------------------------------------------------------------------------- internals --------------------------------------------------------------------------- Unless you are interrested in an in-deep discussion of the "xmlrpc.php" you should effectively stop reading here. xmlrpc data representation encoders ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ This lib uses the simple xml2array() compact format to do the initial work of converting a XML file into an array representation. Various design restrictions of the XML-RPC message format then impose certain structures inside of the xml2array-compact representation, what is taken adavantage of. For example <struct> entries have in the compact representation sub-elements like ["member,0"], ["member,1"], ["member,2"] and so on. Each of which then has two sub elements: ["name,0"] and ["value,1"]. The XML-RPC <array> instead had one ["data,0"] with sub-arrays of ["value,0"], ["value,1"], ["value,2"] and so on, which would be recursively feed through: xmlrpc_decode_value() ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ Makes a PHP representation of a part (one must start it with the content of a ["value,0"]) from a xml2array()-compact representation made out of a XML-RPC message. xmlrpc_compact_value() ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ Converts a PHP array or scalar variable into an array suitable for transformation into a XML-RPC message string using the array2xml() function then. generic functions ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ The xml2array() and array2xml() functions are stupid XML parsers and probably only suitable for XML-RPC messages. xml2array() ¯¯¯¯¯¯¯¯¯¯¯ Can decode a SimplifiedXML document into an array structure - and this in two formats. Internall xml+rpc uses only the so called "$compact format". If we had a XML document like the following: <xml> <more> <string> String </string> </more> <more> <string> String2 </string> <int>5</int> </more> </xml> It would return for the $compact=1 format, something like: array( "xml,0" => array( "more,0" => array( "string,0" = array( ",0" => " String " ) ) "more,1" => array( "string,0" = array( ",0" => " String2 " ), "int,1" = array( ",0" => 5 ) ) ) ); Where every tagname had a ","+NUMBER suffix, and text nodes would start with the comma. The numbers are always counted up in each nesting level from 0, regardless if it counted text or tag nodes. The not-compact format would hold another subarray to denote a deeper level tag node, but leave the text nodes as entries into the ordering array level. This was more suitable for XML like files, where you had mixed text and tag nodes in a level. For example: <html> string1 <b>string2</b> </html> Would become in the not-compact format: array( 0 => array( "html" => array( 0 => "\n string1\n " 1 => array( "b" => array( 0 => "string2", ) ) ) ) array2xml() ¯¯¯¯¯¯¯¯¯¯¯ Regenerates a XML stream from an array structure like the one emitted by xml2array(). other functions ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ If you want a different behaviour, you might want to alter one of the following functions. xmlrpc_method_call() ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ Is responsible in the _server() part for invoking the requested function. It does so by using the $xmlrpc_methods[] array as mapping to the PHP functions to activate. If you would like to have a better mapping support, or even to add parameter type and number checking, then this is where you would want to start editing the code. |
Added dtools/compact.
> > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 | #!/bin/sh # # creates comment+whitespace free version of upgrade.php script # cd `dirname $0` cd .. php -q -w upgrade.php | perl -pe 's/\s*([{}()\[\]=\-\/\$<>+*",;!&|])\s*|\n/$1/gmis;' > contrib/upgrade.php.shortened ls -l upgrade.php contrib/upgrade.php* |
Changes to ext/base64.php.
︙ | ︙ | |||
13 14 15 16 17 18 19 | function base64_decode_safe($b64) { return base64_decode(strtr($str, "-_", "+/")); } #-- base16 function base16_encode($str) { | > | > | | 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 | function base64_decode_safe($b64) { return base64_decode(strtr($str, "-_", "+/")); } #-- base16 function base16_encode($str) { $str = unpack("H".(2*strlen($str)), $str); $str = chunk_split($str[1]); return($str); } function base16_decode($b16) { $b16 = preg_replace("/\s+/", '', $b16); $b16 = pack("H*", $b16); return($b16); } #-- base32 function base32_encode() { # strtoupper() # "A-Z,0-7,=" } } ?> |
Added ext/bcmath.
Added ext/bcmath.php.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | <?php /* Emulates mathematical functions with arbitrary precision using GMP or PHPs bigint extension module and the Linux native 'bc' as last fallback. */ #-- GMP versions if (!function_exists("bcadd") && function_exists("")) { function bcadd($a, $b) { return gmp_strval(gmp_add($a, $b)); } function bcsub($a, $b) { return gmp_strval(gmp_sub($a, $b)); } function bccomp($a, $b, $precision="IGNORED") { return gmp_strval(gmp_sub($a, $b)); } function bcdiv($a, $b, $precision=NULL) { $qr = gmp_div_qr($a, $b); $q = gmp_strval($qr[0]); $r = gmp_strval($qr[1]); if ((!$r) || ($precision===0)) { return($q); } else { if (isset($precision)) { $r = substr($r, 0, $precision); } return("$q.$r"); } } function bcmod($a, $b) { return gmp_strval(gmp_mod($a, $b)); } function bcmul($a, $b) { return gmp_strval(gmp_mul($a, $b)); } function bcpow($a, $b) { return gmp_strval(gmp_pow($a, $b)); } function bcpowmod($x, $y, $mod, $scale="IGNORED") { return gmp_strval(gmp_powm($x, $y, $mod)); } function bcscale($scale="IGNORED") { trigger_error("bcscale(): ignored", E_USER_ERROR); } function bcsqrt($x, $precision="IGNORED") { return gmp_strval(gmp_powm($x)); } }//gmp #-- bigint if (0) { // ... } #-- shell bc if (!function_exists("bcadd") && isset($_ENV["SHELL"])) { $GLOBALS["bc___scale"] = 10; #-- invokes commandline 'bc' utility (maybe 'dc' was better) # (later version should use proc_open() for faster bi-directional I/O) function bc___exec($calc, $scale=NULL) { global $bc___scale; #-- assemble shell call $calc = escapeshellarg($calc); // redundant, unless input from untrusted sources and non-integers would get passed if (isset($scale) || ($scale = $bc___scale) || isset($scale)) { $calc = "scale = \"" . ((int)$scale) . "\n\"" . $calc; } $cmd = "echo $calc | /usr/bin/bc"; //@BUG: hard-wired pathname #-- do $r = `$cmd`; $r = str_replace("\\"."\n", "", $r); $r = trim($r); return($r); } #-- sets global state variable function bcscale($scale=NULL) { $GLOBALS["bc___scale"] = $scale; } #-- wrapper calls function bcadd($a, $b, $scale=NULL) { return bc___exec("$a + $b", $scale); } function bcsub($a, $b, $scale=NULL) { return bc___exec("$a - $b", $scale); } function bcmul($a, $b, $scale=NULL) { return bc___exec("$a * $b", $scale); } function bcdiv($a, $b, $scale=NULL) { return bc___exec("$a / $b", $scale); } function bcmod($a, $b, $scale=NULL) { return bc___exec("$a % $b", $scale); } function bcpow($a, $b, $scale=NULL) { return bc___exec("$a ^ $b", $scale); } function bcpowmod($x, $y, $mod, $scale=NULL) { return bc___exec("($x ^ $y) % $mod", $scale); } function bcsqrt($x, $scale=NULL) { return bc___exec("sqrt($x)", $scale); } function bccomp($a, $b, $scale=NULL) { //@BUG: doesn't support downscaling return (int) bc___exec("a=$a+0 \n b=$b+0 \n if (a > b) { print 1 } else if (a == b) { print 0 } else { print -1 }"); } }//shell ?> |
Changes to ext/ctype.php.
︙ | ︙ | |||
42 43 44 45 46 47 48 49 50 51 52 53 54 55 | function ctype_print($text) { return ctype_punct($text) && ctype_graph($text); } } #-- simple char-by-char comparisions if (!function_exists("ctype_alnum")) { #-- true if string is made of letters and digits only function ctype_alnum($text) { | > | 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | function ctype_print($text) { return ctype_punct($text) && ctype_graph($text); } } /***<old> #-- simple char-by-char comparisions if (!function_exists("ctype_alnum")) { #-- true if string is made of letters and digits only function ctype_alnum($text) { |
︙ | ︙ | |||
199 200 201 202 203 204 205 206 | // // function ctype_print($text) { // } } ?> | > > > | 200 201 202 203 204 205 206 207 208 209 210 | // // function ctype_print($text) { // } } </old>***/ ?> |
Added ext/exceptions.php.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | <?php /* simplistic exception handling for PHP4 -------------------------------------- As you might know, PHP5 introduced exceptions, like those from Java. This feature of course cannot be used for PHP4-compatible scripts, and it can in no way be emulated by a functional API emulation like "upgrade.php". To use an exception-like scheme in PHP4 we have to agree on conventions - lots of. And exceptions won't look object-oriented anymore and not be compliant with the PHP5 scheme - the names are in fact held incompatible to avoid conflicts in the language semantics (reserved words). interfaces ---------- - class Exception - global variable $_EXCEPTION (- should better be a list of excptn objs?) - _try() function - _throw() function - _catch() function howto ----- - prefix a block of commands with _try(); this will initialize exception handling (evtl. resets internal vars) - errors are thrown, by calling _throw() with an Exception-class derived object instance as parameter, and returning immediately - exceptions are "catched" in if() statements, the _catch() function with a classname as parameter returns false or the $_EXCEPTION object - you shouldn't use set_exception_handler(), but $_EXCEPTION="funcname"; #-- main code _try(); { sub_call(); } if ($e = _catch("Special_Case")) { echo $e->broken_file(); } if ($e = _catch("Exception")) { echo "Something broke, I'd say."; } #-- error-prone function sub_call() { // ... _throw(new Exception("error",255)) && return(); } note ---- Please don't send hatemails only because you feel the syntax is too far away from PHP5s native exception handling and counter to that in other languages. And the underscores in this agreement are just to prevent conflicts with PHP5 constructs - this is not yet another case of PHP-underscoritis ;) -> there has been another PHP framework which implemented exceptions long before PHP5 came out; I just don't know anymore which it was //@TODO: build a search engine similar to Google to find that out */ #-- base class for exceptions if (!class_exists("exception")) { class Exception { #-- attributes var $message = ""; var $code = 0; var $file = NULL; var $line = NULL; var $backtrace = NULL; #-- constructor function Exception($message="", $code=0) { #-- values $this->message = $message; $this->code = $code; #-- debugging $this->backtrace = debug_backtrace(); array_shift($this->backtrace); $this->file = @$this->backtrace[0]["file"]; $this->line = @$this->backtrace[0]["line"]; } #-- get_ wrappers function getMessage() { return($this->message); } function getCode() { return($this->code); } function getFile() { return($this->file); } function getLine() { return($this->line); } function getTrace() { return($this->backtrace); } function getTraceAsString() { return(var_export($this->backtrace, TRUE)); } #-- output function __toString() { return($this->message); } } } #-- initialize exception handling for next block function _try() { global $_EXCEPTION; #-- clean up if (!is_string($_EXCEPTION) || !function_exists($_EXCEPTION)) { $_EXCEPTION = new Object(); } } #-- use for throwing errors function _throw($obj) { global $_EXCEPTION; #-- quick if (is_string($_EXCEPTION) && function_exists($_EXCEPTION)) { $_EXCEPTION($obj); } #-- what do we do if there's already an exception? if ($_EXCEPTION) { // ??? trigger_error("_throw: there is already an unhandled exception on the stack", E_USER_ERROR); } #-- generate object from error message if (!is_object($obj)) { $_EXCEPTION = new Exception(); $_EXCEPTION->message = (string)$obj; } #-- pass $_EXCEPTION = $obj; return(true); // break 5; (after throwing an exception, you should // exit from your current function quickly) } #-- check if exception thrown function &_catch($classname="Exception") { global $_EXCEPTION; static $e; #-- checked for a specific error type / exception class if (is_object($_EXCEPTION) && (($classname == "*") || is_a($_EXCEPTION, $classname))) { $e = &$_EXCEPTION; //@FIX: remove reference passing, seems unnecessary unset($_EXCEPTION); // this doesn't clean the global var [but _try() does] } else { $e = false; } #-- give out extracted exception return $e; } #-- functional additions if (!function_exists("debug_backtrace")) { function debug_backtrace() { return array(); } } #-- sets global state if (!function_exists("set_exception_handler")) { function set_exception_handler($func) { global $_EXCEPTION; // quick hack, should use a different func name $_EXCEPTION = $func; } } ?> |
Added ext/exotic.php.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | <?php /* Following funtions have been removed from the core emulation script, because they are considered too special to be commonly used in WWW scripts. Anybody using them, probably takes extra precautions prior calling them (you could still load this script). Some of these functions could also be too difficult to be reimplemented 100% exactly. */ #-- calls PHP interpreter itself (really only works with 4.3 onwards) # (you should use the PHP_Compat implementation of this preferably) if (!function_exists("php_strip_whitespace")) { function php_strip_whitespace($fn) { // alternatives would be using te tokenizer or // some regexs to strip unwanted content parts // (PEAR::PHP_Compat simply calls the tokenizer) $fn = escapeshellcmd($fn); $text = `php -wqCf '$fn'`; if (!$text) { $text = implode("", file($fn)); } return $text; } } #-- invocates PHP interpreter to do the syntax check (nothing else can do) # (you should use the PHP_Compat implementation of this preferably) if (!function_exists("php_check_syntax")) { function php_check_syntax($fn) { $args = func_get_args(); if (count($args)>1) { $result = & $args[1]; } $fn = escapeshellcmd($fn); $result = system("php -lqCf '$fn'", $err); return($err==0); } } #-- print enumerated lsit of last-called functions if (!function_exists("debug_print_backtrace") && function_exists("debug_backtrace")) { function debug_print_backtrace() { $d = debug_backtrace(); foreach ($d as $i=>$info) { #-- index echo "#" . ($i) . " "; #-- function name if (isset($info["class"])) { echo "$info[class]::"; } if (isset($info["object"])) { echo "\$$info[object]->"; } echo "$info[function]"; #-- args echo "("; foreach ($info["args"] as $a) { echo str_replace("\n", "", var_export($a, 1)) . ", "; } echo ")"; #-- caller echo " called at ["; if ($info["file"]) { echo $info["file"] . ":" . $info["line"]; } else { echo "unknown_location"; } echo "]\n"; } } } ?> |
Added ext/gettext+plural0.php.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | <?php /* Simulates gettext functionality. Understands .mo and .po files. Lookup of plural forms mostly work (but not fully compliant, no interpreter for Plural-Forms: header). Categories/codesets are ignored. Besides using setlocale() you should change the $_ENV["LANG"] var to the desired language manually. Additionally all your scripts could contain following (may also work with standard gettext): $_ENV["LANGUAGE"] = $_SERVER["HTTP_ACCEPT_LANGUAGE"]; What's often more user-friendly than hardwired server-side values. */ #-- emulate only if not present in current PHP interpreter if (!function_exists("gettext")) { #-- all-in-one combined implementation # (in original API only the first parameter is present) function gettext($msg, $msg2=NULL, $domain=NULL, $category=NULL, $plural=NULL) { global $_GETTEXT; #-- get default params if corresponding args are empty if (!isset($domain)) { $domain = $_GETTEXT["%domain"]; } elseif (empty($_GETTEXT[$domain])) { bindtextdomain($domain); // load from system dirs } #-- guess plural array position if (!isset($plural)) { $pli = 0; } elseif (function_exists("gettext___plural_guess")) { $pli = gettext___plural_guess($_GETTEXT[$domain]["%plural-c"], $plural); } else { $pli = $plural != 1 ? 1 : 0; // English } #-- look up string if ($trans = $_GETTEXT[$domain][$msg]) { // handle plural entries if (is_array($trans)) { if (!isset($trans[$pli])) { $pli = 0; // missing translation } $trans = $trans[$pli]; } // only return, if something found if (strlen($trans)) { $msg = $trans; } } #-- handle $category (???) // recode() ... #-- give out whatever we have return($msg); } #-- try to match C string into one of the known possible forms # (makes us faster than parsetree execution in original C libintl) function gettext___plural_guess(&$c_expr, $n) { #-- guess from string with C expression and set integer shorthand if (!is_int($c_expr)) { if (($c_expr == "nplurals=1;plural=0;") || !strlen($c_expr)) { $c_expr = 0; // no plurals } elseif ($c_expr == "nplurals=2;plural=n!=1;") { $c_expr = 1; // English } elseif ($c_expr == "nplurals=2;plural=n>1;") { $c_expr = 2; // French } // special cases elseif (strpos($c_expr, "n%100!=11")) { if (strpos($c_expr, "n!=0")) { $c_expr == 21; // Latvian } if (strpos($c_expr, "n%10<=4")) { $c_expr = 22; // a few Slavic langs (code similar to Polish below) } if (strpos($c_expr, "n%10>=2")) { // Lithuanian $c_expr = 23; } $c_expr = 0; } // specials, group 2 elseif (strpos($c_expr, "n<=4")) { // Slovak $c_expr = 25; } elseif (strpos($c_expr, "n==2")) { // Irish $c_expr = 31; } elseif (strpos($c_expr, "n%10>=2")) { // Polish $c_expr = 26; } elseif (strpos($c_expr, "n%100==3")) { // Slovenian $c_expr = 28; } // fallbacks elseif (strpos($c_expr, ";plural=n;")) { $c_expr = 7; // unused } // first at this point a tokenizer/parser/interpreter would have made sense else { $c_expr = 0; // no plurals } } #-- return plural index value from pre-set formulas switch ($c_expr) { case 0: // no plural forms return(0); case 1: // English, and lots of others... return($n != 1 ? 1 : 0); case 2: // French, Brazilian Protuguese return($n > 1 ? 1 : 0); case 7: // unused return($n); case 21: // Latvian return (($n%10==1) && ($n%100!=11)) ? (0) : ($n!=0 ? 1 : 2) ; case 22: // Slavic langs return ($n%10==1) && ($n%100!=11) ? 0 : ( ($n%10>=2) && ($n%10<=4) && ($n%100<10 || $n%100>=20) ? 1 : 2 ) ; case 23: // Lithuanian return ($n%10==1) && ($n%100!=11) ? 0 : ( ($n%10>=2) && ($n%100<10 || $n%100>=20) ? 1 : 2 ) ; case 25: // Slovak return $n==1 ? 0 : ($n>=2 && $n<=4 ? 1 : 2) ; case 26: // Polish return $n==1 ? 0 : ( $n%10>=2 && $n%10<=4 && ($n%100<10 || $n%100>=20) ? 1 : 2 ) ; case 28: // Slovenian return $n%100==1 ? 0 : ($n%100==2 || $n%100==3 || $n%100==4 ? 2 : 3) ; case 31: // Irish return ($n == 1) ? (0) : (($n == 2) ? 1 : 2) ; default: } // unsupported, always return non-plural index [0] return(0); } #-- wrappers around monster function above function ngettext($msg1, $msg2, $plural) { return gettext($msg1, $msg2, NULL, NULL, $plural); } function dngettext($domain, $msg1, $msg2, $plural) { return gettext($msg1, $msg2, $domain, NULL, $plural); } function dcngettext($domain, $msg1, $msg2, $plural, $category) { return gettext($msg1, $msg2, $domain, $category, $plural); } function dcgettext($domain, $msg, $category) { return gettext($msg, NULL, $domain, $category); } function dgettext($domain, $msg) { return gettext($msg, NULL, $domain); } #-- sets current translation data source # (must have been loaded beforehand) function textdomain($default="NULL") { global $_GETTEXT; $prev = $_GETTEXT["%domain"]; if (isset($default)) { $_GETTEXT["%domain"] = $default; } return $prev; } #-- loads data files function bindtextdomain($domain, $directory="/usr/share/locale:/usr/local/share/locale:./locale") { global $_GETTEXT; if (isset($_GETTEXT["domain"]) && (count($_GETTEXT["domain"]) > 3)) { return; // don't load twice } $_GETTEXT[$domain]["%dir"] = $directory; $_GETTEXT["%locale"] = setlocale(LC_CTYPE, 0); #-- language directories $langs = "$_ENV[LANGUAGE],$_ENV[LC_ALL],$_ENV[LC_MESSAGE],$_ENV[LANG]," . "{$_GETTEXT['%locale']},$_SERVER[HTTP_ACCEPT_LANGUAGE],C,en"; #-- add shortened language codes (en_UK.UTF-8 -> + en_UK, en) foreach (explode(",",$langs) as $d) { $d = trim($d); // $dir2[] = $d; $d = strtok($d, "@.-+=%:; "); if (strlen($d)) { $dir2[] = $d; } if (strpos($d, "_")) { $dir2[] = strtok($d, "_"); } } #-- search for matching directory foreach (explode(":", $directory) as $directory) { foreach ($dir2 as $lang) { $base_fn = "$directory/$lang/LC_MESSAGES/$domain"; #-- binary format if (file_exists($f = "$base_fn.mo") && ($f = fopen($f, "rb"))) { gettext___load_mo($f, $domain); break 2; } #-- text file elseif (file_exists($f = "$base_fn.po") && ($f = fopen($f, "r"))) { gettext___load_po($f, $domain); break 2; } } }//foreach #-- extract headers $h = $_GETTEXT[$domain][""]; foreach (explode("\n", $h) as $line) { $header = strtok(":", $line); $line = trim(strtok("\n", $line)); $_GETTEXT[$domain]["%po-header"][strtolower($header)] = $line; } #-- copy plural-forms header $h = $_GETTEXT[$domain]["%po-header"]["plural-forms"]; // $h = substr($h, strpos($h, ";") + 1); // strip "nplurals = x;" // $h = substr($h, strpos($h, "=") + 1); // strip "plural=" $h = str_replace(" ", "", strtr($h, "()[]*{}^&\n\\", " ")); $_GETTEXT[$domain]["%plural-c"] = $h; #-- set as default textdomain if (empty($_GETTEXT["%domain"])) { textdomain($domain); } return($domain); } #-- load string data from binary .mo files (ign checksums) function gettext___load_mo($f, $domain) { global $_GETTEXT; #-- read in data file completely $data = fread($f, 1<<20); fclose($f); #-- extract header fields and check file magic if ($data) { $header = substr($data, 0, 20); $header = unpack("L1magic/L1version/L1count/L1o_msg/L1o_trn", $header); extract($header); if ((dechex($magic) == "950412de") && ($version == 0)) { #-- fetch all entries for ($n=0; $n<$count; $n++) { #-- msgid $r = unpack("L1len/L1offs", substr($data, $o_msg + $n * 8, 8)); $msgid = substr($data, $r["offs"], $r["len"]); unset($msgid_plural); if (strpos($msgid, "\000")) { list($msgid, $msgid_plural) = explode("\000", $msgid); } #-- translation(s) $r = unpack("L1len/L1offs", substr($data, $o_trn + $n * 8, 8)); $msgstr = substr($data, $r["offs"], $r["len"]); if (strpos($msgstr, "\000")) { $msgstr = explode("\000", $msgstr); } #-- add $_GETTEXT[$domain][$msgid] = $msgstr; if (isset($msgid_plural)) { $_GETTEXT[$domain][$msgid_plural] = &$_GETTEXT[$domain][$msgid]; } } } } } #-- read from textual .po source file (not fully correct, and redundant # because the original gettext/libintl doesn't support this at all) function gettext___load_po($f, $domain) { global $_GETTEXT; #-- read line-wise from text file do { $line = trim(fgets($f)); #-- append to global $_GETTEXT hash as soon as we have a complete dataset if (isset($msgid) && isset($msgstr) && (empty($line) || ($line[0]=="m")) ) // || feof($f) { foreach ($msgstr as $v) { $_GETTEXT[$domain][$msgid[0]] = $v; } if ($msgid[1]) { $_GETTEXT[$domain][$msgid[1]] = &$_GETTEXT[$domain][$msgid[0]]; } unset($msgid); unset($msgstr); } #-- check what's in the current line $space = strpos($line, " "); // comment if ($line[0] == "#") { continue; } // msgid elseif (strncmp($line, "msgid", 5)==0) { $msgid[] = trim(substr($line, $space+1), '"'); } // translation elseif (strncmp($line, "msgstr", 6)==0) { $msgstr[] = trim(substr($line, $space+1), '"'); } // continued (could be _id or _str) elseif ($line[0] == '"') { $line = trim($line, '"'); if (isset($msggstr)) { $msgstr[count($msgstr)] .= $line; } else { $msgid[count($msgid)] .= $line; } } } while (!feof($f)); fclose($f); #-- add last msg pair (unclean, doesn't take plural-transls into account) if ($msgid && $msgstr) { $_GETTEXT[$domain][$msgid[0]] = $msgstr[0]; } } #-- ignored setting (no idea what it really should do) function bind_textdomain_codeset($domain, $codeset) { global $_GETTEXT; $_GETTEXT[$domain]["%codeset"] = $codeset; return($domain); } } #-- define gettexts preferred function name _ separately # (some PHP scripts define their own _(), so we're safer included initially) if (!function_exists("_")) { function _($str) { return gettext($str); } } ?> |
Added ext/gettext.meta.
> > > > > > | 1 2 3 4 5 6 | api: PHP type: functions title: gettext() description: emulates gettext functionality priority: auto category: library |
Changes to ext/gettext.php.
︙ | ︙ | |||
8 9 10 11 12 13 14 | to the desired language manually. Additionally all your scripts could contain following (may also work with standard gettext): $_ENV["LANGUAGE"] = $_SERVER["HTTP_ACCEPT_LANGUAGE"]; What's often more user-friendly than hardwired server-side values. */ | | > | | | | < < < | | > | > | > > > > > | > | > > > > | | | | | | < < < < < < < < < < < < < < < < < < < < < | < < < < < < | | | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 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 | to the desired language manually. Additionally all your scripts could contain following (may also work with standard gettext): $_ENV["LANGUAGE"] = $_SERVER["HTTP_ACCEPT_LANGUAGE"]; What's often more user-friendly than hardwired server-side values. */ #-- emulate only if not present in current PHP interpreter if (!function_exists("gettext")) { #-- all-in-one combined implementation # (in original API only the first parameter is present) function gettext($msg, $msg2=NULL, $domain=NULL, $category=NULL, $plural=NULL) { global $_GETTEXT; #-- get default params if corresponding args are empty if (!isset($domain)) { $domain = $_GETTEXT["%domain"]; } elseif (empty($_GETTEXT[$domain])) { bindtextdomain($domain); // load from system dirs } #-- plural array position (English only) if (!isset($plural) || ($plural == 1)) { $pli = 0; } else { if (isset($msg2)) { $msg = $msg2; } $pli = 1; } // $pli = ($plural==1) ?0 :1; // we could hook in tokenizer/interpreter from phpjs here #-- look up string if ($trans = $_GETTEXT[$domain][$msg]) { // handle plural entries if (is_array($trans)) { if (!isset($trans[$pli])) { $pli = 0; // missing translation } $trans = $trans[$pli]; } // only return, if something found if (strlen($trans)) { $msg = $trans; } } #-- handle $category (???) // recode() ... #-- give out whatever we have return($msg); } #-- wrappers around monster function above function ngettext($msg1, $msg2, $plural) { return gettext($msg1, $msg2, NULL, NULL, $plural); } function dngettext($domain, $msg1, $msg2, $plural) { return gettext($msg1, $msg2, $domain, NULL, $plural); } function dcngettext($domain, $msg1, $msg2, $plural, $category) { return gettext($msg1, $msg2, $domain, $category, $plural); } function dcgettext($domain, $msg, $category) { return gettext($msg, NULL, $domain, $category); } function dgettext($domain, $msg) { return gettext($msg, NULL, $domain); } #-- sets current translation data source # (must have been loaded beforehand) function textdomain($default="NULL") { global $_GETTEXT; $prev = $_GETTEXT["%domain"]; if (isset($default)) { $_GETTEXT["%domain"] = $default; } return $prev; } #-- loads data files function bindtextdomain($domain, $directory="/usr/share/locale:/usr/local/share/locale:./locale") { global $_GETTEXT; if (isset($_GETTEXT["domain"]) && (count($_GETTEXT["domain"]) > 3)) { return; // don't load twice } $_GETTEXT[$domain]["%dir"] = $directory; $_GETTEXT["%locale"] = setlocale(LC_CTYPE, 0); #-- language directories $langs = "$_ENV[LANGUAGE],$_ENV[LC_ALL],$_ENV[LC_MESSAGE],$_ENV[LANG]," . "{$_GETTEXT['%locale']},$_SERVER[HTTP_ACCEPT_LANGUAGE],C,en"; #-- add shortened language codes (en_UK.UTF-8 -> + en_UK, en) foreach (explode(",",$langs) as $d) { $d = trim($d); // $dir2[] = $d; $d = strtok($d, "@.-+=%:; "); if (strlen($d)) { $dir2[] = $d; } if (strpos($d, "_")) { $dir2[] = strtok($d, "_"); } } #-- search for matching directory foreach (explode(":", $directory) as $directory) { foreach ($dir2 as $lang) { $base_fn = "$directory/$lang/LC_MESSAGES/$domain"; #-- binary format if (file_exists($f = "$base_fn.mo") && ($f = fopen($f, "rb"))) { gettext___load_mo($f, $domain); break 2; } #-- text file elseif (file_exists($f = "$base_fn.po") && ($f = fopen($f, "r"))) { gettext___load_po($f, $domain); break 2; } } }//foreach #-- set as default textdomain if (empty($_GETTEXT["%domain"])) { textdomain($domain); } return($domain); } #-- load string data from binary .mo files (ign checksums) function gettext___load_mo($f, $domain) { global $_GETTEXT; #-- read in data file completely $data = fread($f, 1<<20); fclose($f); #-- extract header fields and check file magic if ($data) { $header = substr($data, 0, 20); $header = unpack("L1magic/L1version/L1count/L1o_msg/L1o_trn", $header); extract($header); if ((dechex($magic) == "950412de") && ($version == 0)) { #-- fetch all entries for ($n=0; $n<$count; $n++) { #-- msgid $r = unpack("L1len/L1offs", substr($data, $o_msg + $n * 8, 8)); $msgid = substr($data, $r["offs"], $r["len"]); unset($msgid_plural); if (strpos($msgid, "\000")) { list($msgid, $msgid_plural) = explode("\000", $msgid); } #-- translation(s) $r = unpack("L1len/L1offs", substr($data, $o_trn + $n * 8, 8)); $msgstr = substr($data, $r["offs"], $r["len"]); if (strpos($msgstr, "\000")) { $msgstr = explode("\000", $msgstr); } #-- add $_GETTEXT[$domain][$msgid] = $msgstr; if (isset($msgid_plural)) { $_GETTEXT[$domain][$msgid_plural] = &$_GETTEXT[$domain][$msgid]; } } } } } #-- read from textual .po source file (not fully correct, and redundant # because the original gettext/libintl doesn't support this at all) function gettext___load_po($f, $domain) { global $_GETTEXT; #-- read line-wise from text file do { $line = trim(fgets($f)); #-- append to global $_GETTEXT hash as soon as we have a complete dataset if (isset($msgid) && isset($msgstr) && (empty($line) || ($line[0]=="m")) ) // || feof($f) { foreach ($msgstr as $v) { $_GETTEXT[$domain][$msgid[0]] = $v; } if ($msgid[1]) { $_GETTEXT[$domain][$msgid[1]] = &$_GETTEXT[$domain][$msgid[0]]; } unset($msgid); unset($msgstr); } #-- check what's in the current line $space = strpos($line, " "); // comment if ($line[0] == "#") { continue; } // msgid elseif (strncmp($line, "msgid", 5)==0) { $msgid[] = trim(substr($line, $space+1), '"'); } // translation elseif (strncmp($line, "msgstr", 6)==0) { $msgstr[] = trim(substr($line, $space+1), '"'); } // continued (could be _id or _str) elseif ($line[0] == '"') { $line = trim($line, '"'); if (isset($msggstr)) { $msgstr[count($msgstr)] .= $line; } else { $msgid[count($msgid)] .= $line; } } } while (!feof($f)); fclose($f); #-- add last msg pair (unclean, doesn't take plural-transls into account) if ($msgid && $msgstr) { $_GETTEXT[$domain][$msgid[0]] = $msgstr[0]; } } #-- ignored setting (no idea what it really should do) function bind_textdomain_codeset($domain, $codeset) { global $_GETTEXT; $_GETTEXT[$domain]["%codeset"] = $codeset; return($domain); } } #-- define gettexts preferred function name _ separately if (!function_exists("_")) { function _($str) { return gettext($str); } } ?> |
Added ext/gettext.txt.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | PHP-only gettext emulation -------------------------- The "gettext.php" include script tries to reimplement GNU gettext in pure PHP. It is incomplete and divergent in many ways, but seems to work well in its goal to be a quick drop-in replacement. You load the script, like you'd include the "upgrade.php" script, and then have the family of gettext functions always available - if they are compiled in into your PHP binary or not. This way you can freely use standardized i18n features safely on any web server and with all your applications. There are however a few minor obstacles and differences in between the original and the emulation which you have to take care of. Most of the incompatibilites descend from lousily documented behaviour of the original and from lack of extensqive testing of the emulated versions. - You should use setlocale() before any bindtextdomain(), because this emulation does load the .mo/.po data files only once. - The emulation only ever loads one translation file (it never retrieves translation strings from different localizations, so it is less useful in conjunction with Accept-Language header settings - where multiple languages could be given). [Original gettext may or may not load from multiple files??] - To be compliant with the native implementation, you have to make sure, that the .mo files are built from the *.po source files. (The emulation tries to work on both, but it really shouldn't do that.) - Order of environment variable precedence is: 1. LANGUAGE 2. LC_ALL 3. LC_MESSAGE 4. LANG (multiple langs) 5. setlocale() 6. HTTP_ACCEPT_LANGUAGE (incompliant with GNU gettext) - There is a second variant of the script, which tries to handle plural forms. This has multiple limitations: - does not employ a full Plural-Forms parser (a C expression which must be interpreted at runtime) - matches and works only with a few built-in language plural form syntaxes and orderings - and it's fully untested as of yet - It constructs a global $_GETTEXT[] variable which contains all messages and translations at runtime in-memory. That means, it is far more memory-hungry and less scalable than the original GNU libintl in C. |
Added ext/odbc.php.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | <?php die("'odbc.php' is incomplete. Don't use this yet.\n"); /* This is just another SQL interface wrapper. It reimplements the ODBC functions in PHP by itself chaining to PEAR::DB (a double wrapper, to simplify this initial version). - does not use integers as connection_id Because any mysql_*() calls are easier replaced with odbc_() funcs, but at the same time offer the same degree of database independence, this can often make more sense than transitioning to PEAR::DB or the ADOdb classes. - PEAR::DB provides the saner OO-interface - ADOdb is slightly faster, but has a less nicely abstracted API */ #-- declare odbc interface functions if (!function_exists("odbc_connect")) { #-- load PEAR::DB require_once("DB.php"); #-- initialize connection function odbc_connect($dsn, $user, $password, $cursor_type=NULL) { #-- mangle $dsn for PEAR $dsn = str_replace("://", "://$user:$password@", $dsn); // ... rename dbtype identifiers #-- connect $c = DB::connect($dsn); if (!PEAR::isError($c)) { return($c); } } #-- incomplete function odbc_pconnect($dsn, $user, $password, $cursor_type=NULL) { return odbc_connect($dsn, $user, $password, $cursor_type); } #-- end connection function odbc_close($db) { $db->disconnect(); } #-- SQL command execution function odbc_exec($db, $query) { return $db->query($db); } function odbc_do($db, $query) { return odbc_exec($db, $query); } #-- sql pre-parsing function odbc_prepare($db, $query) { return( array($db, $db->prepare($db)) ); } #-- and execution of prepared query function odbc_execute($pq, $args=NULL) { return $pq[0]->execute($pq[1], $args); } #-- return result row function odbc_fetch_array($res) { return $res->fetchRow(DB_FETCHMODE_ASSOC); } function odbc_fetch_row($res) { return $res->fetchRow(DB_FETCHMODE_ORDERED); } function odbc_fetch_object($res) { return $res->fetchRow(DB_FETCHMODE_OBJECT); } function odbc_fetch_into($res, $count, &$array) { $array = array(); while ($count--) { $array[] = $res->fetchRow(DB_FETCHMODE_ORDERED); } } #-- more functions on result sets function odbc_free_result(&$res) { $res->free(); $res = NULL; } function odbc_next_result($res) { return $res->nextResult(); } function odbc_num_fields($res) { return $res->numCols(); } function odbc_num_rows($res) { return $res->numRows(); } #-- and there's more //... } ?> |
Changes to ext/openssl.php.
1 2 | <?php /* | | | 1 2 3 4 5 | <?php /* Ok, that's a joke. (Not that this wasn't possible, though ...) */ ?> |
Changes to ext/phprequest.php.
1 2 3 4 5 6 7 8 | <?php /* Allows http "POST" and "PUSH" requests with a Content-Type of "application/vnd.php.serialized". This isn't used in the wild. */ if (empty($_POST) and (strtoupper($_SERVER["REQUEST_METHOD"][0]) == "P") | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <?php /* Allows http "POST" and "PUSH" requests with a Content-Type of "application/vnd.php.serialized". This isn't used in the wild. */ if (empty($_POST) and (strtoupper($_SERVER["REQUEST_METHOD"][0]) == "P") and (strtolower(trim(strtok($_SERVER["CONTENT_TYPE"], ";,("))) == "application/vnd.php.serialized")) { #-- search for bare request body if (isset($GLOBALS["HTTP_RAW_POST_DATA"])) { $_POST = $GLOBALS["HTTP_RAW_POST_DATA"]; } else { $f = fopen("php://input", "rb"); |
︙ | ︙ | |||
27 28 29 30 31 32 33 | if ($enc == "deflate") { $_POST = gzinflate($_POST); } elseif ($enc == "compress") { $_POST = gzuncompress($_POST); } elseif ($enc == "gzip") { | | | 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | if ($enc == "deflate") { $_POST = gzinflate($_POST); } elseif ($enc == "compress") { $_POST = gzuncompress($_POST); } elseif ($enc == "gzip") { $_POST = function_exists("gzdecode") ? gzdecode($_POST) : gzinflate(substr($_POST, 10, strlen($_POST) - 18)); } elseif (($enc == "x-bzip2") or ($enc == "bzip2")) { $_POST = function_exists("bzdecompress") ? bzdecompress($_POST) : NULL; } #-- decipher if ($_POST) { |
︙ | ︙ |
Deleted ext/spl.php.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Added tests/bcmath.
> > > > > > > > | 1 2 3 4 5 6 7 8 | <?php include("../ext/bcmath.php"); bcscale(100); echo bcdiv("1", "17"); ?> |
Added tests/gettext.
> > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <?php include("../ext/gettext+plural0.php"); #-- load echo "bindtextdomain(\"tar\");\n"; bindtextdomain("tar"); textdomain("tar"); #-- query echo "_(\"stdin\") == \""; echo _("stdin"); echo "\"\n"; ?> |
Added tests/mhash.
> > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | <?php include("../upgrade.php"); echo "HMAC-MD5 test cases (RFC2104/page 9):\n\n"; # 1 $k = str_pad("", 16, chr(0x0b)); $text = "Hi There"; $end = unpack("H32", mhash(MHASH_MD5, $text, $k)); echo "key = 0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b\n"; echo "data = \"$text\"\n"; echo "digest = 0x$end[1]\n"; echo "should = 0x9294727a3638bb1c13f48ef8158bfc9d\n\n"; # 2 $k = "Jefe"; $text = "what do ya want for nothing?"; $end = unpack("H32", mhash(MHASH_MD5, $text, $k)); echo "key = \"$k\"\n"; echo "data = \"$text\"\n"; echo "digest = 0x$end[1]\n"; echo "should = 0x750c783e6ab0b503eaa86e310a5db738\n\n"; ?> |
Added upgrade.meta.
> > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 | api: PHP type: emulation priority: auto category: library sort: -200 provides: upgrade-php title: PHP-Upgrade description: backwards-compatility layer for older PHP versions license: Public Domain url: http://freshmeat.net/p/upgradephp version: 12 |
Changes to upgrade.php.
1 2 3 4 5 | <?php /* This include() script adds missing PHP functions to earlier interpreter versions, so you can make downwards compatible scripts without having to stick to the least common denominator. It only defines the ones that | | > | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <?php /* This include() script adds missing PHP functions to earlier interpreter versions, so you can make downwards compatible scripts without having to stick to the least common denominator. It only defines the ones that are really missing - the faster native functions will be used whenever available. - many of the emulation functions are one-liners - a few features have been added that never made it into one of the official versions (CVS code and the ever-absent "gzdecode" and "file_put_contents" for example) - a few very extravagant functions (array_u?diff*_u*assoc?) and other extensions have been separated out into ext/ - the advanced OO-capabilities and language syntax extensions of PHP5 and ZE2 cannot seriously be emulated here, this emulation only takes care of procedural interfaces - with only this part loaded, you get "PHP 4.1 COMPATIBILITY" - this is PuplicDomain (no copyright, no license, no warranty) so you can melt it into anything, regardless of your preferred license (you may strip this paragraph and turn it all into GPL, BSD, GNU LGPL, Artistic, MPL, PHP license, M$ EULA, or whatever you like best) Get update notes via "http://freshmeat.net/projects/upgradephp" or |
︙ | ︙ | |||
105 106 107 108 109 110 111 | else { return($data); } } } | > | > | > | | | 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 | else { return($data); } } } #-- get all already made headers(), # CANNOT be emulated, because output buffering functions # already swallow up any sent http header if (!function_exists("ob_get_headers")) { function ob_get_headers() { return (array)NULL; } } #-- encodes required named XML entities, like htmlentities(), # but does not re-encode numeric &#xxxx; character references # - could screw up scripts which then implement this themselves # - doesn't fix bogus or invalid numeric entities if (!function_exists("xmlentities")) { function xmlentities($str) { return strtr($str, array( "&#"=>"&#", "&"=>"&", "'"=>"'", "<"=>"<", ">"=>">", "\""=>""", )); } |
︙ | ︙ | |||
141 142 143 144 145 146 147 | # -- # proc_nice # dns_get_record # date_sunrise - undoc. # date_sunset - undoc. | > | > | > > < > > > | > > > > | > > > < | > | | > > > | | | | < > | | > > | < < < | > > > > > > > > | < > > > > > > | > > > > > > | | | | | | | > | < | < < | > | | | | > | | | | | | | > | | | | > > | | | | > > | | | < < | | | | | < | > | > > > | > > > > > | > > | > > > > > | | > | > > > | > | | > > | | | | > > > | > > > | > > > > > > > > > > > | > > > | > | > > > > > | > > > > > > | | > > > | > | > | > > > > > | > > | > | < > > > > > > | > > > | | > > > > > > > | > > > > | | < < | < | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | > > > > > | > < | | > | | | > | > | > | 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 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 | # -- # proc_nice # dns_get_record # date_sunrise - undoc. # date_sunset - undoc. #-- constant: end of line if (!defined("PHP_EOL")) { define("PHP_EOL", ( (DIRECTORY_SEPARATOR == "\\") ?"\015\012" :(strncmp(PHP_OS,"D",1)?"\012":"\015") ) ); #" } #-- case-insensitive string search function, # - finds position of first occourence of a string c-i # - parameters identical to strpos() if (!function_exists("stripos")) { function stripos($haystack, $needle, $offset=NULL) { #-- simply lowercase args $haystack = strtolower($haystack); $needle = strtolower($needle); #-- search $pos = strpos($haystack, $needle, $offset); return($pos); } } #-- case-insensitive string search function # - but this one starts from the end of string (right to left) # - offset can be negative or positive if (!function_exists("strripos")) { function strripos($haystack, $needle, $offset=NULL) { #-- lowercase incoming strings $haystack = strtolower($haystack); $needle = strtolower($needle); #-- [-]$offset tells to ignore a few string bytes, # we simply cut a bit from the right if (isset($offset) && ($offset < 0)) { $haystack = substr($haystack, 0, strlen($haystack) - 1); } #-- let PHP do it $pos = strrpos($haystack, $needle); #-- [+]$offset => ignore left haystack bytes if (isset($offset) && ($offset > 0) && ($pos > $offset)) { $pos = false; } #-- result return($pos); } } #-- case-insensitive version of str_replace if (!function_exists("str_ireplace")) { function str_ireplace($search, $replace, $subject, $count=NULL) { #-- call ourselves recursively, if parameters are arrays/lists if (is_array($search)) { $replace = array_values($replace); foreach (array_values($search) as $i=>$srch) { $subject = str_ireplace($srch, $replace[$i], $subject); } } #-- sluice replacement strings through the Perl-regex module # (faster than doing it by hand) else { $replace = addcslashes($replace, "$\\"); $search = "{" . preg_quote($search) . "}i"; $subject = preg_replace($search, $replace, $subject); } #-- result return($subject); } } #-- performs a http HEAD request if (!function_exists("get_headers")) { function get_headers($url, $parse=0) { #-- extract URL parts ($host, $port, $path, ...) $c = parse_url($url); extract($c); if (!isset($port)) { $port = 80; } #-- try to open TCP connection $f = fsockopen($host, $port, $errno, $errstr, $timeout=15); if (!$f) { return; } #-- send request header socket_set_blocking($f, true); fwrite($f, "HEAD $path HTTP/1.0\015\012" . "Host: $host\015\012" . "Connection: close\015\012" . "Accept: */*, xml/*\015\012" . "User-Agent: ".trim(ini_get("user_agent"))."\015\012" . "\015\012"); #-- read incoming lines $ls = array(); while ( !feof($f) && ($line = trim(fgets($f, 1<<16))) ) { #-- read header names to make result an hash (names in array index) if ($parse) { if ($l = strpos($line, ":")) { $name = substr($line, 0, $l); $value = trim(substr($line, $l + 1)); #-- merge headers if (isset($ls[$name])) { $ls[$name] .= ", $value"; } else { $ls[$name] = $value; } } #-- HTTP response status header as result[0] else { $ls[] = $line; } } #-- unparsed header list (numeric indices) else { $ls[] = $line; } } #-- close TCP connection and give result fclose($f); return($ls); } } #-- list of already/potentially sent HTTP responsee headers(), # CANNOT be implemented (except for Apache module maybe) if (!function_exists("headers_list")) { function headers_list() { trigger_error("headers_list(): not supported by this PHP version", E_USER_WARNING); return (array)NULL; } } #-- write formatted string to stream/file, # arbitrary numer of arguments if (!function_exists("fprintf")) { function fprintf(/*...*/) { $args = func_get_args(); $stream = array_shift($args); return fwrite($stream, call_user_func_array("sprintf", $args)); } } #-- write formatted string to stream, args array if (!function_exists("vfprintf")) { function vfprintf($stream, $format, $args=NULL) { return fwrite($stream, vsprintf($format, $args)); } } #-- splits a string in evenly sized chunks # and returns this as array if (!function_exists("str_split")) { function str_split($str, $chunk=1) { $r = array(); #-- return back as one chunk completely, if size chosen too low if ($chunk < 1) { $r[] = $str; } #-- add substrings to result array until subject strings end reached else { $len = strlen($str); for ($n=0; $n<$len; $n+=$chunk) { $r[] = substr($str, $n, $chunk); } } return($r); } } #-- constructs a QUERY_STRING (application/x-www-form-urlencoded format, non-raw) # from a nested array/hash with name=>value pairs # - only first two args are part of the original API - rest used for recursion if (!function_exists("http_build_query")) { function http_build_query($data, $int_prefix="", $subarray_pfix="", $level=0) { #-- empty starting string $s = ""; ($SEP = ini_get("arg_separator.output")) or ($SEP = "&"); #-- traverse hash/array/list entries foreach ($data as $index=>$value) { #-- add sub_prefix for subarrays (happens for recursed innovocation) if ($subarray_pfix) { if ($level) { $index = "[" . $index . "]"; } $index = $subarray_pfix . $index; } #-- add user-specified prefix for integer-indices elseif (is_int($index) && strlen($int_prefix)) { $index = $int_prefix . $index; } #-- recurse for sub-arrays if (is_array($value)) { $s .= http_build_query($value, "", $index, $level + 1); } else { // or just literal URL parameter $s .= $SEP . $index . "=" . urlencode($value); } } #-- remove redundant "&" from first round (-not checked above to simplifiy loop) if (!$subarray_pfix) { $s = substr($s, strlen($SEP)); } #-- return result / to previous array level and iteration return($s); } } #-- transform into 3to4 uuencode # - this is the bare encoding, not the uu file format if (!function_exists("convert_uuencode")) { function convert_uuencode($data) { #-- init vars $out = ""; $line = ""; $len = strlen($data); # $data .= "\252\252\252"; // PHP and uuencode(1) use some special garbage??, looks like "\000"* and "`\n`" simply appended #-- canvass source string for ($n=0; $n<$len; ) { #-- make 24-bit integer from first three bytes $x = (ord($data[$n++]) << 16) + (ord($data[$n++]) << 8) + (ord($data[$n++]) << 0); #-- disperse that into 4 ascii characters $line .= chr( 32 + (($x >> 18) & 0x3f) ) . chr( 32 + (($x >> 12) & 0x3f) ) . chr( 32 + (($x >> 6) & 0x3f) ) . chr( 32 + (($x >> 0) & 0x3f) ); #-- cut lines, inject count prefix before each if (($n % 45) == 0) { $out .= chr(32 + 45) . "$line\n"; $line = ""; } } #-- throw last line, +length prefix if ($trail = ($len % 45)) { $out .= chr(32 + $trail) . "$line\n"; } // uuencode(5) doesn't tell so, but spaces are replaced with the ` char in most implementations $out = strtr("$out \n", " ", "`"); return($out); } } #-- decodes uuencoded() data again if (!function_exists("convert_uudecode")) { function convert_uudecode($data) { #-- prepare $out = ""; $data = strtr($data, "`", " "); #-- go through lines foreach(explode("\n", ltrim($data)) as $line) { if (!strlen($line)) { break; // end reached } #-- current line length prefix unset($num); $num = ord($line{0}) - 32; if (($num <= 0) || ($num > 62)) { // 62 is the maximum line length break; // according to uuencode(5), so we stop here too } $line = substr($line, 1); #-- prepare to decode 4-char chunks $add = ""; for ($n=0; strlen($add)<$num; ) { #-- merge 24 bit integer from the 4 ascii characters (6 bit each) $x = ((ord($line[$n++]) - 32) << 18) + ((ord($line[$n++]) - 32) << 12) // were saner with "& 0x3f" + ((ord($line[$n++]) - 32) << 6) + ((ord($line[$n++]) - 32) << 0); #-- reconstruct the 3 original data chars $add .= chr( ($x >> 16) & 0xff ) . chr( ($x >> 8) & 0xff ) . chr( ($x >> 0) & 0xff ); } #-- cut any trailing garbage (last two decoded chars may be wrong) $out .= substr($add, 0, $num); $line = ""; } return($out); } } #-- return array of filenames in a given directory # (only works for local files) if (!function_exists("scandir")) { function scandir($dirname, $desc=0) { #-- check for file:// protocol, others aren't handled if (strpos($dirname, "file://") === 0) { $dirname = substr($dirname, 7); if (strpos($dirname, "localh") === 0) { $dirname = substr($dirname, strpos($dirname, "/")); } } #-- directory reading handle if ($dh = opendir($dirname)) { $ls = array(); while ($fn = readdir($dh)) { $ls[] = $fn; // add to array } closedir($dh); #-- sort filenames if ($desc) { rsort($ls); } else { sort($ls); } return $ls; } #-- failure return false; } } #-- like date(), but returns an integer for given one-letter format parameter if (!function_exists("idate")) { function idate($formatchar, $timestamp=NULL) { #-- reject non-simple type parameters if (strlen($formatchar) != 1) { return false; } #-- get current time, if not given if (!isset($timestamp)) { $timestamp = time(); } #-- get and turn into integer $str = date($formatchar, $timestamp); return (int)$str; } } #-- combined sleep() and usleep() if (!function_exists("time_nanosleep")) { function time_nanosleep($sec, $nano) { sleep($sec); usleep($nano); } } #-- search first occourence of any of the given chars, returns rest of haystack # (char_list must be a string for compatibility with the real PHP func) if (!function_exists("strpbrk")) { function strpbrk($haystack, $char_list) { #-- prepare $len = strlen($char_list); $min = strlen($haystack); #-- check with every symbol from $char_list for ($n = 0; $n < $len; $n++) { $l = strpos($haystack, $char_list{$n}); #-- get left-most occourence if (($l !== false) && ($l < $min)) { $min = $l; } } #-- result if ($min) { return(substr($haystack, $min)); } else { return(false); } } } #-- logo image activation URL query strings (gaga feature) if (!function_exists("php_real_logo_guid")) { function php_real_logo_guid() { return php_logo_guid(); } function php_egg_logo_guid() { return zend_logo_guid(); } } #-- no need to implement this # (there aren't interfaces in PHP4 anyhow) if (!function_exists("get_declared_interfaces")) { function get_declared_interfaces() { trigger_error("get_declared_interfaces(): Current script won't run reliably with PHP4.", E_USER_WARNING); return( (array)NULL ); } } #-- creates an array from lists of $keys and $values # (both should have same number of entries) if (!function_exists("array_combine")) { function array_combine($keys, $values) { #-- convert input arrays into lists $keys = array_values($keys); $values = array_values($values); $r = array(); #-- one from each foreach ($values as $i=>$val) { if ($key = $keys[$i]) { $r[$key] = $val; } else { $r[] = $val; // useless, PHP would have long aborted here } } return($r); } } #-- apply userfunction to each array element (descending recursively) # use it like: array_walk_recursive($_POST, "stripslashes"); # - $callback can be static function name or object/method, class/method if (!function_exists("array_walk_recursive")) { function array_walk_recursive(&$input, $callback, $userdata=NULL) { #-- each entry foreach ($input as $key=>$value) { #-- recurse for sub-arrays if (is_array($value)) { array_walk_recursive($input[$key], $callback, $userdata); } #-- $callback handles scalars else { call_user_func_array($callback, array(&$input[$key], $key, $userdata) ); } } // no return value } } #-- complicated wrapper around substr() and and strncmp() if (!function_exists("substr_compare")) { function substr_compare($haystack, $needle, $offset=0, $len=0, $ci=0) { #-- check params if ($len <= 0) { // not well documented $len = strlen($needle); if (!$len) { return(0); } } #-- length exception if ($len + $offset >= strlen($haystack)) { trigger_error("substr_compare: given length exceeds main_str", E_USER_WARNING); return(false); } #-- cut if ($offset) { $haystack = substr($haystack, $offset, $len); } #-- case-insensitivity if ($ci) { $haystack = strtolower($haystack); |
︙ | ︙ | |||
582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 | } #-- gets you list of class names the given objects class was derived from, slow if (!function_exists("class_parents")) { function class_parents($obj) { $all = get_declared_classes(); $r = array(); foreach ($all as $potential_parent) { if (is_subclass_of($obj, $potential_parent)) { $r[$potential_parent] = $potential_parent; } } return($r); } } #-- an alias if (!function_exists("session_commit") && function_exists("session_write_close")) { function session_commit() { session_write_close(); } } #-- aliases if (!function_exists("dns_check_record")) { function dns_check_record($host, $type=NULL) { return checkdnsrr($host, $type); } } if (!function_exists("dns_get_mx")) { function dns_get_mx($host, $mx) { $args = func_get_args(); | > > > > > > > | > > > > > | > | 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 | } #-- gets you list of class names the given objects class was derived from, slow if (!function_exists("class_parents")) { function class_parents($obj) { #-- first get full list $all = get_declared_classes(); $r = array(); #-- filter out foreach ($all as $potential_parent) { if (is_subclass_of($obj, $potential_parent)) { $r[$potential_parent] = $potential_parent; } } return($r); } } #-- an alias if (!function_exists("session_commit") && function_exists("session_write_close")) { function session_commit() { // simple session_write_close(); } } #-- aliases if (!function_exists("dns_check_record")) { function dns_check_record($host, $type=NULL) { // synonym to return checkdnsrr($host, $type); } } if (!function_exists("dns_get_mx")) { function dns_get_mx($host, $mx) { $args = func_get_args(); // simple alias - except the optional, but referenced third parameter if ($args[2]) { $w = & $args[2]; } else { $w = false; } return getmxrr($host, $mx, $w); } } #-- setrawcookie(), # can this be emulated 100% exactly? if (!function_exists("setrawcookie")) { // we output everything directly as HTTP header(), PHP doesn't seem // to manage an internal cookie list anyhow function setrawcookie($name, $value=NULL, $expire=NULL, $path=NULL, $domain=NULL, $secure=0) { if (isset($value) && strpbrk($value, ",; \r\t\n\f\014\013")) { trigger_error("setrawcookie: value may not contain any of ',; \r\n' and some other control chars; thrown away", E_USER_WARNING); } |
︙ | ︙ | |||
639 640 641 642 643 644 645 646 647 648 649 650 | } } } #-- write-at-once file access (counterpart to file_get_contents) if (!function_exists("file_put_contents")) { define("FILE_USE_INCLUDE_PATH", 1); define("FILE_IGNORE_NEW_LINES", 2); define("FILE_SKIP_EMPTY_LINES", 4); define("FILE_APPEND", 8); define("FILE_NO_DEFAULT_CONTEXT", 16); | > > > > > > > > > > > > > > > > > > > > > > < < < < < < < > | > > | > > > > > > > > > > > > > > > > > > > > > > > > | > > > | | | < | > > > > | > | < | | | > | > > > > > > > > > > > > | > > > > > > < > | > > > > | > > > > > > | | 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 | } } } #-- write-at-once file access (counterpart to file_get_contents) if (!function_exists("file_put_contents")) { function file_put_contents($filename, $data, $flags=0, $resource=NULL) { #-- prepare $mode = ($flags & FILE_APPEND ? "a" : "w" ) ."b"; $incl = $flags & FILE_USE_INCLUDE_PATH; $length = strlen($data); #-- open for writing $f = fopen($filename, $mode, $incl); if ($f) { $written = fwrite($f, $data); fclose($f); #-- only report success, if completely saved return($length == $written); } } } #-- file-related constants if (!defined("FILE_APPEND")) { define("FILE_USE_INCLUDE_PATH", 1); define("FILE_IGNORE_NEW_LINES", 2); define("FILE_SKIP_EMPTY_LINES", 4); define("FILE_APPEND", 8); define("FILE_NO_DEFAULT_CONTEXT", 16); } #-- more new constants for 5.0 if (!defined("E_STRICT")) { define("E_STRICT", 2048); // _STRICT is a special case of _NOTICE (_DEBUG) # PHP_CONFIG_FILE_SCAN_DIR } #-- array count_recursive() if (!defined("COUNT_RECURSIVE")) { define("COUNT_NORMAL", 0); // count($array, 0); define("COUNT_RECURSIVE", 1); // not supported } #-- we introduce a new function, because we cannot emulate the # newly introduced second parameter to count() if (!function_exists("count_recursive")) { function count_recursive($array, $mode=1) { if (!$mode) { return(count($array)); } else { $c = count($array); foreach ($array as $sub) { if (is_array($sub)) { $c += count_recursive($sub); } } return($c); } } } #------------------------------------------------------------------ 4.3 --- # money_format - unimpl? # sha1, sha1_file - too much code to pack it into here; and this # has already been implemented elsewhere, btw #-- simplified file read-at-once function if (!function_exists("file_get_contents")) { function file_get_contents($filename, $use_include_path=1) { #-- open file, let fopen() report error $f = fopen($filename, "rb", $use_include_path); if (!$f) { return; } #-- read max 2MB $content = fread($f, 1<<21); fclose($f); return($content); } } #-- shell-like filename matching (* and ? globbing characters) if (!function_exists("fnmatch")) { #-- associated constants define("FNM_PATHNAME", 1<<0); // no wildcard ever matches a "/" define("FNM_NOESCAPE", 1<<1); // backslash can't escape meta chars define("FNM_PERIOD", 1<<2); // leading dot must be given explicit define("FNM_LEADING_DIR", 1<<3); // not in PHP define("FNM_CASEFOLD", 0x50); // match case-insensitive define("FNM_EXTMATCH", 1<<5); // not in PHP #-- implementation function fnmatch($pattern, $str, $flags=0x0000) { #-- 'hidden' files if ($flags & FNM_PERIOD) { if (($str[0] == ".") && ($pattern[0] != ".")) { return(false); // abort early } } #-- case-insensitivity $rxci = ""; if ($flags & FNM_CASEFOLD) { $rxci = "i"; } #-- handline of pathname separators (/) $wild = "."; if ($flags & FNM_PATHNAME) { $wild = "[^/".DIRECTORY_SEPARATOR.DIRECTORY_SEPARATOR."]"; } #-- check for cached regular expressions static $cmp = array(); if (isset($cmp["$pattern+$flags"])) { $rx = $cmp["$pattern+$flags"]; } #-- convert filename globs into regex else { $rx = preg_quote($pattern); $rx = strtr($rx, array( "\\*"=>"$wild*?", "\\?"=>"$wild", "\\["=>"[", "\\]"=>"]", )); $rx = "{^" . $rx . "$}" . $rxci; #-- cache if (count($cmp) >= 50) { $cmp = array(); // free } $cmp["$pattern+$flags"] = $rx; } #-- compare return(preg_match($rx, $str)); } } #-- file search and name matching (with shell patterns) if (!function_exists("glob")) { #-- introduced constants define("GLOB_MARK", 1<<0); define("GLOB_NOSORT", 1<<1); define("GLOB_NOCHECK", 1<<2); define("GLOB_NOESCAPE", 1<<3); define("GLOB_BRACE", 1<<4); define("GLOB_ONLYDIR", 1<<5); define("GLOB_NOCASE", 1<<6); define("GLOB_DOTS", 1<<7); // unlikely to work under Win(?), without replacing the explode() with // a preg_split() incorporating the native DIRECTORY_SEPARATOR as well #-- implementation function glob($pattern, $flags=0x0000) { $ls = array(); $rxci = ($flags & GLOB_NOCASE) ? "i" : ""; #echo "\n=> glob($pattern)...\n"; #-- transform glob pattern into regular expression # (similar to fnmatch() but still different enough to require a second func) if ($pattern) { #-- look at each directory/fn spec part separately $parts2 = explode("/", $pattern); $pat = preg_quote($pattern); $pat = strtr($pat, array("\\*"=>".*?", "\\?"=>".?")); if ($flags ^ GLOB_NOESCAPE) { // uh, oh, ouuch - the above is unclean enough... } if ($flags ^ GLOB_BRACE) { $pat = preg_replace("/\{(.+?)\}/e", 'strtr("[$1]", ",", "")', $pat); } $parts = explode("/", $pat); #echo "parts == ".implode(" // ", $parts) . "\n"; $lasti = count($parts) - 1; $dn = ""; foreach ($parts as $i=>$p) { #-- basedir included (yet no pattern matching necessary) if (!strpos($p, "*?") && (strpos($p, ".?")===false)) { $dn .= $parts2[$i] . ($i!=$lasti ? "/" : ""); #echo "skip:$i, cause no pattern matching char found -> only a basedir spec\n"; continue; } #-- start reading dir + match filenames against current pattern if ($dh = opendir($dn ?$dn:'.')) { $with_dot = ($p[1]==".") || ($flags & GLOB_DOTS); |
︙ | ︙ | |||
821 822 823 824 825 826 827 | if ($flags ^ GLOB_NOSORT) { sort($ls); } #print_r($ls); #echo "<=\n"; return($ls); } | | | > > > > > | | > > | > | > > > > > > | | > > < < | > | | > > | > > > > > > > > | > > | | 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 | if ($flags ^ GLOB_NOSORT) { sort($ls); } #print_r($ls); #echo "<=\n"; return($ls); } } //@FIX: fully comment, remove debugging code (- as soon as it works ;) #-- redundant alias for isset() if (!function_exists("array_key_exists")) { function array_key_exists($key, $search) { return isset($search[$key]); } } #-- who could need that? if (!function_exists("array_intersect_assoc")) { function array_intersect_assoc( /*array, array, array...*/ ) { #-- parameters, prepare $in = func_get_args(); $cmax = count($in); $whatsleftover = array(); #-- walk through each array pair # (take first as checklist) foreach ($in[0] as $i => $v) { for ($c = 1; $c < $cmax; $c++) { #-- remove entry, as soon as it isn't present # in one of the other arrays if (!isset($in[$c][$i]) || (@$in[$c][$i] !== $v)) { continue 2; } } #-- it was found in all other arrays $whatsleftover[$i] = $v; } return $whatsleftover; } } #-- the opposite of the above if (!function_exists("array_diff_assoc")) { function array_diff_assoc( /*array, array, array...*/ ) { #-- params $in = func_get_args(); $diff = array(); #-- compare each array with primary/first foreach ($in[0] as $i=>$v) { for ($c=1; $c<count($in); $c++) { #-- skip as soon as it matches with entry in another array if (isset($in[$c][$i]) && ($in[$c][$i] == $v)) { continue 2; } } #-- else $diff[$i] = $v; } return $diff; } } #-- opposite of htmlentities if (!function_exists("html_entity_decode")) { function html_entity_decode($string, $quote_style=ENT_COMPAT, $charset="ISO-8859-1") { //@FIX: we fall short on anything other than Latin-1 $y = array_flip(get_html_translation_table(HTML_ENTITIES, $quote_style)); return strtr($string, $y); } } #-- extracts single words from a string if (!function_exists("str_word_count")) { function str_word_count($string, $result=0) { #-- let someone else do the work preg_match_all('/([\w](?:[-\'\w]?[\w]+)*)/', $string, $uu); #-- return full word list if ($result == 1) { return($uu[1]); } #-- array() of $pos=>$word entries elseif ($result >= 2) { $r = array(); $l = 0; foreach ($uu[1] as $word) { $l = strpos($string, $word, $l); $r[$l] = $word; $l += strlen($word); // speed up next search } return($r); } #-- only count else { return(count($uu[1])); } } } #-- creates a permutation of the given strings characters # (let's hope the random number generator was alread initialized) if (!function_exists("str_shuffle")) { function str_shuffle($str) { $r = ""; #-- cut string down with every iteration while (strlen($str)) { $n = strlen($str) - 1; if ($n) { $n = rand(0, $n); // glibcs` rand is ok since 2.1 at least } #-- cut out elected char, add to result string $r .= $str{$n}; $str = substr($str, 0, $n) . substr($str, $n + 1); } return($r); } } |
︙ | ︙ | |||
936 937 938 939 940 941 942 | ini_restore("include_path"); } } #-- constants for 4.3 if (!defined("PATH_SEPARATOR")) { | | | > > > | > > | 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 | ini_restore("include_path"); } } #-- constants for 4.3 if (!defined("PATH_SEPARATOR")) { define("PATH_SEPARATOR", ((DIRECTORY_SEPARATOR=='\\') ? ';' :':')); define("PHP_SHLIB_SUFFIX", ((DIRECTORY_SEPARATOR=='\\') ? 'dll' :'so')); } if (!defined("PHP_SAPI")) { define("PHP_SAPI", php_sapi_name()); } #-- not identical to what PHP reports (it seems to `which` for itself) if (!defined("PHP_PREFIX") && isset($_ENV["_"])) { define("PHP_PREFIX", substr($_ENV["_"], 0, strpos($_ENV["_"], "bin/"))); } #------------------------------------------------------------------ 4.2 --- # almost complete!? |
︙ | ︙ | |||
966 967 968 969 970 971 972 973 974 975 976 | return strtr($str, $from, $to); } } #-- well, if you need it if (!function_exists("array_change_key_case")) { define("CASE_LOWER", 0); define("CASE_UPPER", 1); function array_change_key_case($array, $case=CASE_LOWER) { foreach ($array as $i=>$v) { | > > > > > > < > > < | > > | > > > > | > > > > > | > > > > > > | | | | | > > | | | | < > > > | > > | | 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 | return strtr($str, $from, $to); } } #-- well, if you need it if (!function_exists("array_change_key_case")) { #-- introduced constants define("CASE_LOWER", 0); define("CASE_UPPER", 1); #-- implementation function array_change_key_case($array, $case=CASE_LOWER) { #-- loop through foreach ($array as $i=>$v) { #-- do anything for strings only if (is_string($i)) { unset($array[$i]); $i = ($case==CASE_LOWER) ? strtolower($i) : strtoupper($i); $array[$i] = $v; } // non-recursive } return($array); } } #-- create fixed-length array made up of $value data if (!function_exists("array_fill")) { function array_fill($start_index, $num, $value) { #-- params $r = array(); $i = $start_index; $end = $num + $start_index; #-- append for (; $i < $end; $i++) { $r[$i] = $value; } return($r); } } #-- split an array into evenly sized parts if (!function_exists("array_chunk")) { function array_chunk($input, $size, $preserve_keys=false) { #-- array for chunked output $r = array(); $n = -1; // chunk index #-- enum input array blocks foreach ($input as $i=>$v) { #-- new chunk if (($n < 0) || (count($r[$n]) == $size)) { $n++; $r[$n] = array(); } #-- add input value into current [$n] chunk if ($preserve_keys) { $r[$n][$i] = $v; } else { $r[$n][] = $v; } } return($r); } } #-- convenience wrapper if (!function_exists("md5_file")) { function md5_file($filename, $raw_output=false) { #-- read file, apply hash function $data = file_get_contents($filename, "rb"); $r = md5($data); $data = NULL; #-- transform? and return if ($raw_output) { $r = pack("H*", $r); } return $r; } } #-- object type checking if (!function_exists("is_a")) { function is_a($obj, $classname) { #-- lowercase everything for comparison $classnaqme = strtolower($classname); $obj_class = strtolower(get_class($obj)); #-- two possible checks return ($obj_class == $classname) or is_subclass_of($obj, $classname); } } #-- floating point modulo if (!function_exists("fmod")) { function fmod($x, $y) { |
︙ | ︙ | |||
1063 1064 1065 1066 1067 1068 1069 1070 | return (float)$str; } } #-- floats if (!function_exists("is_infinite")) { define("NAN", "NAN"); | > > | > > > > > > > > > | 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 | return (float)$str; } } #-- floats if (!function_exists("is_infinite")) { #-- constants as-is define("NAN", "NAN"); define("INF", "INF"); // there is also "-INF" #-- simple checks function is_infinite($f) { $s = (string)$f; return( ($s=="INF") || ($s=="-INF") ); } function is_nan($f) { $s = (string)$f; return( $s=="NAN" ); } function is_finite($f) { $s = (string)$f; return( !strpos($s, "N") ); } } #-- throws value-instantiation PHP-code for given variable # (a bit different from the standard, was intentional for its orig use) if (!function_exists("var_export")) { function var_export($var, $return=false, $indent="", $output="") { #-- output as in-class variable definitions if (is_object($var)) { $output = "class " . get_class($var) . " {\n"; foreach (((array)$var) as $id=>$var) { $output .= " var \$$id = " . var_export($var, true) . ";\n"; } $output .= "}"; } #-- array constructor elseif (is_array($var)) { foreach ($var as $id=>$next) { if ($output) $output .= ",\n"; else $output = "array(\n"; $output .= $indent . ' ' . (is_numeric($id) ? $id : '"'.addslashes($id).'"') . ' => ' . var_export($next, true, "$indent "); } if (empty($output)) $output = "array("; $output .= "\n{$indent})"; #if ($indent == "") $output .= ";"; } #-- literals elseif (is_numeric($var)) { $output = "$var"; } elseif (is_bool($var)) { $output = $var ? "true" : "false"; } else { $output = "'" . preg_replace("/([\\\\\'])/", '\\\\$1', $var) . "'"; } #-- done if ($return) { return($output); } else { print($output); } |
︙ | ︙ | |||
1145 1146 1147 1148 1149 1150 1151 | # version_compare # # See also "ext/math41.php" for some more (rarely used mathematical funcs). | | | 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 | # version_compare # # See also "ext/math41.php" for some more (rarely used mathematical funcs). #-- aliases (an earlier fallen attempt to unify PHP function names) if (!function_exists("diskfreespace")) { function diskfreespace() { return disk_free_sapce(); } function disktotalspace() { return disk_total_sapce(); } |
︙ | ︙ | |||
1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 | } } #-- can be used to simulate a register_globals=on environment if (!function_exists("import_request_variables")) { function import_request_variables($types="GPC", $pfix="") { if (!isset($_REQUEST)) { $_GET = & $HTTP_GET_VARS; $_POST = & $HTTP_POST_VARS; $_COOKIE = & $HTTP_COOKIE_VARS; } | > > > > > > > > > > | | < < < < < | | 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 | } } #-- can be used to simulate a register_globals=on environment if (!function_exists("import_request_variables")) { function import_request_variables($types="GPC", $pfix="") { #-- associate abbreviations to global var names $alias = array( "G" => "_GET", "P" => "_POST", "C" => "_COOKIE", "S" => "_SERVER", // non-standard "E" => "_ENV", // non-standard ); #-- alias long names (PHP < 4.0.6) if (!isset($_REQUEST)) { $_GET = & $HTTP_GET_VARS; $_POST = & $HTTP_POST_VARS; $_COOKIE = & $HTTP_COOKIE_VARS; } #-- copy for ($i=0; $i<strlen($types); $i++) { if ($FROM = $alias[strtoupper($c)]) { foreach ($$FROM as $key=>$val) { if (!isset($GLOBALS[$pfix.$key])) { $GLOBALS[$pfix . $key] = $val; } } } } // done } } |
︙ | ︙ | |||
1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 | return( log($x + sqrt($x*$x-1)) ); } function atanh($x) { return( log1p( 2*$x / (1-$x) ) / 2 ); } } #-- other stuff /* removed funcs?? [18] => leak */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 | return( log($x + sqrt($x*$x-1)) ); } function atanh($x) { return( log1p( 2*$x / (1-$x) ) / 2 ); } } #-- HMAC from RFC2104, but see also PHP_Compat and Crypt_HMAC if (!function_exists("mhash")) { #-- constants define("MHASH_CRC32", 0); define("MHASH_MD5", 1); // RFC1321 define("MHASH_SHA1", 2); // RFC3174 define("MHASH_TIGER", 7); define("MHASH_MD4", 16); // RFC1320 define("MHASH_SHA256", 17); define("MHASH_ADLER32", 18); #-- implementation function mhash($hashtype, $text, $key) { #-- hash function if (!($func = mhash_get_hash_name($hashtype)) || !function_exists($func)) { return trigger_error("mhash: cannot use hash algorithm #$hashtype/$func", E_USER_ERROR); } if (!$key) { trigger_error("mhash: called without key", E_USER_WARNING); } #-- params $bsize = mhash_get_block_size($hashtype); // fixed size, 64 #-- pad key if (strlen($key) > $bsize) { // hash key, when it's too long $key = $func($key); $key = pack("H*", $key); // binarify } $key = str_pad($key, $bsize, "\0"); // fill up with NULs (1) #-- prepare inner and outer padding stream $ipad = str_pad("", $bsize, "6"); // %36 $opad = str_pad("", $bsize, "\\"); // %5C #-- call hash func // php can XOR strings for us $dgst = pack("H*", $func( ($key ^ $ipad) . $text )); // (2,3,4) $dgst = pack("H*", $func( ($key ^ $opad) . $dgst )); // (5,6,7) return($dgst); } #-- return which hash functions are implemented function mhash_count() { return(MHASH_SHA1); } #-- map numeric identifier to hash function name function mhash_get_hash_name($i) { static $hash_funcs = array( MHASH_CRC32 => "crc32", // would need dechex()ing in main func? MHASH_MD5 => "md5", MHASH_SHA1 => "sha1", ); return(strtoupper($hash_funcs[$i])); } #-- static value function mhash_get_block_size($i) { return(64); } } #-- other stuff /* removed funcs?? [18] => leak */ |
︙ | ︙ |