PHP userland backwards compatibility layer that emulates PHP 5.5+ core functions.

⌈⌋ ⎇ branch:  upgrade.php


Check-in [bcf7d8cbab]

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:upgradephp-12
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: bcf7d8cbab53b6c9dac3c0a1ab6418a43ded0ba9
User & Date: mario 2010-06-22 16:59:47
Context
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
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to README.

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 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






|







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
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

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.





      PEAR::PHP_Compat
      ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
      Only after finishing release 5 of this library I found out, that
      such a thing already exists.  You can find the PEAR package named
      "PHP_Compat" (written by Aidan Lister) on http://pear.php.net/,
      and give that a try also.  Because it exists much 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
      comes under the PHP license.


      You could get something similar to this "upgrade.php" script by
      simply unpacking the PHP_Compat tarball and running:

         cat  .../PHP_Compat-1.3.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 many overly redundant 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 package this with any application or
      script you are developing.

      And, btw IMO, in this case it was simply the drawback of the
      "PEAR coding standards", that PHP_Compat looks a bit complicated
      at first - it just had to be made a bit "OO", because that's the
      magic entry ticket buzzword over there.

      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).








|
>
>






|
|
|


|
|
>




|



|


|
|


|
|
|







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
91
92
93
94
95
96
97
98

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") { require(".../upgrade.php"); }
  ?>

Currently following functions can be emulated:
· gzdecode
· ob_get_headers
· xmlentities
· stripos







|







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
115
116
117
118
119
120
121
122
123
124
125
126
127

128
129
130
131
132
133
134
· convert_uudecode
· scandir
· idate
· time_nanosleep
· strpbrk
· php_real_logo_guid
· php_egg_logo_guid
· php_strip_whitespace
· php_check_syntax
· 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

· file_get_contents
· fnmatch
· glob
· array_key_exists
· array_intersect_assoc
· array_diff_assoc
· html_entity_decode







<
<











>







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
249
250
251
252
253
254
255
256
257
258
259
260
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

· "ext/spl" tries to mimic the "Standard PHP Library" which suddenly
  only is going to be made "standard" for PHP5 and above. Load this
  emulation with version 4 only. NOT READY (difficult to rewrite for
  the old PHP4 OO capabilities). Happily not in use too widely yet.

· "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







>
>
>













<
<
<
<
<







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
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
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.







|
|
|
|

|
|

|
|
|
|







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
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
¯¯¯¯¯¯¯¯
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().





Please also have a peek into the README files accompaning the script
snippets distributed in this directory.














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.







|
|
|
|

|
|
|
|
|
|
|
|

|
|
|
|
|

>
>
>
>



>
>
>
>
>
>
>
>
>
>
>







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
11
12
13
14
15
16
17
18




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 reqeust. 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.




>
>









|







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
5
6
7
8
9
10
11
12
13
14
15
16
17
<?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 output 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 - 'w3m' makes an excellent
   choice! (press "=" there)
*/

set_error_handler("ewiki_http_header_errors");
ini_set("html_errors", 0);

function ewiki_http_header_errors($errno, $msg, $file, $line, $lvars) {





|



|
<







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
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
   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;




      }
      $this->method($method);
      $this->setURL($url);
   }


   #-- sets request method
   function method($str = "GET") {
      $this->method = $str;
   }

   #-- special headers
   function setcookie($str = "name=value") {
      $this->cookies[strtok($str, "=")] = strtok("\000");
   }


   #-- deciphers URL into server+path and query string
   function setURL($url) {
      if ($this->method == "GET") {
         $this->url = strtok($url, "?");







|












>
>
>
>












|
|







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
398
399
400
401
402
403
404
405
               $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;
   var $type = "/dev/null";
   var $content = "";
   
   
   function http_response() {
   }
   








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>




>
>










|







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.

1
<?php if(!function_exists("gzdecode")){function gzdecode($data,$maxlen=NULL){$len=strlen($data);if($len<20){return;}$head=substr($data,0,10);$head=unpack("n1id/C1cm/C1flg/V1mtime/C1xfl/C1os",$head);list($ID,$CM,$FLG,$MTIME,$XFL,$OS)=array_values($head);$FTEXT=1<<0;$FHCRC=1<<1;$FEXTRA=1<<2;$FNAME=1<<3;$FCOMMENT=1<<4;$head=unpack("V1crc/V1isize",substr($data,$len-8,8));list($CRC32,$ISIZE)=array_values($head);if($ID!=0x1f8b){trigger_error("gzdecode: not in gzip format",E_USER_WARNING);return;}if($CM!=8){trigger_error("gzdecode: cannot decode anything but deflated streams",E_USER_WARNING);return;}$s=10;if($FLG&$FEXTRA){$s+=$XFL;}if($FLG&$FNAME){$s=strpos($data,"\000",$s)+1;}if($FLG&$FCOMMENT){$s=strpos($data,"\000",$s)+1;}if($FLG&$FHCRC){$s+=2;}$data=substr($data,$s,$len-$s);if($maxlen){$data=gzinflate($data,$maxlen);return($data);}else{$data=gzinflate($data);}$chk=crc32($data);if($CRC32!=$chk){trigger_error("gzdecode: checksum failed(real$chk!=comp$CRC32)",E_USER_WARNING);}elseif($ISIZE!=strlen($data)){trigger_error("gzdecode: stream size mismatch",E_USER_WARNING);}else{return($data);}}}if(!function_exists("ob_get_headers")){function ob_get_headers(){return(array)NULL;}}if(!function_exists("xmlentities")){function xmlentities($str){return strtr($str,array("&#"=>"&#","&"=>"&amp;","'"=>"&apos;","<"=>"&lt;",">"=>"&gt;","\""=>"&quot;",));}}if(!defined("PHP_EOL")){define("PHP_EOL",((DIRECTORY_SEPARATOR=="\\")?"\015\012":(strncmp(PHP_OS,"D",1)?"\012":"\015")));}if(!function_exists("stripos")){function stripos($haystack,$needle,$offset=NULL){return strpos(strtolower($haystack),strtolower($needle),$offset);}}if(!function_exists("strripos")){function strripos($haystack,$needle,$offset=NULL){if(isset($offset)){$haystack=strtolower($haystack);$needle=strtolower($needle);if($offset<0){$offset=strlen($haystack)+$offset;}do{$l=$new;$new=strpos($haystack,$needle,$l);}while(($new!==false)&&($new<$offset));return($l);}else{return strrpos(strtolower($haystack),strtolower($needle));}}}if(!function_exists("str_ireplace")){function str_ireplace($search,$replace,$subject,$count=NULL){if(is_array($search)){$replace=array_values($replace);foreach(array_values($search)as$i=>$srch){$subject=str_ireplace($srch,$replace[$i],$subject);}}else{$search="\007". preg_quote($search)."\007i";$replace=strtr($replace,array('$'=>'\\$',"\\"=>"\\\\"));$subject=preg_replace($search,$replace,$subject);}return($subject);}}if(!function_exists("get_headers")){function get_headers($url,$parse=0){$c=parse_url($url);extract($c);if(!isset($port)){$port=80;}if($f=fsockopen($host,$port,$errno,$errstr,$timeout=5)){fwrite($f,"HEAD$path HTTP/1.1\015\012"."Host:$host\015\012"."Connection: close\015\012"."Accept:*/*\015\012"."User-Agent:".trim(ini_get("user_agent"))."\015\012"."\015\012");socket_set_blocking($f,true);$ls=array();while(!feof($f)){$line=trim(fgets($f,1<<16));if(!strlen($line)){break;}elseif($parse){if($l=strpos($line,":")){$name=substr($line,0,$l);$value=trim(substr($line,$l+1));if(isset($ls[$name])){$ls[$name].=",$value";}else{$ls[$name]=$value;}}else{$ls[]=$line;}}else{$ls[]=$line;}}fclose($f);return($ls);}else{return(false);}}}if(!function_exists("headers_list")){function headers_list(){trigger_error("headers_list(): not supported by this PHP version",E_USER_WARNING);return(array)NULL;}}if(!function_exists("fprintf")){function fprintf(){$args=func_get_args();$stream=array_shift($args);return fwrite($stream,call_user_func_array("sprintf",$args));}}if(!function_exists("vfprintf")){function vfprintf($stream,$format,$args=NULL){return fwrite($stream,vsprintf($format,$args));}}if(!function_exists("str_split")){function str_split($str,$chunk=1){$r=array();if($chunk<1){$r[]=$str;}else{$len=strlen($str);for($n=0;$n<$len;$n+=$chunk){$r[]=substr($str,$n,$chunk);}}return($r);}}if(!function_exists("http_build_query")){function http_build_query($data,$prefix="",$fpfix="",$l=0){$s="";foreach($data as$in=>$val){$s_in=$in;if($fpfix){$s_in=$l ?"$fpfix"."[$s_in]":"$fpfix$s_in";}elseif(is_int($s_in)&&$prefix){$s_in="$prefix$s_in";}if(is_array($val)){$s .=http_build_query($val,"",$s_in,$l+1);}else{$s .="&$s_in=". urlencode($val);}}if(!$fpfix){$s=substr($s,1);}return($s);}}if(!function_exists("convert_uuencode")){function convert_uuencode($data){$out="";$line="";$len=strlen($data);for($n=0;$n<$len;){$x=(ord($data[$n++])<<16)+(ord($data[$n++])<<8)+(ord($data[$n++])<<0);$line .=chr(32+(($x>>18)&0x3f)). chr(32+(($x>>12)&0x3f)). chr(32+(($x>>6)&0x3f)). chr(32+(($x>>0)&0x3f));if(($n % 45)==0){$out .=chr(32+45)."$line\n";$line="";}}if($trail=($len % 45)){$out .=chr(32+$trail)."$line\n";}$out=strtr("$out \n","","`");return($out);}}if(!function_exists("convert_uudecode")){function convert_uudecode($data){$out="";$data=strtr($data,"`","");foreach(explode("\n",ltrim($data))as$line){if(!strlen($line)){break;}unset($num);$num=ord($line{0})-32;if(($num<=0)||($num>62)){break;}$line=substr($line,1);$add="";for($n=0;strlen($add)<$num;){$x=((ord($line[$n++])-32)<<18)+((ord($line[$n++])-32)<<12)+((ord($line[$n++])-32)<<6)+((ord($line[$n++])-32)<<0);$add .=chr(($x>>16)&0xff). chr(($x>>8)&0xff). chr(($x>>0)&0xff);}$out .=substr($add,0,$num);$line="";}return($out);}}if(!function_exists("scandir")){function scandir($dirname,$desc=0){if(strpos($dirname,"file://")===0){$dirname=substr($dirname,7);if(strpos($dirname,"localh")===0){$dirname=substr($dirname,strpos($dirname,"/"));}}if($dh=opendir($dirname)){$ls=array();while($fn=readdir($dh)){$ls[]=$fn;}closedir($dh);if($desc){rsort($ls);}else{sort($ls);}return$ls;}else{return false;}}}if(!function_exists("idate")){function idate($formatchar,$timestamp=NULL){if(strlen($formatchar)!=1){return false;}if(!isset($timestamp)){$timestamp=time();}return((int)(date($formatchar,$timestamp)));}}if(!function_exists("time_nanosleep")){function time_nanosleep($sec,$nano){sleep($sec);usleep($nano);}}if(!function_exists("strpbrk")){function strpbrk($haystack,$char_list){$cn=strlen($char_list);$min=strlen($haystack);for($n=0;$n<$cn;$n++){$l=strpos($haystack,$char_list{$n});if(($l!==false)&&($l<$min)){$min=$l;}}return($min ? substr($haystack,$min):$haystack);}}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();}}if(!function_exists("php_strip_whitespace")){function php_strip_whitespace($fn){$fn=escapeshellcmd($fn);$text=`php-wqCf '$fn'`;if(!$text){$text=implode("",file($fn));}return$text;}}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);}}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);}}if(!function_exists("array_combine")){function array_combine($keys,$values){$keys=array_values($keys);$values=array_values($values);$r=array();foreach($values as$i=>$val){if($key=$keys[$i]){$r[$key]=$val;}else{$r[]=$val;}}return($r);}}if(!function_exists("array_walk_recursive")){function array_walk_recursive(&$input,$callback,$userdata=NULL){foreach($input as$i=>$value){if(is_array($value)){array_walk_recursive($input[$i],$callback,@$userdata);}else{call_user_func_array($callback,array(&$input[$i],&$i,@$userdata));}}return NULL;}}if(!function_exists("substr_compare")){function substr_compare($haystack,$needle,$offset=0,$len=0,$ci=0){if($len<=0){$len=strlen($needle);if(!$len){return(0);}}if($len+$offset>=strlen($haystack)){trigger_error("substr_compare: given length exceeds main_str",E_USER_WARNING);return(false);}if($offset){$haystack=substr($haystack,$offset,$len);}if($ci){$haystack=strtolower($haystack);$needle=strtolower($needle);}return(strncmp($haystack,$needle,$len));}}if(!function_exists("spl_classes")){function spl_classes(){trigger_error("spl_classes(): not built into this PHP version");return(array)NULL;}}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);}}if(!function_exists("session_commit")&&function_exists("session_write_close")){function session_commit(){session_write_close();}}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();if($args[2]){$w=&$args[2];}return getmxrr($host,$mx,$w);}}if(!function_exists("setrawcookie")){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);}else{$h="Set-Cookie:$name=$value".($expire ?";expires=". gmstrftime("%a,%d-%b-%y %H:%M:%S %Z",$expire):"").($path ?";path=$path":"").($domain ?";domain=$domain":"").($secure ?";secure":"");header($h);}}}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);function file_put_contents($filename,$data,$flags=0,$resource=NULL){if($f=fopen($filename,($flags&FILE_APPEND?"a":"w")."b",$flags&FILE_USE_INCLUDE_PATH)){fwrite($f,$data);fclose($f);return(TRUE);}}}if(!defined("E_STRICT")){define("E_STRICT",2048);}if(!function_exists("file_get_contents")){function file_get_contents($filename,$use_include_path=1){if($f=fopen($filename,"rb",$use_include_path)){$content=fread($f,1<<21);fclose($f);return($content);}}}if(!function_exists("fnmatch")){define("FNM_PATHNAME",1<<0);define("FNM_NOESCAPE",1<<1);define("FNM_PERIOD",1<<2);define("FNM_LEADING_DIR",1<<3);define("FNM_CASEFOLD",0x50);define("FNM_EXTMATCH",1<<5);function fnmatch($pattern,$str,$flags=0x0000){static$cmp=array();$rxci=($flags&FNM_CASEFOLD ?'i' :'');$rx=@$cmp["$pattern$flags"];if(($str[0]==".")&&($flags&FNM_PERIOD)){if($pattern[0]!="."){return(false);}}if(!$rx){if(count($cmp)>=10){$cmp=array();}$rx=preg_quote($pattern);$wild=(($flags&FNM_PATHNAME)?"[^/]":".");$rx=strtr($rx,array("\\*"=>"$wild*?","\\?"=>"$wild","\\["=>"[","\\]"=>"]",));$rx="\007^$rx$\007$rxci";$cmp["$pattern$flags"]=$rx;}return(preg_match($rx,$str));}}if(!function_exists("glob")){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);function glob($pattern,$flags=0x0000){$ls=array();$rxci=($flags&GLOB_NOCASE)?"i":"";if($pattern){$parts2=explode("/",$pattern);$pat=preg_quote($pattern);$pat=strtr($pat,array("\\*"=>".*?","\\?"=>".?"));if($flags ^ GLOB_NOESCAPE){}if($flags ^ GLOB_BRACE){$pat=preg_replace("/\{(.+?)\}/e",'strtr("[$1]",",","")',$pat);}$parts=explode("/",$pat);$lasti=count($parts)-1;$dn="";foreach($parts as$i=>$p){if(!strpos($p,"*?")&&(strpos($p,".?")===false)){$dn .=$parts2[$i].($i!=$lasti ?"/":"");continue;}if($dh=opendir($dn ?$dn:'.')){$with_dot=($p[1]==".")||($flags&GLOB_DOTS);while($fn=readdir($dh)){if(preg_match("\007^$p$\007$rxci",$fn)){if(($fn[0]==".")&&!$with_dot){continue;}if($i==$lasti){if(is_dir("$dn$fn")){if($flags&GLOB_ONLYDIR){continue;}if($flags&GLOB_MARK){$fn .="/";}}$ls[]="$dn$fn";}elseif(is_dir("$dn$fn")){$remaind=implode("/",array_slice($parts2,$i+1));$ls=array_merge($ls,glob("$dn$fn/$remaind",$flags));}}}closedir($dh);break;}else{return($ls);}}}if(!$ls&&($flags&GLOB_NOCHECK)){$ls[]=$pattern;}if($flags ^ GLOB_NOSORT){sort($ls);}return($ls);}}if(!function_exists("array_key_exists")){function array_key_exists($key,$search){return isset($search[$key]);}}if(!function_exists("array_intersect_assoc")){function array_intersect_assoc(){$whatsleftover=array();$in=func_get_args();$cmax=count($in);foreach($in[0]as$i=>$v){for($c=1;$c<$cmax;$c++){if(@$in[$c][$i]!==$v){continue 2;}}$whatsleftover[$i]=$v;}return$whatsleftover;}}if(!function_exists("array_diff_assoc")){function array_diff_assoc(){$diff=array();$in=func_get_args();foreach($in[0]as$i=>$v){for($c=1;$c<count($in);$c++){if(isset($in[$c][$i])&&($in[$c][$i]==$v)){continue 2;}}$diff[$i]=$v;}return$diff;}}if(!function_exists("html_entity_decode")){function html_entity_decode($string,$quote_style=ENT_COMPAT,$charset="ISO-8859-1"){$y=array_flip(get_html_translation_table(HTML_ENTITIES,$quote_style));return strtr($string,$y);}}if(!function_exists("str_word_count")){function str_word_count($string,$format=0){preg_match_all('/([\w](?:[-\'\w]?[\w]+)*)/',$string,$uu);if(!$format){return(count($uu[1]));}elseif($format==1){return($uu[1]);}else{$r=array();$l=0;foreach($uu[1]as$word){$l=strpos($string,$word,$l);$r[$l]=$word;$l+=strlen($word);}return($r);}}}if(!function_exists("str_shuffle")){function str_shuffle($str){$r="";while(strlen($str)){$n=strlen($str)-1;if($n){$n=rand(0,$n);}$r .=$str[$n];$str=substr($str,0,$n). substr($str,$n+1);}return($r);}}if(!function_exists("get_include_path")){function get_include_path(){return(get_cfg_var("include_path"));}function set_include_path($new){return ini_set("include_path",$new);}function restore_include_path(){ini_restore("include_path");}}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());}if(!defined("PHP_PREFIX")&&isset($_ENV["_"])){define("PHP_PREFIX",substr($_ENV["_"],strpos($_ENV["_"],"/bin/")));}if(!function_exists("str_rot13")){function str_rot13($str){static$from="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";static$to="NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm";return strtr($str,$from,$to);}}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){unset($array[$i]);if(is_string($i)){$i=($case==CASE_LOWER)? strtolower($i): strtoupper($i);}$array[$i]=$v;}return($array);}}if(!function_exists("array_fill")){function array_fill($start_index,$num,$value){$r=array();for($i=$start_index,$end=$num+$i;$i<$end;$i++){$r[$i]=$value;}return($r);}}if(!function_exists("array_chunk")){function array_chunk($input,$size,$preserve_keys=false){$r=array();$n=-1;foreach($input as$i=>$v){if(($n<0)||(count($r[$n])==$size)){$n++;$r[$n]=array();}if($preserve_keys){$r[$n][$i]=$v;}else{$r[$n][]=$v;}}return($r);}}if(!function_exists("md5_file")){function md5_file($filename,$raw_output=false){if($f=fopen($filename,"rb")){$data=fread($f,1<<22);fclose($f);$r=md5($data);$data=NULL;if($raw_output){$r=pack("H*",$r);}return$r;}}}if(!function_exists("is_a")){function is_a($obj,$classname){return((strtolower(get_class($obj))==strtolower($classname))or is_subclass_of($obj,$classname));}}if(!function_exists("fmod")){function fmod($x,$y){$r=$x/$y;$r-=(int)$r;$r*=$y;return($r);}}if(!function_exists("floatval")){function floatval($str){$str=ltrim($str);return(float)$str;}}if(!function_exists("is_infinite")){define("NAN","NAN");define("INF","INF");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"));}}if(!function_exists("var_export")){function var_export($var,$return=false,$indent="",$output=""){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 .="}";}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})";}elseif(is_numeric($var)){$output="$var";}elseif(is_bool($var)){$output=$var ?"true":"false";}else{$output="'". preg_replace("/([\\\\\'])/",'\\\\$1',$var)."'";}if($return){return($output);}else{print($output);}}}if(!function_exists("strcoll")){function strcoll($str1,$str2){return strcmp($str1,$str2);}}if(!function_exists("diskfreespace")){function diskfreespace(){return disk_free_sapce();}function disktotalspace(){return disk_total_sapce();}}if(!function_exists("vprintf")){function vprintf($format,$args=NULL){call_user_func_array("fprintf",get_func_args());}}if(!function_exists("vsprintf")){function vsprintf($format,$args=NULL){$args=array_merge(array($format),array_values((array)$args));return call_user_func_array("sprintf",$args);}}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;}$alias=array("G"=>"_GET","P"=>"_POST","C"=>"_COOKIE",);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;}}}}}}if(!function_exists("hypot")){function hypot($num1,$num2){return sqrt($num1*$num1+$num2*$num2);}}if(!function_exists("log1p")){function log1p($x){return(log(1+$x));}function expm1($x){return(exp($x)-1);}}if(!function_exists("sinh")){function sinh($f){return((exp($f)-exp(-$f))/2);}function cosh($f){return((exp($f)+exp(-$f))/2);}function tanh($f){return(sinh($f)/cosh($f));}}if(!function_exists("asinh")){function asinh($x){return(log($x+sqrt($x*$x+1)));}function acosh($x){return(log($x+sqrt($x*$x-1)));}function atanh($x){return(log1p(2*$x/(1-$x))/2);}}?>
<


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.9");
#
#  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
|







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


44
45
46
47
48
49
50
51
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);







############################################################################
#                                                                          #
#  client part                                                             #







>
>
|







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
374
375
376
377
378
379
380
381
382
383
384
         $_SERVER[strtoupper(strtr("HTTP_$i", "-", "_"))] = $v;
      }
   }

   #-- check and get call
   $allowed = array(
      "REQUEST_METHOD" => array("POST", "PUT", "CALL"),
      "HTTP_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");
      }







|


|







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
436
437
438
439
440
441
442
443

#-- 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["HTTP_CONTENT_TYPE"].$_SERVER["HTTP_CONTENT_CHARSET"]);
   }

   #-- decode XML string into PHP arrays
   $call = xml2array($xml_request, 1);
   $xml_request = NULL;

   $call = $call["methodCall,0"];







|







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
612
613
614
615
616
617
618
619

   #-- 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["HTTP_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.'" ');
   }







|







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

20

21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
   function base64_decode_safe($b64) {
      return base64_decode(strtr($str, "-_", "+/"));
   }


   #-- base16
   function base16_encode($str) {

      return chunk_split(bin2hex($str));

   }
   function base16_decode($b16) {
      $b16 = preg_replace("/\s+/", '', $b16);
      $b16 = pack("H*", $b16);
      return($b16[0]);
   }


   #-- base32
   function base32_encode() {
      
      # strtoupper()
      # "A-Z,0-7,="
   }

}
?>







>
|
>




|












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
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
   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.
*/


#-- define if not there
if (!function_exists("gettext")) {


   #-- all-in-one combined implementation
   #   (in PHP only the first parameter is used)
   function gettext($msg, $msg2=NULL, $domain=NULL, $category=NULL, $plural=NULL, $config=NULL) {
      global $_GETTEXT;
      
      #-- params
      if (!isset($domain)) {
         $domain = $_GETTEXT["%domain"];
      }
      elseif (empty($_GETTEXT[$domain])) {
         bindtextdomain($domain);  // load from system dirs
      }
      #-- config
      if (isset($config)) {
         return false;
      }
      #-- plural array position (English)
      if (!isset($plural) || ($plural == 1)) {
         $pli = 0;
      }
      else {
         if (isset($msg2)) {
            $msg = $msg2;
         }
         $pli = 1;
      }
      // $pli = ($plural==1) ?0 :1;


      #-- look up
      if ($trans = $_GETTEXT[$domain][$msg]) {

         if (is_array($trans)) {
            if (!isset($trans[$pli])) {
               $pli = 0;
            }
            $trans = $trans[$pli];
         }

         if (strlen($trans)) {
            $msg = $trans;
         }
      }




      #-- give out whatever we have
      return($msg);
   }


   #-- wrappers
   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);
   }


   #-- settings

   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";


      foreach (explode(",",$langs) as $d) {
         $d = trim($d);
         // $dir2[] = $d;
         $d = strtok($d, "@.-+=%:; ");
         if (strlen($d)) {
            $dir2[] = $d;
         }
         if (strpos($d, "_")) {
            $dir2[] = strtok($d, "_");
         }
      }
      
      #-- repeat
      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"))) {
           $data = fread($f, 1<<20);
           fclose($f);
           #-- check file magic
           if ($data) {
              extract(unpack("L1magic/L1version/L1count/L1o_msg/L1o_trn", substr($data, 0, 20)));
              if ((dechex($magic) == "950412de") && ($version == 0)) {
                 for ($n=0; $n<$count; $n++) {
                    #-- id
                    $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
                    $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];
                    }
                 }
              }
           }
           break;
        }

        #-- read from text file (not fully correct, and redundant because
        #   the original gettext/libintl doesn't support this at all)
        elseif (file_exists($f = "$base_fn.po") && ($f = fopen($f, "r"))) {
           do {
              $line = trim(fgets($f));
              if (isset($msgid) && isset($msgstr) && (empty($line) || ($line[0]=="m"))) {
                 foreach ($msgstr as $v) {
                    $_GETTEXT[$domain][$msgid[0]] = $v;
                 }
                 if ($msgid[1]) {
                    $_GETTEXT[$domain][$msgid[1]] = &$_GETTEXT[$domain][$msgid[0]];
                 }
                 unset($msgid);
                 unset($msgstr);
              }
              $space = strpos($line, " ");
              if ($line[0] == "#") {
                 continue;
              }
              elseif (strncmp($line, "msgid", 5)==0) {
                 $msgid[] = trim(substr($line, $space+1), '"');
              }
              elseif (strncmp($line, "msgstr", 6)==0) {
                 $msgstr[] = trim(substr($line, $space+1), '"');
              }
              elseif ($line[0] == '"') {
                 $line = trim($line, '"');
                 if (isset($msggstr)) {
                    $msgstr[count($msgstr)] .= $line;
                 }
                 else {
                    $msgid[count($msgid)] .= $line;
                 }
              }
           }
           while (!feof($f));
           if ($msgid && $msgstr) { $_GETTEXT[$domain][$msgid[0]] = $msgstr[0]; }
           
           fclose($f);
           break;
        }
        
      }//foreach

      #-- set as default textdomain
      if (empty($_GETTEXT["%domain"]) && (count($_GETTEXT[$domain]) > 1)) {
         $_GETTEXT["%domain"] = $domain;
      }
      return($domain);
   }






































































































   #-- ignored setting (no idea what it really should do)
   function bind_textdomain_codeset($domain, $codeset) {
      global $_GETTEXT;
      $_GETTEXT[$domain]["%codeset"] = $codeset;
      return($domain);
   }


}


#-- define separately
if (!function_exists("_")) {
   function _($str) {
      return gettext($str);
   }
}



?>







|


>

|
|

|
|






<
<
<
|
|










>

|

>


|



>




>
>
>





>
|
















>
|
>








>













>
>












|
|
|
|

|
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
<
<
<
<
<
<
|
|

|
<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
<
|
|
|



|
|



>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







>




|









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
3
4
5
<?php
/*
   Ok, that's a joke.
*/
?>


|


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
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["HTTP_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");








|
|







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
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) {







|







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.

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
<?php
/*
   Emulates a bit of PHP5 convinience for PHP4 interpreter versions. Of
   course no Interfaces are there, but most stuff can be done with plain
   class definitions anyhow. There is a collection of spl class defines
   in the PHP source distributions ext/spl/internal/ dir to eventually
   get used together with this part (not included here because of its PHP
   license).
   
   THIS IS NOT TESTED FOR CORRECTNESS, because very few people have any
   interest in using this anyhow (so me). Moreover this part is ALMOST
   ABANDONED as I have more important projects to waste time on.
*/


#-- be funny
class WikiWord {
}
#-- general class here
class GeneralIterator extends WikiWord {
   var $list = array();
}


#-- an interface
class CanYieldIterator extends WikiWord {
   function &getIterator() {
      $i = new GeneralIterator();
      return($i);
   }
}


#-- wrapper around arrays
class ArrayIterator extends GeneralIterator {
   function valid() {
      $r = (next($this->list) !== false);
      prev($this->list);
      return($r);
   }
   function key() {
      return(key($this->list));
   }
   function current() {
      return(current($this->list));
   }
   function next() {
      next($this->list);
   }
   function rewind() {
      reset($this->list);
   }
}


#-- complicated and new-syntax-inventing wrapper around basic array features
class ArrayObject extends CanYieldIterator {
   function ArrayObject($arg) {
      if (is_array($arg)) {
         $this->array = $arg;
      }
      elseif (is_a($arg, "ArrayObject")) {
         $this->array = $arg->array;
      }
      else {
         $this->array = (array)$arg;
      }
   }
   function &getIterator() {
      $ai = &new ArrayIterator();
      $ai->$list = $this->array;
      return($ai);
   }
   function count() {    // this whole class must be some kind of joke
      return(count($this->array));
   }
   function append($value) {
      $this->array[] = $value;
   }
   function offsetExists($key) {
      return(isset($this->array[$key]));
   }
   function offsetGet($key) {
      return($this->array[$key]);
   }
   function offsetSet($key, $value) {
      $this->array[$key] = $value;
   }
   function offsetUnset($key) {
      unset($this->array[$key]);
   }
   #+ seek()
   #+ ...()
}


?>
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


































































































































































































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
6

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?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; native functions will be used where 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 script 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





|
>








|
|







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

112

113
114
115
116
117
118
119
120

121
122
123
124
125
126
127
128
129
      else {
         return($data);
      }
   }
}



#-- output buffering functions swallow up any http header()

if (!function_exists("ob_get_headers")) {
   function ob_get_headers() {
      return (array)NULL;
   }
}


#-- uh, ooops, now hopefully this doesn't screw scripts which

#   already implemented this themselves
#   (this implementation doesn't fix bogus numeric entities)
if (!function_exists("xmlentities")) {
   function xmlentities($str) {
      return strtr($str, array(
        "&#"=>"&#", "&"=>"&amp;", "'"=>"&apos;",
        "<"=>"&lt;", ">"=>"&gt;", "\""=>"&quot;", 
      ));
   }







>
|
>







|
>
|
|







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(
        "&#"=>"&#", "&"=>"&amp;", "'"=>"&apos;",
        "<"=>"&lt;", ">"=>"&gt;", "\""=>"&quot;", 
      ));
   }
141
142
143
144
145
146
147

148
149
150
151
152

153


154
155
156



157




158
159
160
161



162
163
164
165

166
167



168
169
170
171
172

173
174


175
176
177
178
179
180


181
182
183
184
185
186
187


188
189
190
191
192
193



194

195
196
197
198


199
200
201
202
203
204
205
206


207
208
209
210
211


212






213
214
215
216
217
218
219

220
221
222
223
224
225

226
227
228
229

230
231
232
233
234
235
236

237
238
239
240


241
242
243
244


245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264

265
266
267
268
269
270
271



272
273
274
275
276
277
278
279

280
281
282


283
284
285


286
287
288
289
290
291
292
293
294
295
296
297


298
299


300



301
302

303



304
305

306
307
308


309
310
311
312
313
314
315



316



317
318
319
320
321
322

323
324


325
326
327
328


329


330
331
332


333
334
335
336


337
338
339
340
341


342
343
344

345

346
347
348
349
350

351
352


353
354


355
356
357
358


359
360
361
362
363
364


365
366


367
368
369
370


371
372
373
374

375

376
377

378
379
380
381
382
383

384
385


386
387
388
389
390
391


392
393
394
395
396
397


398
399
400
401
402
403
404
405
406

407
408
409
410
411
412
413
414
415


416
417
418


419
420
421


422

423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441


442
443
444


445


446
447
448
449



450




451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505

506
507


508
509
510


511
512
513
514
515
516
517
518
519
520
521
522
523
524
525

526
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
# --
# proc_nice
# dns_get_record
# date_sunrise - undoc.
# date_sunset - undoc.



#-- end of line
if (!defined("PHP_EOL")) {
   define("PHP_EOL", ( (DIRECTORY_SEPARATOR == "\\") ?"\015\012" :(strncmp(PHP_OS,"D",1)?"\012":"\015") )  ); #"
}


#-- ci string search functions


if (!function_exists("stripos")) {
   #-- find position of first occourence of a case-insensitive string
   function stripos($haystack, $needle, $offset=NULL) {



      return strpos(strtolower($haystack), strtolower($needle), $offset);




   }
}

#-- more complicated, because $offset param not supported in basic form



if (!function_exists("strripos")) {
   #-- ... from end of string
   function strripos($haystack, $needle, $offset=NULL) {
      if (isset($offset)) {

         $haystack = strtolower($haystack);
         $needle = strtolower($needle);



         if ($offset < 0) {
            $offset = strlen($haystack) + $offset;
         }
         do {
            $l = $new;

            $new = strpos($haystack, $needle, $l);
         }


         while (($new !== false) && ($new < $offset));
         return($l);
      }
      else {
         return strrpos(strtolower($haystack), strtolower($needle));
      }


   }
}


#-- case-insensitive version of str_replace
if (!function_exists("str_ireplace")) {
   function str_ireplace($search, $replace, $subject, $count=NULL) {


      if (is_array($search)) {
         $replace = array_values($replace);
         foreach (array_values($search) as $i=>$srch) {
            $subject = str_ireplace($srch, $replace[$i], $subject);
         }
      }



      else {

         $search = "\007" . preg_quote($search) . "\007i";
         $replace = strtr($replace, array('$'=>'\\$', "\\"=>"\\\\"));
         $subject = preg_replace($search, $replace, $subject);
      }


      return($subject);
   }
}


#-- performs a http HEAD request
if (!function_exists("get_headers")) {
   function get_headers($url, $parse=0) {


      $c = parse_url($url);
      extract($c);
      if (!isset($port)) { 
         $port = 80;
      }


      if ($f = fsockopen($host, $port, $errno, $errstr, $timeout=5)) {






         fwrite($f, "HEAD $path HTTP/1.1\015\012"
                  . "Host: $host\015\012"
                  . "Connection: close\015\012"
                  . "Accept: */*\015\012"
                  . "User-Agent: ".trim(ini_get("user_agent"))."\015\012"
                  . "\015\012");
         socket_set_blocking($f, true);

         $ls = array();
         while (!feof($f)) {
            $line = trim(fgets($f, 1<<16));
            if (!strlen($line)) {
               break;
            }

            elseif ($parse) {
               if ($l = strpos($line, ":")) {
                  $name = substr($line, 0, $l);
                  $value = trim(substr($line, $l + 1));

                  if (isset($ls[$name])) {
                     $ls[$name] .= ", $value";
                  }
                  else {
                     $ls[$name] = $value;
                  }
               }

               else {
                  $ls[] = $line;
               }
            }


            else {
               $ls[] = $line;
            }
         }


         fclose($f);
         return($ls);
      }
      else {
         return(false);
      }
   }
}


#-- stub
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

if (!function_exists("fprintf")) {
   function fprintf() {
      $args = func_get_args();
      $stream = array_shift($args);
      return fwrite($stream, call_user_func_array("sprintf", $args));
   }
}



if (!function_exists("vfprintf")) {
   function vfprintf($stream, $format, $args=NULL) {
      return fwrite($stream, vsprintf($format, $args));
   }
}


#-- splits a string in even sized chunks, returns an array

if (!function_exists("str_split")) {
   function str_split($str, $chunk=1) {
      $r = array();


      if ($chunk < 1) {
         $r[] = $str;
      }


      else {
         $len = strlen($str);
         for ($n=0; $n<$len; $n+=$chunk) {
            $r[] = substr($str, $n, $chunk);
         }
      }
      return($r);
   }
}


#-- mmmh?


if (!function_exists("http_build_query")) {
   function http_build_query($data, $prefix="", $fpfix="", $l=0) {


      $s = "";



      foreach ($data as $in=>$val) {
         $s_in = $in;

         if ($fpfix) {



            $s_in = $l ? "$fpfix"."[$s_in]" : "$fpfix$s_in";
         }

         elseif (is_int($s_in) && $prefix) {
            $s_in = "$prefix$s_in";
         }


         if (is_array($val)) {
            $s .= http_build_query($val, "", $s_in, $l+1);
         }
         else {
            $s .= "&$s_in=" . urlencode($val);
         }
      }



      if (!$fpfix) { $s = substr($s, 1); }



      return($s);
   }
}


#-- transform into 3to4 uuencode (bare encoding, not the uu file format)

if (!function_exists("convert_uuencode")) {
   function convert_uuencode($data) {


      $out = "";
      $line = "";
      $len = strlen($data);
#      $data .= "\252\252\252";   // PHP and uuencode(1) use some special garbage??, looks like "\000"* and "`\n`" simply appended


      for ($n=0; $n<$len; ) {


         $x = (ord($data[$n++]) << 16)
            + (ord($data[$n++]) <<  8)
            + (ord($data[$n++]) <<  0);


         $line .= chr( 32 + (($x >> 18) & 0x3f) )
                . chr( 32 + (($x >> 12) & 0x3f) )
                . chr( 32 + (($x >>  6) & 0x3f) )
                . chr( 32 + (($x >>  0) & 0x3f) );


         if (($n % 45) == 0) {
            $out .= chr(32+45) . "$line\n";
            $line = "";
         }
      }


      if ($trail = ($len % 45)) {
         $out .= chr(32 + $trail) . "$line\n";
      }

      $out = strtr("$out \n", " ", "`");   // uuencode(5) doesn't tell so, but spaces are replaced with the ` char in most implementations

      return($out);
   }
}

#-- decodes again what the above mangled

if (!function_exists("convert_uudecode")) {
   function convert_uudecode($data) {


      $out = "";
      $data = strtr($data, "`", " ");


      foreach(explode("\n", ltrim($data)) as $line) {
         if (!strlen($line)) {
            break;
         }


         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);


         $add = "";
         for ($n=0; strlen($add)<$num; ) {


            $x = ((ord($line[$n++]) - 32) << 18)     // add &0x3f
               + ((ord($line[$n++]) - 32) << 12)
               + ((ord($line[$n++]) - 32) <<  6)
               + ((ord($line[$n++]) - 32) <<  0);


            $add .= chr( ($x >> 16) & 0xff )
                  . chr( ($x >>  8) & 0xff )
                  . chr( ($x >>  0) & 0xff );
         }

         $out .= substr($add, 0, $num);   // cut any trailing garbage (last two decoded chars may be wrong)

         $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) {


      if (strpos($dirname, "file://") === 0) {
         $dirname = substr($dirname, 7);
         if (strpos($dirname, "localh") === 0) {
            $dirname = substr($dirname, strpos($dirname, "/"));
         }
      }


      if ($dh = opendir($dirname)) {
         $ls = array();
         while ($fn = readdir($dh)) {
            $ls[] = $fn;
         }
         closedir($dh);


         if ($desc) {
            rsort($ls);
         }
         else {
            sort($ls);
         }
         return $ls;
      }
      else {

         return false;
      }
   }
}


#-- like date(), but returns an integer for given one-letter format parameter
if (!function_exists("idate")) {
   function idate($formatchar, $timestamp=NULL) {


      if (strlen($formatchar) != 1) {
         return false;
      }


      if (!isset($timestamp)) {
         $timestamp = time();
      }


      return((int)(date($formatchar, $timestamp)));

   }
}



#-- 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) {


      $cn = strlen($char_list);
      $min = strlen($haystack);
      for ($n=0; $n<$cn; $n++) {


         $l = strpos($haystack, $char_list{$n});


         if (($l !== false) && ($l < $min)) {
            $min = $l;
         }
      }



      return($min ? substr($haystack, $min) : $haystack);




   }
}



#-- logo image activation URL query strings
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();
   }
}


#-- calls PHP interpreter itself (really only works with 4.3 onwards)
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 blindly 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)
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);
   }
}


#-- 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 (should have same number of entries)

if (!function_exists("array_combine")) {
   function array_combine($keys, $values) {


      $keys = array_values($keys);
      $values = array_values($values);
      $r = array();


      foreach ($values as $i=>$val) {
         if ($key = $keys[$i]) {
            $r[$key] = $val;
         }
         else {
            $r[] = $val;
         }
      }
      return($r);
   }
}


#-- apply userfunction to each array element (descending recursively)
#   use it like:  array_walk_recursive($_POST, "stripslashes");

if (!function_exists("array_walk_recursive")) {
   function array_walk_recursive(&$input, $callback, $userdata=NULL) {

      #-- walk
      foreach ($input as $i=>$value) {

         #-- recurse
         if (is_array($value)) {
            array_walk_recursive($input[$i], $callback, @$userdata);
         }
         #-- scalar

         else {
            call_user_func_array($callback, array(&$input[$i], &$i, @$userdata) );
         }
      }

      return NULL; //?
   }
}


#-- 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);







>
|




>
|
>
>

<

>
>
>
|
>
>
>
>



|
>
>
>

<

|
>
|
|
>
>
>
|
|
|
|
<
>
|
|
>
>
|
<

<
<
|
>
>







>
>






>
>
>

>
|
<


>
>








>
>





>
>
|
>
>
>
>
>
>
|
|
|
|
|
|
|
>
|
<
|
<
<
|
>
|
|
|
|
>
|
|
|
|
|
|
|
>
|
|
|
|
>
>
|
|
|
|
>
>
|
|
|
<
<
|
|
|
|
|
<








|
>

|





>
>
>







|
>



>
>



>
>











|
>
>

|
>
>

>
>
>
|
|
>
|
>
>
>
|

>
|
|

>
>
|
|

|
|


>
>
>
|
>
>
>





|
>


>
>




>
>

>
>



>
>




>
>

|



>
>



>
|
>




|
>


>
>


>
>


|

>
>






>
>


>
>
|
|


>
>




>
|
>
|

>





|
>


>
>






>
>



|


>
>








|
>
|
<







>
>



>
>



>
>
|
>



















>
>
|

|
>
>

>
>




>
>
>
|
>
>
>
>





|

|
<
<
|
<
|
|

|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|








|
>


>
>



>
>





|









>


<
|
|
>
|

|

|
>

|


>
|


















>







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

618





619
620
621
622
623
624

625
626
627
628
629
630
631
}



#-- 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();

      if ($args[2]) { $w = & $args[2]; }





      return getmxrr($host, $mx, $w);
   }
}


#-- setrawcookie() - but can this be emulated reliably?

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);
      }







>
>


>
>













>








>






>
|
>
>
>
>
>





|
>







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
651
652
653
654
655
656
657
658
659
660
661
662
663
664

665


666






















667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683


684



685
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
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
      }
   }
}


#-- 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);
   function file_put_contents($filename, $data, $flags=0, $resource=NULL) {
      if ($f = fopen($filename, ($flags&FILE_APPEND?"a":"w")."b", $flags&FILE_USE_INCLUDE_PATH)) {
         fwrite($f, $data);
         fclose($f);
         return(TRUE);
      }
   }
}


#-- 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

   # COUNT_NORMAL   seems unused


   # COUNT_RECURSIVE






















}







#------------------------------------------------------------------ 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) {


      if ($f = fopen($filename, "rb", $use_include_path)) {



         $content = fread($f, 1<<21);  # max 2MB
         fclose($f);
         return($content);
      }
   }
}



#-- shell-like filename matching
if (!function_exists("fnmatch")) {


   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


   function fnmatch($pattern, $str, $flags=0x0000) {
      static $cmp = array();

      $rxci = ($flags & FNM_CASEFOLD ?'i' :'');
      $rx = @$cmp["$pattern$flags"];
      if (($str[0] == ".") && ($flags & FNM_PERIOD)) {
         if ($pattern[0] != ".") { return(false); }
      }

      if (!$rx) {












         if (count($cmp) >= 10) { $cmp = array(); }






         $rx = preg_quote($pattern);
         $wild = (($flags & FNM_PATHNAME) ? "[^/]" : ".");
         $rx = strtr($rx, array(
            "\\*"=>"$wild*?", "\\?"=>"$wild", "\\["=>"[", "\\]"=>"]",
         ));

         $rx = "\007^$rx$\007$rxci";




         $cmp["$pattern$flags"] = $rx;
      }


      return(preg_match($rx, $str));
   }
}


#-- file search and name matching (with shell patterns)
if (!function_exists("glob")) {


   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


   function glob($pattern, $flags=0x0000) {
      $ls = array();
      $rxci = ($flags & GLOB_NOCASE) ? "i" : "";
#echo "\n=> glob($pattern)...\n";
      
      #-- transform glob pattern into regular expression

      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);







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>





<
<
<
<
<
<
<







>
|
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

















>
>
|
>
>
>
|
|
|
<





|

>
>






>
>

|
>
|
<
|
|
|
>
|
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>

<



>
|
>
>
>
>
|

>
>







>
>











>






>




















|







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
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
      if ($flags ^ GLOB_NOSORT) {
         sort($ls);
      }
#print_r($ls);
#echo "<=\n";
      return($ls);
   }
}


#-- 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...*/ ) {
      $whatsleftover = array();

      $in = func_get_args();
      $cmax = count($in);




      foreach ($in[0] as $i=>$v) {
         for ($c=1; $c<$cmax; $c++) {


            if (@$in[$c][$i] !== $v) {
               continue 2;
            }
         }

         $whatsleftover[$i] = $v;
      }
      return $whatsleftover;
   }
}


#-- the opposite of the above
if (!function_exists("array_diff_assoc")) {
   function array_diff_assoc( /*array, array, array...*/ ) {
      $diff = array();

      $in = func_get_args();



      foreach ($in[0] as $i=>$v) {
         for ($c=1; $c<count($in); $c++) {

            if (isset($in[$c][$i]) && ($in[$c][$i] == $v)) {
               continue 2;
            }
         }

         $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") {
      // 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, $format=0) {


      preg_match_all('/([\w](?:[-\'\w]?[\w]+)*)/', $string, $uu);
      if (!$format) {
         return(count($uu[1]));
      }

      elseif ($format==1) {
         return($uu[1]);
      }
      else {


         $r = array();
         $l = 0;
         foreach ($uu[1] as $word) {
            $l = strpos($string, $word, $l);
            $r[$l] = $word;
            $l += strlen($word);
         }
         return($r);
      }





   }
}


#-- creates a permutation of the given strings characters

if (!function_exists("str_shuffle")) {
   function str_shuffle($str) {
      $r = "";


      while (strlen($str)) {
         $n = strlen($str) - 1;
         if ($n) {
            $n = rand(0, $n);
         }


         $r .= $str[$n];
         $str = substr($str, 0, $n) . substr($str, $n + 1);
      }
      return($r);
   }
}









|













|
>


>
>
>
>
|
|
>
>
|



>










|
>

>
>
>


>




>










|








|
>
>

<
<
|
>
|


|
>
>





|



>
>
>
>
>





>



>
>



|

>
>
|







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
943
944
945
946
947
948



949
950
951


952
953
954
955
956
957
958
      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());
}



if (!defined("PHP_PREFIX") && isset($_ENV["_"])) { 
   define("PHP_PREFIX", substr($_ENV["_"], strpos($_ENV["_"], "/bin/")));
}






#------------------------------------------------------------------ 4.2 ---
# almost complete!?








|
|




>
>
>

|

>
>







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
977

978

979
980
981


982
983
984
985
986
987
988
989
990


991


992



993
994
995
996
997
998
999
1000
1001
1002


1003
1004


1005


1006
1007
1008
1009


1010
1011
1012
1013
1014
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
      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) {
         unset($array[$i]);

         if (is_string($i)) {

            $i = ($case==CASE_LOWER) ? strtolower($i) : strtoupper($i);
         }
         $array[$i] = $v;


      }
      return($array);
   }
}


#-- hey, why not
if (!function_exists("array_fill")) {
   function array_fill($start_index, $num, $value) {


      $r = array();


      for ($i=$start_index,$end=$num+$i; $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) {


      $r = array();
      $n = -1;


      foreach ($input as $i=>$v) {


         if (($n < 0) || (count($r[$n]) == $size)) {
            $n++;
            $r[$n] = array();
         }


         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) {
      if ($f = fopen($filename, "rb")) {
         $data = fread($f, 1<<22);  // can be too large for mem
         fclose($f);
         $r = md5($data);
         $data = NULL;


         if ($raw_output) {
            $r = pack("H*", $r);
         }
         return $r;
      }
   }
}


#-- object type checking
if (!function_exists("is_a")) {
   function is_a($obj, $classname) {



      return ((strtolower(get_class($obj))==strtolower($classname))


          or is_subclass_of($obj, $classname));
   }
}


#-- floating point modulo
if (!function_exists("fmod")) {
   function fmod($x, $y) {







>
>


>
>

>
>

<
>

>

<
|
>
>






|


>
>

>
>
|
>
>
>










>
>

|
>
>

>
>




>
>















|
|
|
|
|
>
>
|
|
|
|
<







>
>
>
|
>
>
|







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
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
      return (float)$str;
   }
}


#-- floats
if (!function_exists("is_infinite")) {


   define("NAN", "NAN");
   define("INF", "INF");


   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="") {


      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 .= "}";
      }


      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 .= ";";
      }


      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);
      }







>
>

|
>
>



















>
>







>
>












>
>









>







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
1152
1153
1154
1155
1156
1157
1158
1159
# version_compare
#
# See also "ext/math41.php" for some more (rarely used mathematical funcs).




#-- a silly alias (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();
   }







|







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
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
   }
}


#-- 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;
      }
      $alias = array(
         "G" => "_GET",
         "P" => "_POST",
         "C" => "_COOKIE",
   //      "S" => "_SERVER",
   //      "E" => "_ENV",
      );
      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
   }
}







>
>
>
>
>
>
>
>
>
>





|
|
<
<
<
<
<




|







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
*/