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

⌈⌋ ⎇ branch:  upgrade.php


Check-in [02e65f8aad]

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

Overview
Comment:upgradephp-16
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 02e65f8aad653b484395b5b20eaacea2370baf57
User & Date: mario 2010-06-22 17:03:43
Context
2010-06-22
17:21
builds a test-version of upgrade.php, having all functions prefixed with "up_" check-in: 94a0e3704d user: mario tags: trunk
17:03
upgradephp-16 check-in: 02e65f8aad user: mario tags: trunk
17:03
upgradephp-15 check-in: 51e3884900 user: mario tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to doc/README.

1
2
3
4
5
6

7
8
9
10
11
12

13
14
15
16
17
18
19
20
21

PHP downwards compatibility functions
-------------------------------------
The "upgrade.php" package implements features and functions from
later PHP versions in pure PHP script and dynamically defines them
at runtime. The emulated functions use exactly the same names as

the originals, and cannot perturb if the native functions exist.

So this is really a drop-in replacement, and allows you to use all
PHP features regardless of the current PHP interpreter. If you just
include() this single script you are freed from wasting time with
backward compatibility problems. Stop omitting certain more useful

PHP functions or retyping workarounds. Your applications remain
"PHP 4.1+ COMPATIBLE" while you in fact use PHP5.2 features.


this is useful:

- for open source distributions
- if your own providers PHP version is immemorial
- you want to test new functions, but not install a new PHP ver




|
|
>
|

|
|
|
|
>
|
|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

PHP downwards compatibility functions
-------------------------------------
The "upgrade.php" package implements features and functions from
newer PHP versions. It defines them as pure PHP code. Functions
get defined dynamically defines, at runtime. All emulated functions
use names identical to the original implementation. But it doesn't
perturb if the native functions exist.

So this is really a drop-in replacement. It allows you to use all
PHP features regardless of the current PHP interpreter. You just
have to include() this single script to remove any backward
compatibility woes.
This allows relying on the newer, more powerful PHP functions. The
use and retyping of workarounds gets superfluous. Your application
remains "PHP 4.1+ COMPATIBLE" while actually using PHP5.2 features.


this is useful:

- for open source distributions
- if your own providers PHP version is immemorial
- you want to test new functions, but not install a new PHP ver
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
this README), because they probably make little sense distributed
alongside elsewhere.

It is also safe to extract a few function bodies/definitions out of
upgrade.php to make a shorter version (load only the needed funcs).
But you should keep the "if (function_exists(...))" wrapper code
preferrably.
PHP_Compat however might make a better source, if you seriously need
just one or two functions.


Omissions
---------
A few PHP features are specifically NOT implemented, and so still
had to be taken care of in your scripts:







|







271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
this README), because they probably make little sense distributed
alongside elsewhere.

It is also safe to extract a few function bodies/definitions out of
upgrade.php to make a shorter version (load only the needed funcs).
But you should keep the "if (function_exists(...))" wrapper code
preferrably.
PHP_Compat however might make a better source, if you really need
just one or two functions.


Omissions
---------
A few PHP features are specifically NOT implemented, and so still
had to be taken care of in your scripts:
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306


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/bcmath" provides the mathematical functions with arbitrary
  precision on Unix systems, but emulation also works on top of







|







294
295
296
297
298
299
300
301
302
303
304
305
306
307
308


ext/
----
The ext/ subdirectory in here provides a few more or less useful
emulations for various PHP extensions or function groups.

· "ext/php40array" 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/bcmath" provides the mathematical functions with arbitrary
  precision on Unix systems, but emulation also works on top of
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341



342
343
344
345
346
347
348

Other snippets in ext/ are probably incomplete or just TODO stubs.


doc/devtools/
-------------
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:







|
|
|






>
>
>







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

Other snippets in ext/ are probably incomplete or just TODO stubs.


doc/devtools/
-------------
Please run the "updoc" script once to update your PHP manual, if you
are planning to use the upgrade.php script. It adds notes to version
compatibility strings on each page, when an upgradephp equivalent
exists.

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


The other cmdline scripts are used for developing upgrade.php:

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

Other Notes
-----------
· This script doesn't reside in any CVS/SVN reposititory currently
  because it is considered a too minor and small project.

· The project homepage is <http://upgradephp.berlios.de/> but see
  also <http://freshmeat.net/p/upgradephp> for update notifications.




License
-------
Almost all 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.
It has absolutely no impact on the rest of YOUR project; you are free
to include it as if you had written it yourself.

You could prepend the license preamble (GNU GPL, LGPL, BSD, MPL, MSFT
EULA, PHP, CDDL, Artistic, ...) of your choice if you want to.

Exceptions are the doc/tests* and doc/runtest scripts. Those are under
the PHP license, taken from PEAR, PECL or PHP.

The "ext/pdo.php" class is from Andrea Giammarchi and under the PHP
License as well. Also check out http://xpdo.org/ - slightly related.


Author
------
The current maintainer can be contacted under <milky*users·sf·net>

Please drop me a line, regarding omissions, bugs, contributing a few
bytes...



ChangeLog
---------






v15
  - moved to phpDoc comment style,
    but not all emulated functions carry @param lists
  - tarball directories restructured
  - ext/filter ...
  - json_decode now decodes \uXXXX unicode references
  - include the PDO emulation classes of Andrea Giammarchi (under PHP License)







|
>


















|














>
>
>
>
>







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

Other Notes
-----------
· This script doesn't reside in any CVS/SVN reposititory currently
  because it is considered a too minor and small project.

· The project homepage is <http://upgradephp.berlios.de/> but see
  also <http://freshmeat.net/projects/upgradephp> for any update
  notifications.



License
-------
Almost all 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.
It has absolutely no impact on the rest of YOUR project; you are free
to include it as if you had written it yourself.

You could prepend the license preamble (GNU GPL, LGPL, BSD, MPL, MSFT
EULA, PHP, CDDL, Artistic, ...) of your choice if you want to.

Exceptions are the doc/tests* and doc/runtest scripts. Those are under
the PHP license, taken from PEAR, PECL or PHP.

The "ext/pdo.php" class is from Andrea Giammarchi and under the PHP
License as well. Also check out http://xpdo.org/ - the origin.


Author
------
The current maintainer can be contacted under <milky*users·sf·net>

Please drop me a line, regarding omissions, bugs, contributing a few
bytes...



ChangeLog
---------

v16
  - json_decode() array-conversion fix by Gerhard (tinned-software.net)
  - object-oriented input $_REQUEST filter wrapper in contrib/
  - some old code moved to contrib/archive/

v15
  - moved to phpDoc comment style,
    but not all emulated functions carry @param lists
  - tarball directories restructured
  - ext/filter ...
  - json_decode now decodes \uXXXX unicode references
  - include the PDO emulation classes of Andrea Giammarchi (under PHP License)

Changes to doc/devtools/listemu.

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
#!/usr/local/bin/php -qC
<?php
/*
   Prints the list of emulated functions.
*/

#-- basedir
$dir = realpath(dirname(__FILE__) . "/../");

#-- grep for function definitions
$text = "";
$text .= implode("", file("$dir/upgrade.php"));
$text .= implode("", file("$dir/ext/array.php"));
$text .= implode("", file("$dir/ext/bcmath.php"));
$text .= implode("", file("$dir/ext/gettext.php"));
$text .= implode("", file("$dir/ext/mime.php"));
$text .= implode("", file("$dir/ext/old.php"));
$text .= implode("", file("$dir/ext/posix.php"));
$text .= implode("", file("$dir/ext/ctype.php"));
$text .= implode("", file("$dir/ext/odbc.php"));
if (preg_match_all("/function[ ]+([_\w\d]+)\s*\(/", $text, $uu)) {
   $list = array_unique($uu[1]);
}

#-- print
echo "Following functions can be emulated currently:\n";
foreach ($list as $func) {
   echo "· $func\n";
}

?>












|






|











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
#!/usr/local/bin/php -qC
<?php
/*
   Prints the list of emulated functions.
*/

#-- basedir
$dir = realpath(dirname(__FILE__) . "/../");

#-- grep for function definitions
$text = "";
$text .= implode("", file("$dir/upgrade.php"));
$text .= implode("", file("$dir/ext/php40array.php"));
$text .= implode("", file("$dir/ext/bcmath.php"));
$text .= implode("", file("$dir/ext/gettext.php"));
$text .= implode("", file("$dir/ext/mime.php"));
$text .= implode("", file("$dir/ext/old.php"));
$text .= implode("", file("$dir/ext/posix.php"));
$text .= implode("", file("$dir/ext/ctype.php"));
$text .= implode("", file("$dir/ext/unfinished/odbc.php"));
if (preg_match_all("/function[ ]+([_\w\d]+)\s*\(/", $text, $uu)) {
   $list = array_unique($uu[1]);
}

#-- print
echo "Following functions can be emulated currently:\n";
foreach ($list as $func) {
   echo "· $func\n";
}

?>

Changes to doc/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.











|
|
|
|
|




|
|







|













|
>







|
>








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

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. You
then have the family of gettext functions always available - wether
compiled 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 the emulated version have not been tested
*extensively*.

 - 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 mixed together).
   [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,
                                 but deemed senseful for PHP)

 - 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 (= not tested with a
       real-world plural .po/.mo translation package)

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



Deleted ext/array.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
<?php
/**
 *
 *  Extended PHP array functions - _diff and _intersect() for associative
 *  arrays and/or with callback functions (for keys and/or values). These
 *  are too rarely used and exotic to be part of the core "upgrade.php"
 *  script.
 *  
 *  NOTHING IN HERE WAS SERIOUSLY TESTED. Please grab the definitions from
 *  PEAR::PHP_Compat if you want reliable and tested versions.
 *
 *
 *  @group ARRAY_FUNCS_4_0
 *  @since 4.0
 *  @untested
 *
 */


#-- diff associative arrays with two user callbacks
#   (if this looks complicated to you, don't even try to look at the manual)
if (!function_exists("array_udiff_uassoc")) {
   function array_udiff_uassoc() {
      $in = func_get_args();
      $key_cb = array_pop($in);
      $val_cb = array_pop($in);
      $arr1 = array_shift($in);
      $r = array();
      
      foreach ($arr1 as $i=>$v) {
         #-- in each array, compare against each key/value pair
         foreach (array_keys($in) as $c) {
            foreach ($in[$c] as $i2=>$v2) {
               
               $key_cmp = call_user_func_array($key_cb, array($i, $i2));
               if ($key_cmp == 0) {

                  #-- ok, in this case we must compare the data as well
                  $val_cmp = call_user_func_array($val_cb, array($v, $v2));
                  if ($val_cmp == 0) {
                     continue 3;
                  }
               }
            }
         }

         #-- this combination isn't really found anywhere else
         $r[$i] = $v;
      }
      return($r);
   }
}


#-- same, but that keys now are compared normally (without callback)
if (!function_exists("array_udiff_assoc")) {
   function array_udiff_assoc() {
      $in = func_get_args();
      $val_cb = array_pop($in);
      $arr1 = array_shift($in);
      $r = array();
      
      #-- compare against each key/value pair in other arrays
      foreach ($arr1 as $i=>$v) {
         foreach (array_keys($in) as $c) {
            if (isset($in[$c][$i])) {
               #-- now compare data by callback
               $cmp = call_user_func_array($val_cb, array($v, $in[$c][$i]));
               if ($cmp == 0) {
                   continue 2;
               }
            }
         }
         #-- everything exists only in array1
         $r[$i] = $v;
      }
      return($r);
   }
}


#-- ....
if (!function_exists("array_diff_uassoc")) {
   function array_diff_uassoc() {
      $in = func_get_args();
      $key_cb = array_pop($in);
      $arr1 = array_shift($in);
      $num = count($in);
      $r = array();
      
      foreach ($arr1 as $i=>$v) {
         #-- in other arrays?
         for ($c=0; $c<$num; $c++) {
            foreach ($in[$c] as $i2=>$v2) {
               if ($v == $v2) {
                  $cmp = call_user_func_array($key_cb, array($i, $i2));
                  if ($cmp == 0) {
                     continue 3;
                  }
               }
            }
         }
         #-- exists only in array1
         $r[$i] = $v;
      }
      return($r);
   }
}


#-- diff array, keys ignored, callback for comparing values
if (!function_exists("array_udiff")) {
   function array_udiff() {
      $in = func_get_args();
      $val_cb = array_pop($in);
      $arr1 = array_shift($in);
      $num = count($in);
      $r = array();
      foreach ($arr1 as $i=>$v) {
         #-- check other arrays
         for ($c=0; $c<$num; $c++) {
            foreach ($in[$c] as $v2) {
               $cmp = call_user_func_array($val_cb, array($v, $v2));
               if ($cmp == 0) {
                  continue 3;
               }
            }
         }
         #-- exists only in array1
         $r[$i] = $v;
      }
      return($r);
   }
}












#-- same for intersections
if (!function_exists("array_uintersect_uassoc")) {
   function array_uintersect_uassoc() {
      $in = func_get_args();
      $key_cb = array_pop($in);
      $val_cb = array_pop($in);
      $all = array();
      $conc = count($in);
      foreach ($in[0] as $i=>$v) {
         #-- must exist in each array (at least once, callbacks may match fuzzy)
         for ($c=1; $c<$conc; $c++) {
            $ok = false;
            foreach ($in[$c] as $i2=>$v2) {
               $key_cmp = call_user_func_array($key_cb, array($i, $i2));
               $val_cmp = call_user_func_array($val_cb, array($v, $v2));
               if (($key_cmp == 0) && ($val_cmp == 0)) {
                  $ok = true;
                  break;
               }
            }
            if (!$ok) {
               continue 2;
            }
         }
         #-- exists in all arrays
         $all[$i] = $v;
      }
      return($all);
   }
}




#-- intersection again
if (!function_exists("array_uintersect_assoc")) {
   function array_uintersect_assoc() {
      $in = func_get_args();
      $val_cb = array_pop($in);
      $all = array();
      $conc = count($in);
      foreach ($in[0] as $i=>$v) {
         #-- test for that entry in any other array
         for ($c=1; $c<$conc; $c++) {
            if (isset($in[$c][$i])) {
               $cmp = call_user_func_array($val_cb, array($v, $in[$c][$i]));
               if ($cmp == 0) { continue; }
            }
            #-- failed
            continue 2;
         }
         #-- exists in all arrays
         # (but for fuzzy matching: only the first entry will be returned here)
         $all[$i] = $v;
      }
      return($all);
   }
}





#-- array intersection, no keys compared, but callback for values
if (!function_exists("array_uintersect")) {
   function array_uintersect() {
      $in = func_get_args();
      $val_cb = array_pop($in);
      $arr1 = array_shift($in);
      $num = count($in);
      $r = array();

      foreach ($arr1 as $i=>$v) {
         #-- must have equivalent value in all other arrays
         for ($c=0; $c<$num; $c++) {
            foreach ($in[$c] as $i2=>$v2) {
               $cmp = call_user_func_array($val_cb, array($v, $v2));
               if ($cmp == 0) {
                  continue 2; //found
               }
            }
            continue 2; //failed
         }
         #-- everywhere
         $r[$i] = $v;
      }
      return($r);
   }
}




#-- diff array, keys ignored, callback for comparing values
if (!function_exists("array_intersect_uassoc")) {
   function array_intersect_uassoc() {
      $args = func_get_args();
      $key_cb = array_pop($args);
      $array1 = array_shift($args);
      $num = count($args);
      $all = array();
      foreach ($array1 as $i=>$v) {
         #-- look through other arrays
         for ($c=0; $c<$num; $c++) {
            $ok = 0;
            foreach ($args[$c] as $i2=>$v2) {
               $cmp = call_user_func_array($key_cb, array($i, $i2));
               if (($cmp == 0) && ($v == $v2)) {
                  $ok = 1;
                  continue 2;
               }
            }
            if (!$ok) { 
               continue 2;
            }
         }
         #-- found in all arrays
         if ($ok) {
            $diff[$i] = $v;
         }
      }
      return($diff);
   }
}


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


































































































































































































































































































































































































































































































































































Added ext/contrib/archive/bcmath.old.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
<?php
/**
 * These two alternate bcmath implementations don't emulate arbitrary
 * precision at all. And therefore have been removed from bcmath.php.
 *
 */


#-- GMP
if (!function_exists("bcadd") && function_exists("gmp_strval")) {
   function bcadd($a, $b) {
      return gmp_strval(gmp_add($a, $b));
   }
   function bcsub($a, $b) {
      return gmp_strval(gmp_sub($a, $b));
   }
   function bcmul($a, $b) {
      return gmp_strval(gmp_mul($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 bcpow($a, $b) {
      return gmp_strval(gmp_pow($a, $b));
   }
   function bcpowmod($x, $y, $mod) {
      return gmp_strval(gmp_powm($x, $y, $mod));
   }
   function bcsqrt($x) {
      return gmp_strval(gmp_sqrt($x));
   }
   function bccomp($a, $b) {
      return gmp_cmp($a, $b);
   }
   function bcscale($scale="IGNORED") {
      trigger_error("bcscale(): ignored", E_USER_ERROR);
   }
}//gmp emulation



#-- bigint
// @dl("php_big_int".PHP_SHLIB_SUFFIX))
if (!function_exists("bcadd") && function_exists("bi_serialize")) {
   function bcadd($a, $b) {
      return bi_to_str(bi_add($a, $b));
   }
   function bcsub($a, $b) {
      return bi_to_str(bi_sub($a, $b));
   }
   function bcmul($a, $b) {
      return bi_to_str(bi_mul($a, $b));
   }
   function bcdiv($a, $b) {
      return bi_to_str(bi_div($a, $b));
   }
   function bcmod($a, $b) {
      return bi_to_str(bi_mod($a, $b));
   }
   function bcpow($a, $b) {
      return bi_to_str(bi_pow($a, $b));
   }
   function bcpowmod($a, $b, $c) {
      return bi_to_str(bi_powmod($a, $b, $c));
   }
   function bcsqrt($a) {
      return bi_to_str(bi_sqrt($a));
   }
   function bccomp($a, $b) {
      return bi_cmp($a, $b);
   }
   function bcscale($scale="IGNORED") {
      trigger_error("bcscale(): ignored", E_USER_ERROR);
   }
}


?>

Added ext/contrib/archive/pdo-2006-01-29.tar.gz.

cannot compute difference between binary files

Added ext/contrib/archive/phprequest.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
<?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");
      $_POST = fread($f, 1<<22);
      fclose($f);
   }

   #-- uncompress and decode, if something found
   if ($_POST) {

      #-- strip known/supported encodings
      $enc = trim(strtok(strtolower($_SERVER["HTTP_CONTENT_ENCODING"]), ",;"));
      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) {
         $_POST = unserialize($_POST);
      }
      #-- merge
      if ($_POST) {
         $_REQUEST = array_merge($_REQUEST, $_POST);
      }

   }
}

?>

Added ext/contrib/archive/xmlrpc.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
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
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
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
965
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
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
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
<?php define("XMLRPC_VERSION", "0.3.10");
# 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
#
#  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
#     XXXXXXX   MMMMM MMMMM LLL      +++     RRR   RRR PPP   PPP CCC    CCC
#      XXXXX    MMMMMMMMMMM LLL  +++++++++++ RRR   RRR PPP   PPP CCC
#       XXX     MMM MMM MMM LLL  +++++++++++ RRRRRRRR  PPPPPPPP  CCC
#      XXXXX    MMM  M  MMM LLL      +++     RRRRRRR   PPPPPPP   CCC
#     XXXXXXX   MMM     MMM LLL      +++     RRR  RRR  PPP       CCC    CCC
#    XXXX XXXX  MMM     MMM LLLLLLL          RRR   RRR PPP       CCCCCCCCC
#   XXXX   XXXX MMM     MMM LLLLLLL          RRR   RRR PPP        CCCCCCC
#
#  This is Public Domain. (c) 2004 WhoEver wants to. [milky*erphesfurt·de]


#-- config
define("XMLRPC_PLUS", 0);        # use XML+RPC per default
define("XMLRPC_AUTO_TYPES", 0);  # detect base64+datetime strings and automatically generate the according xmlrpc object representations then
define("XMLRPC_AUTO_UTF8", 1);   # de/convert anything from and to UTF-8 automatically - if yourscripts use Latin1 natively, but the RPC server expects/sends UTF-8
define("XMLRPC_CHARSET", "utf-8");  # used in responses and requests
define("XMLRPC_AUTODISCOVERY", 0);  # "connections" automatically create methods
define("XMLRPC_FAST", 1);        # use PHPs XML-RPC extension where possible
define("XMLRPC_OO", 1);          # return XML-RPC/HTTP errors as objects
define("XMLRPC_DEBUG", 0);       # output error hints, write /tmp dumps - set this to 1, 2 or 3

#-- _server() settings
define("XMLRPC_LOG", "/tmp/xmlrpc.".@$_SERVER["SERVER_NAME"].".log");

#-- general data
#  (don't change the following, most are auto-configured values)
define("XMLRPC_UA", "xml+rpc/".XMLRPC_VERSION." (PHP/".PHP_VERSION."; ".PHP_OS.")");
define("XMLRPC_MIME_NEW", "application/rpc+xml");
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                                                             #
#                                                                          #
############################################################################


#-- Issue a request, call can take any number of arguments.
#     $result = xmlrpc("http://example.com/RPC2/", "method1", $arg1 ...);
#     $result = xmlrpc("xml+rpc://here.org/RPC3/", "ns.function", ...);
#   Results automatically have <datetime> values converted into Unix
#   timestamps and <base64> unpacked into strings.
#
function xmlrpc($server, $method=NULL /*, ... */) {
   if ($method) {
      $params = func_get_args();
      shift($params); shift($params);
      return
        xmlrpc_request($server, $method, $params);
   }
   else {
      return
        new xmlrpc_connection($server);
   }
}



#--  Generate and send request, decode response.
function xmlrpc_request($url, $method, $params=array(), $plus=XMLRPC_PLUS, $gzip=0) {
   global $xmlrpc_response_headers, $xmlrpc_error;
   
   #-- init whole lib for request (we are not-OO here)
   $xmlrpc_error = false;
   $xmlrpc_response_headers = array();
   
   #-- encapsulate req, transmit it
   $socket = xmlrpc_request_send($url, $method, $params, $plus, $gzip);
   if (!$socket) {
      return xmlrpc_error(-32768, "no connection", 0, "GLOBALVARS");
   }

   #-- wait for, read response
   $response = "";
   while (!feof($socket) && (strlen($DATA) <= 768<<10)) {
      $response .= fread($socket, 4<<10);
   }
   fclose($socket);
   if (XMLRPC_DEBUG >= 3) {
      echo "<code>$response</code>";
   }

   #-- decode answer and give results
   return xmlrpc_response_decode($response);
}


#-- an alias
function xmlrpc_call($url, $method, $params=array(), $plus=XMLRPC_PLUS, $gzip=0) {
   return xmlrpc_request($url, $method, $params, $plus, $gzip);
}



#-- marshall request parameters into array, hash, xml string
function xmlrpc_request_send($url, $method, &$params, $plus, $gzip, $blocking=true) {

   #-- get connection data
   $c = parse_url($url);
   ($host = $c["host"]);
   ($port = @$c["port"]) or ($port = 80);
   ($path = $c["path"]) or ($path = "/");
   if (strpos($c["scheme"], "+")) {
      $plus++;
   }
   if (strpos($c["scheme"], "gzip")) {
      $gzip++;
   }
   if (!$host) { return(NULL); }
   $inj = "";
   if ($str = $c["user"]) {
      if ($c["pass"]) { $str .= ":" . $c["pass"]; }
      $inj = "Authorization: Basic " . base64_encode($str) . "\n";
   }
   
   #-- mk request HTTP+XML block from params
   $request = xmlrpc_request_marshall($method, $params);
   $request = xmlrpc_request_http($request, $path, $host, $plus, $gzip, $inj);

   #-- connect, send request
   if ($socket = fsockopen($host, $port, $io_err, $io_err_s, 30)) {
      socket_set_blocking($socket, $blocking);
      socket_set_timeout($socket, 17, 555);
   }
   else {
      echo "Could not connect to '<b>$host</b>:$port$path' - error $io_err: $io_err_s.<br>\n";
      return(NULL);
   }
   fputs($socket, $request);

   #-- done here
   return($socket);
}


#-- marshall function call into XML+HTTP string
function xmlrpc_request_marshall($method, &$params) {

   #-- use xmlrpc-epi
   if (XMLRPC_FAST && XMLRPC_EPI) {
      $query = xmlrpc_encode_request($method, $params);
      return($query);
   }

   #-- build query
   $query = array(
      "methodCall" => array(
         "methodName" => array( ",0"=>$method ),
         "params" => array()
      )
   );
   foreach ($params as $i=>$p) {
      $query["methodCall"]["params"]["param,$i"] = xmlrpc_compact_value($p);
   }
   $query = array2xml($query, 1, 'encoding="'.XMLRPC_CHARSET.'" ');

   #-- encode?
   if (XMLRPC_AUTO_UTF8) {
      $query = utf8_encode($query);
   }
   
   return($query);   
}


#-- enclose body into HTTP request string
function xmlrpc_request_http(&$query, $path, $host, $plus, $gzip, $inj_header="") {

   #-- build request
   $n = "\015\012";
   $request = "POST $path HTTP/1.0$n"
            . "Host: $host$n"
            . ($inj_header ? str_replace("\n", $n, $inj_header) : "")
            . "User-Agent: " . XMLRPC_UA . "$n"
            . "Accept: ".XMLRPC_ACCEPT."$n"
            . (!XMLRPC_DEBUG ? "Accept-Encoding: deflate$n" : "")
            . "Content-Type: ".($plus ? XMLRPC_MIME_NEW : XMLRPC_MIME_OLD)
                              ."; charset=".XMLRPC_CHARSET."$n";

   #-- compress?
   if ($gzip) {
      $query = gzdeflate($query);
      $request .= "Content-Encoding: deflate$n";
   }
   $request .= "Content-Length: " . strlen($query) . "$n" . "$n";
   $request .= $query . "$n";

   return($request);
}


#-- unpack response from HTTP and XML representation
function xmlrpc_response_decode(&$response) {
   global $xmlrpc_response_headers;

   #-- split into headers and content
   $l1 = strpos($response, "\n\n");
   $l2 = strpos($response, "\n\r\n");
   if ($l2 && (!$l1 || ($l2<$l1))) {
      $head = substr($response, 0, $l2);
      $response = substr($response, $l2+3);
   }
   else {
      $head = substr($response, 0, $l1);
      $response = substr($response, $l2+2);
   }

   #-- decode headers, decompress body
   foreach (explode("\n", $head) as $line) {
      $xmlrpc_response_headers[strtolower(trim(strtok($line, ":")))] = trim(strtok("\000"));
   }
   if ($enc = trim(@$xmlrpc_response_headers["content-encoding"])) {
      if (($enc == "gzip") || ($enc == "x-gzip")) {
         $response = gzinflate(substr($response, 10, strlen($response)-18));
      }
      elseif (($enc == "compress") || ($enc == "x-compress")) {
         $response = gzuncompress($response);
      }
      elseif (($enc == "deflate") || ($enc == "x-deflate")) {
         $response = gzinflate($response);
      }
   }

   $r = xmlrpc_response_unmarshall($response);
   if (XMLRPC_DEBUG) {var_dump($r);}
   return($r);
}


#-- decode XML-RPC from string into array and extract its actual meaning
function xmlrpc_response_unmarshall(&$response) {
   global $xmlrpc_response_headers;

   #-- strip encoding
   if (XMLRPC_AUTO_UTF8) {
      xmlrpc_decode_utf8xml($response, @$xmlrpc_response_headers["content-type"].@$xmlrpc_response_headers["content-charset"]);
   }

   if (XMLRPC_DEBUG >= 4) { fwrite(fopen("/tmp/xmlrpc:resp_in_xml","w"), $response); }
   
   #-- use xmlrpc-epi
   if (XMLRPC_FAST && XMLRPC_EPI) {
      $r = xmlrpc_decode_request($response, $uu);
      xmlrpc_epi_decode_xtypes($r);
      if (is_array($r) && (count($r)==2) && isset($r["faultCode"]) && isset($r["faultString"])) {
         return xmlrpc_error($r["faultCode"], $r["faultString"], 1, "GLOBALVARS");
      }
      else {
         return($r);
      }
   }


   #-- unmarshall XML
   $response = xml2array($response);

   #-- fetch content (one returned element)
   if ($r = @$response["methodResponse,0"]["params,0"]["param,0"]["value,0"]) {
      $r = xmlrpc_decode_value($r);
      return($r);
   }
  
   #-- error cases
   #  (we should rather return an error object here)
   if (($r = @$response["methodResponse,0"]["fault,0"]["value,0"]) && ($r = xmlrpc_decode_value($r))) { 
      return xmlrpc_error($r["faultCode"], $r["faultString"], 1, "GLOBALVARS");
   }
   else {
      return xmlrpc_error(-32600, "xml+rpc: invalid response", 0, "GLBLVRS");
   }
   return(NULL);
}



#-- Establish a virtual XML+RPC or XML-RPC server connection (a pseudo
#   handshake is used to determine supported protocol / extensions).
class xmlrpc_connection {

   #-- init
   function xmlrpc_connection($url, $autodiscovery=0) {
      global $xmlrpc_response_headers;
      $this->server = $url;
      $this->plus = 0;
      $this->gzip = 0;

      #-- handshake to check supported protocol
      $funcs = $this->call("system.getVersion");
      $this->plus = (strpos($xmlrpc_response_headers["accept"], XMLRPC_MIME_NEW) !== false);
      $this->gzip = (strpos($xmlrpc_response_headers["accept_encoding"], "deflate") !== false);
      
      #-- auto-discovery, create 'method' names
      if ($funcs && (XMLRPC_AUTODISCOVERY || $autodiscovery)) {
         foreach ($funcs as $fn) {
            $short = $fn;
            if ($l = strpos($fn, ".")) {
               $short = substr($fn, $l + 1);
               if (substr($fn, 0, $l) == "system") { continue; }
            }
            $this->short = create_function("", "return xmlrpc_request('{$this->server}','$fn',func_get_args(),{$this->plus},{$this->gzip});");
         }
      }
   }
   
   #-- generical call (needs func name)
   function call($method /*, ... */) {
      $params = func_get_args();
      shift($params);
      $r = xmlrpc_request($this->serverm, $method, $params, $this->plus, $this->gzip);
      return($r);
   }
}

#-- an alias
class xmlrpc extends xmlrpc_connection {
}




############################################################################
#                                                                          #
#  server implementation                                                   #
#                                                                          #
############################################################################


#-- Check request and execute function if registered in $xmlrpc_methods[]
#   array.
function xmlrpc_server() {

   global $xmlrpc_methods;

   #-- server is active
   define("XMLRPC_SERVER", getmypid());
   if (XMLRPC_DEBUG) { error_reporting(E_ALL^E_NOTICE); }
   ob_start();

   #-- standard reply headers
   header("Accept: ".XMLRPC_MIME_NEW.", ".XMLRPC_MIME_OLD."; q=0.5");
   header("Accept-Encoding: deflate");
   header("X-Server: " . XMLRPC_UA);
   header("Connection: close");
   header("Cache-Control: private");

   #-- fixes for PHP/Apache
   if (function_exists("getallheaders")) {
      foreach (getallheaders() as $i=>$v) {
         $_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");
      }
   }
   if (!($xml_request = xmlrpc_fetch_post_chunk())) {
      header("Status: 500 How Sad");
      die("<h2>Error</h2>Could not fetch POST data.\n");
   }

   #-- decipher incoming XML request string
   $method = "";
   if (XMLRPC_FAST && XMLRPC_EPI) {
      $params = xmlrpc_decode_request($xml_request, $method);
      xmlrpc_epi_decode_xtypes($params);
   }
   else {
      $params = xmlrpc_request_unmarshall($xml_request, $method);
   }

   
   #-- add the few system.methods()
   //if (empty($xmlrpc_methods)) {
   //   $xmlrpc_methods = get_defined_functions();
   //}
   $xmlrpc_methods["system"] = "xmlrpc_system_methods";   # a class

   #-- call
   $result = xmlrpc_exec_method($method, $params);

   #-- send back result
   if (isset($result)) {
      if (isset($result)) {
         $resp["methodResponse"]["params"]["param"] = xmlrpc_compact_value($result);
      }
      else {
         $resp["methodResponse"]["params"] = array();
      }

      xmlrpc_send_response($resp);
   }
   else {
      $result = xmlrpc_error(0, "No Result");
      xmlrpc_send_response($result);
   }
}



#-- 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"];
   if (!$call) {
      xmlrpc_send_response(xmlrpc_error(-32600, "Bad Request, <methodCall> missing"));
   }
   $method = $call["methodName,0"][",0"];
   if (!$method) {
      xmlrpc_send_response(xmlrpc_error(-32600, "Bad Request, <methodName> missing"));
   } 

   $params = array();
   foreach ($call["params,1"] as $uu => $param) {
      $params[] = xmlrpc_decode_value($param["value,0"]);
   }

   return($params);
}



#-- Call the requested method (using the XML-method to PHP-function mapping
#   table and hints).
function xmlrpc_exec_method($method, $params) {

   global $xmlrpc_methods;
   if (XMLRPC_DEBUG >= 2) { error_reporting(E_ALL^E_NOTICE); }

   #-- check if allowed call
   $rf = strtr($method, ".", "_");
   $cl = strtok($method, ".");
   if (!$xmlrpc_methods[$method] && !$xmlrpc_methods[$cl]
      && !in_array($method, $xmlrpc_methods)
      && !in_array($rf, $xmlrpc_methods) && !in_array($cl, $xmlrpc_methods) )
   {
      xmlrpc_send_response(xmlrpc_error(-32601));
   }

   #-- real function call
   if ($php_func_name = $xmlrpc_methods[$method]) {
      $rf = $method = $php_func_name;
   }
   if (function_exists($rf)) {
      $result = call_user_func_array($rf, $params);
      if (XMLRPC_DEBUG >= 4) { fwrite(fopen("/tmp/xmlrpc:func_call_res","w"),serialize(array($rf,$result,$params))); }
      return($result);
   }
   #-- PHP object method calls
   else {
      $class = strtok($method, ".");
      $method = strtok("\000");
      if ($uu = $xmlrpc_methods[$class]) {
         $class = $uu;
      }
      if ($class && class_exists($class) && $method) {
         $obj = new $class;
         if (method_exists($obj, $method)) {
            $result = call_user_method_array($method, $obj, $params);  //<DEPRECATED>
            return($result);
         }
      }
   }

   #-- else error
   xmlrpc_send_response(xmlrpc_error(-32601));
}



#-- Get POST data from PHP (if it gives it to us).
function xmlrpc_fetch_post_chunk() {
   global $HTTP_RAW_POST_DATA;

   $data = false;
   if ($f = fopen("php://input", "rb")) {
      $data = fread($f, 0x0100000);
      fclose($f);
   }
   if (empty($data)) {
      ini_set("always_populate_raw_post_data", "true");  // well, maybe(!?)
      $data = $HTTP_RAW_POST_DATA;
      $HTTP_RAW_POST_DATA = "";
   }
   $enc = trim(strtolower($_SERVER["HTTP_CONTENT_ENCODING"]));
   $funcs = array("deflate"=>"gzinflate", "gzip"=>"gzdecode", "compress"=>"gzuncompress", "x-gzip"=>"gzdecode", "x-bzip2"=>"bzuncompress");
   if ($enc && ($pf = $funcs[$enc]) && function_exists($pf)) {
      $data = $pf($data);
   }
   return($data);
}


#-- converts UTF-8 documents into Latin-1 ones
function xmlrpc_decode_utf8xml(&$xml, $ct) {
   if (strpos(strtolower($ct), "utf-8") or preg_match('/<\?xml[^>]+encoding=["\']utf-8/i', $xml)) {
      $xml = utf8_decode($xml);
      $xml = preg_replace('/(<\?xml[^>]+encoding=["\'])utf-8(["\'])/i', '$1iso-8859-1$2', $xml, 1);
   }
}



#-- Creates an error object.
function xmlrpc_error($no=-32500, $str="", $type=1, $into_vars=0) {
   global $xmlrpc_error, $xmlrpc_errorcode;
   $errors = array(
           0 => "No Result",
      -32300 => "Transport error",
      -32400 => "Internal Server Error",
      -32500 => "Application error",
      -32600 => "Invalid message format / Bad request",
      -32601 => "Method does not exist",
      -32602 => "Parameter type mismatch",
      -32603 => "Internal XML-RPC error",
      -32604 => "Too many parameters",
      -32700 => "Not well-formed XML",
      -32701 => "Unsupported encoding - only ISO-8859-1 and UTF-8 capable",
      -32702 => "Invalid characters, encoding mismatch",
   );
   #-- build response xml/array
   if (!($str) && !($str = $errors[$no])) {
      $str = "Unknown Error";
   }
   if ($into_vars && !XMLRPC_OO) {
      $xmlrpc_error = $str;
      $xmlrpc_errorcode = $no;
      return(NULL);
   }
   else {
      return new xmlrpc_error($no, $str, $type);
   }
}


#-- error object
class xmlrpc_error {

   var $type = 1;   // else an HTTP error
   var $no;
   var $str;
   
   function xmlrpc_error($no, $str, $type=1) {
      $this->type = $type;
      $this->no = $no;
      $this->str = $str;
   }
   
   function send() {
      $error = xmlrpc_compact_value(array(
         "faultCode" => $no,
         "faultString" => $str,
      ));
      $resp = array(
         "methodResponse" => array(
            "fault" => $error
         )
      );
      xmlrpc_send_response($resp);
   }
}


#-- Sends a response.
function xmlrpc_send_response($r) {

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

   #-- compress answer?
   if (!headers_sent()) {
      $enc = trim(strtolower($_SERVER["HTTP_ACCEPT_ENCODING"]));
      $funcs = array("deflate"=>"gzdeflate", "gzip"=>"gzencode", "compress"=>"gzcompress", "x-gzip"=>"gzencode", "x-bzip2"=>"bzcompress");
      if ($enc && ($pf = $funcs[$enc]) && function_exists($pf)) {
         header("Content-Encoding: $enc");
         $r = $pf($r);
      }
   }

   #-- send
   if (ob_get_level()) {
      #-- this prevents that PHP errors appear as garbage in our response
      $add .= "<!--\n" . ob_get_contents() . "\n-->";
      ob_end_clean();
   }
   header("Content-Length: " . strlen($r));
   print $r . $add;
   die;
}



#-- Provides "system.*" method namespace.
class xmlrpc_system_methods {

   function listMethods() {
      global $xmlrpc_methods;
      $r = array();
      foreach ($xmlrpc_methods as $i=>$i2) {
         $real = is_int($i) ? $i2 : $i;
         if (class_exists($real) && ($i2=$real) || class_exists($i2)) {
            foreach (get_class_methods($i2) as $add) {
               $r[] = $real.".".$add;
            }
         }
         else {
            $r[] = $real;
         }
      }
      return($r);
   }

   function time() {
      return new xmlrpc_datetime(time());
   }
}


############################################################################
#                                                                          #
#  misc functions                                                          #
#                                                                          #
############################################################################


function xmlrpc_log($message) {
}

function xmlrpc_die($error="", $str="") {
}



############################################################################
#                                                                          #
#  data representation mangling                                            #
#                                                                          #
############################################################################


#-- Makes compact-array2xml datavar from a PHP variable.
function xmlrpc_compact_value($var, $n=0) {

   #-- create compact-array2xml tree
   $root = array(
      "value,$n" => array(),
   );
   $r = &$root["value,$n"];

   #-- detect PHP values to be complex types in XML-RPC
   if (XMLRPC_AUTO_TYPES && is_string($var)) {
      if ((strlen($var) >= 64) && preg_match('/^[\w]+=*$/', $var)) {
         $var = new xmlrpc_base64($var);
      }
      elseif ((strlen($var)==17) && ($var[8]=="T") && preg_match('/^\d{8}T\d\d:\d\d:\d\d$/', $var)) {
         $var = new xmlrpc_datetime($var);
      }
   }

   #-- complex types
   if (is_object($var)) {
      $r = $var->out();
   }
   #-- arrays and hashes(structs)
   elseif (is_array($var)) {
      if (isset($var[0]) || empty($var)) {
         $r = array("array,$n" => array("data,0" => array()));
         $r = &$r["array,$n"]["data,0"];
         foreach ($var as $n=>$val) {
            $r = array_merge($r, xmlrpc_compact_value($val, $n));
         }
      }
      else {
         $r = array("struct,$n"=>array());
         $r = &$r["struct,$n"];
         $n = 0;
         foreach ($var as $i=>$val) {
            $r["member,$n"] = array_merge(array(
               "name,0" => array(",0" => "$i"),
            ), xmlrpc_compact_value($val, 1));
            $n++;
         }
      }
   }
   #-- simple types
   elseif (is_bool($var)) {
      $r = array(
         "boolean,$n" => array(",0" => ($var?1:0)),
      );
   }
   elseif (is_int($var)) {
      $r = array(
         "int,$n" => array(",0" => $var),
      );
   }
   elseif (is_float($var)) {
      $r = array(
         "double,$n" => array(",0" => $var),
      );
   }
   elseif (is_string($var)) {
      $r = array(
         "string,$n" => array(",0" => $var),
      );
   }
   return($root);
}


#-- Makes a PHP array from a compact-xml2array representation. $value must
#   always be the xml2array elements _below_ the ["value,0"] or ["data,0"]
#   or ["member,N"] entry.
function xmlrpc_decode_value($value) {
   $val = NULL;
   foreach ($value as $i=>$d) {

      #-- use single (text) content xml2array entry as actual $d var
      if (is_array($d) && isset($d[",0"])) {
         $d = $d[",0"];
      }

      #-- convert into PHP var based on type
      $type = strtok($i, ",");
      switch ($type) {

         case "array":
            $val = array();
            foreach ($d["data,0"] as $i=>$value) {
               $val[] = xmlrpc_decode_value($value);
            }
            break;

         case "struct":
            $val = array();
            foreach ($d as $uu=>$d2) {
               if (($in=$d2["name,0"][",0"]) && ($pos2=1) || ($in=$d2["name,1"][",0"]) && ($pos2=0)) {
                  $val[$in] = xmlrpc_decode_value($d2["value,$pos2"]);
               }
            }
            break;

         case "":    # handles also '<value>s</value>' instead
         case "0":   # of '<value><string>s</string></value>'
         case "string":
            $val =  is_array($d) ? "" : (string)$d;
            break;

         case "base64":
            $val = (XMLRPC_AUTO_TYPES>=2) ? base64_decode($d) : (string)$d;
            if ((XMLRPC_AUTO_UTF8 >= 2) && ($uu = utf8_decode($val))) {
               $val = $uu;
            }
            break;
            
      // case "real":  case "float":   // neither is allowed
         case "double":
            $val = (double)$d;
            break;
         case "i4":
         case "int":
            $val = (int)$d;
            break;

         case "boolean":
            $val = (boolean)$d;
            break;

         case "dateTime.iso8601":
            $val = xmlrpc_strtotime($d);
            break;

         default:
            if (defined("XMLRPC_SERVER")) {
               xmlrpc_send_response(xmlrpc_error(-32600, "Unknown data type '$type'"));
            }
            else {
               echo $xmlrpc_error = "UNKNOWN XML-RPC DATA TYPE '$type'<br>\n";
               $xmlrpc_errorcode = -32207;
            }
#           echo "<!-- UNKNOWN TYPE $type -->\n";
#           xmlrpc_log("bad data type '$type' enountered");
      }
   }
   return($val);
}


#-- More complex XML-RPC data types need object representation to
#   distinguish them from ordinary string and integer vars.
class xmlrpc_xtype {
   var $scalar = "";
   var $xmlrpc_type = "string";
   var $tag = "string";
   function xmlrpc_type($str) {
      $this->data = $str;
   }
   function out() {
      return array($this->tag.",0" => array(",0"=>$this->scalar));
   }
}
class xmlrpc_base64 extends xmlrpc_xtype {
   function xmlrpc_base64($str) {
      $this->tag = "base64";
      $this->xmlrpc_type = "base64";
      if (XMLRPC_AUTO_UTF8 >= 2) {
         $str = utf8_encode($str);
      }
      if (!preg_match("/^[=\w\s]+$/", $str)) {
         $this->encode=1;
      }
      $this->scalar = $str;
   }
   function out() {
      if (isset($this->encode)) {
         $this->scalar = chunk_split(base64_encode($this->scalar), 74, "\n");
      }
      return xmlrpc_xtype::out();
   }
}
class xmlrpc_datetime extends xmlrpc_xtype {
   function xmlrpc_datetime($t) {
      $this->tag = "dateTime.iso8601";
      $this->xmlrpc_type = "datetime";
      if (($t > 0) && ($t[8] != "T")) {
         $this->timestamp = $t;
         $t = xmlrpc_timetostr($t);
      }
      $this->scalar = $t;
   }
}

#-- Further simplify use of the above ones.
function xmlrpc_base64($string) {
   return(new xmlrpc_base64($string));
}
function xmlrpc_datetime($timestr) {
   return(new xmlrpc_datetime($timestr));
}


#-- Deciphers ISO datetime string into UNIX timestamp.
function xmlrpc_strtotime($str) {
   $tm = explode(":", substr($str, 9));
   $t = mktime($tm[0], $tm[1], $tm[2], substr($str, 4, 2), substr($str, 6, 2), substr($str, 0, 4));
   return($t);
}
function xmlrpc_timetostr($time) {
   return(gmstrftime("%Y%m%dT%T", $time));
}


#-- helping hand for the xmlrpc-epi extension of php
function xmlrpc_epi_decode_xtypes(&$r) {
   if (is_object($r) && isset($r->xmlrpc_type)) {
      if (isset($r->timestamp)) {
         $r = $r->timestamp;
      }
      else {
         $r = $r->scalar;
      }
   }
   elseif (is_array($r)) {
      foreach ($r as $i=>$v) {
         xmlrpc_epi_decode_xtypes($r[$i]);
      }
   }
}




############################################################################
#                                                                          #
#  simplified XML parser                                                   #
#                                                                          #
############################################################################


#-- Encode the two chars & and < into htmlentities (there is nothing said
#   about the possible other entities in the XML-RPC spec).
function xml_entities($str) {
   $e = array(
      "&" => "&amp;",
      "<" => "&lt;",
//      ">" => "&gt;",
   );
   return(strtr($str, $e));
}
function xml_decode_entities($str) {
   $e = array(
      "&lt;" => "<",
      "&gt;" => ">",
      "&apos;" => "'",
      "&quot;" => '"',
      "&amp;" => "&",
   );
   if (strpos($e, "&#") !== false) {
      $e = preg_replace('/&#(\d+);/e', 'chr($1)', $e);
      $e = preg_replace('/&#x([\da-fA-F]+);/e', 'chr(hexdec("$1"))', $e);
   }
   return(strtr($str, $e));
}


#-- Can split simplified XML into a PHP array structure. The now used
#   'compact' format will yield tag sub arrays with an "*,0" index and
#   just [",0"] for text nodes.
function xml2array($xml, $compact="ALWAYS") {
   $r = array();
   if (function_exists("xml_parser_create") && (strlen($xml) >= 512)) {
      $r = xml2array_php($xml);
   }
   else {
      xml2array_parse($xml, $r, $compact);
   }
   return($r);
}


#-- Recursively builds an array of the chunks fetched via strtok() from
#   the original XML input string.
function xml2array_parse(&$string, &$r, $compact=1) {
   $n = 0;
   do {
      #-- split chunks
      $l = strpos($string, "<");
      $p = strpos($string, ">", $l);
      $text = $attr=$close = $tag = false;
      if ($l === false) {
         $text = $string;
         $string = false;
      }
      else {
         $tag = strtok(substr($string, $l+1, $p-$l-1), " ");
         if ((strncmp($tag, "![CDATA[", 8)==0) && ($p = strpos($string, "]]>", $l))) {
            $text = substr($string, $l+9, $p-$l-9);
         }
         else {
            if ($l) {
               $text = xml_decode_entities(substr($string, 0, $l));
            }
            $attr = strtok("\000");
            $close = $attr && ($attr[strlen($attr)-1]=="/");
            $string = substr($string, $p+1);
         }
      }
      #-- insert text/body content into array
      if (trim($text)) {
#         if ($compact) {
             $r[",$n"] = $text;
#         }
#         else {
#            $r[] = $text;
#         }
         $n++;
      }
      #-- recurse for tags
      if ($tag && ($tag[0] >= 'A')) {    #-- don't read <? <! </ pseudo-tags
#         if ($compact) {
             $r["$tag,$n"] = array();
             $new = &$r["$tag,$n"];
#         } else {
#            $r[] = array($tag => array());
#            $new = &$r[count($r)-1][$tag];
#         }
         if (!$close) {
            xml2array_parse($string, $new, $compact);
         }
         $n++;
      }
      #-- stop if no more tags or content
      if (empty($tag) && empty($text) || empty($string)) {
         $tag = "/";
      }
   } while ($tag[0] != "/");
}


#-- Uses the XML extension of PHP to convert an XML stream into the
#   compact array representation.
function xml2array_php(&$xml, $compact=1) {

   $p = xml_parser_create(xml_which_charset($xml));
   xml_parser_set_option($p, XML_OPTION_CASE_FOLDING, false);
   xml_parser_set_option($p, XML_OPTION_TARGET_ENCODING, "ISO-8859-1");

   xml_parse_into_struct($p, $xml, $struct);

   $a = array();  // will hold all tag nodes
   $tree = array(&$a);  // stack of pointers to last node of any tree level
   $in = &$a;           // pointer to last created node

   foreach ($struct as $t) {
      unset($value);
      extract($t);

      $depth = count($tree) - 1;
      $in = &$tree[$depth];
      $tag .= "," . count($in);
//echo "#$depth, TAG=\"$tag\", TYP=$type, LEV=$level, VAL=$value\n";

      switch ($type[1]) {

         #--  OpEN
         case "p":
            $in[$tag] = array();
            if ($type=="open") {
               $tree[] = &$in[$tag];
            }
            if (isset($value) && trim($value)) {
               $in[$tag][",0"] = $value;
            }
            break;

         #--  CoMPLETE
         case "o":
            $in[$tag] = array();
            if (isset($value) && trim($value)) {
               $in[$tag][",0"] = $value;
            }
            break;

         #--  ClOSE
         case "l":
            array_pop($tree);
            break;

         #--  CdATA - usually just whitespace
         case "d":
            if (isset($value) && trim($value)) {
               $in[",".count($in)] = $value;
            }
            break;
         
         default:
            // case "attribute":
            // and anything else we do not want
      }
      
   }
   
   return($a);
}



function xml_which_charset(&$xml) {
   return( strpos(strtok($xml, "\n"), '-8859-1"') ? "iso-8859-1" : "utf-8" );
}



############################################################################
#                                                                          #
#  simplified XML creator                                                  #
#                                                                          #
############################################################################


#-- This is the opposite of the above xml2array, and can also work with the
#   so called $compact format.
function array2xml($r, $compact=1, $ins="") {
   $string = "<?xml version=\"1.0\" $ins?>";
   array2xml_push($string, $r, $compact);
   return($string);
}


#-- Recursively throws out the XMLified tree generated by the xml2array()
#   'parser' function.
function array2xml_push(&$string, &$r, $compact, $ind=-1) {
   $old_ind = ++$ind - 1;
   if ($old_ind < 0) { $old_ind = 0; }
   foreach ($r as $i=>$d) {
      $d = &$r[$i];
      if (is_scalar($d)) {
         $string .= xml_entities($d);
      }
      elseif (is_array($d)) {
         if ($compact) {
            $i = strtok($i, ","); 
         }
         $ls = str_repeat(" ", $ind);
         $string .= "\n$ls<$i>";
         $string .=  array2xml_push($string, $d, $compact, $ind);
         $ls = str_repeat(" ", $old_ind);
         $string .= "</$i>\n$ls";
      }
   }
}




?>

Added ext/contrib/archive/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.


Deleted ext/contrib/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, similiar to Javas. 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 you'd 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 similiar 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("$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")) {
   // quick hack, should use a different func name
   function set_exception_handler($func) {
      global $_EXCEPTION;
      $_EXCEPTION = $func;
   }
}


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






















































































































































































































































































































































































































Deleted ext/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
50
51
52
53
54
55
56
57
58
<?php
/*
  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

   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]);
          unset($TO[$var]);   // double unset to work around ZE-num/assoc-hashcode bug
       }
    }
 }
 function ewiki_recursive_stripslashes(&$var) {
    if (is_array($var)) {
       foreach ($var as $key=>$item) {
          ewiki_recursive_stripslashes($var[$key]);
       }
    }
    else {
       $var = stripslashes($var);
    }
 }

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




















































































































Added ext/contrib/fix_magic_quotes.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
<?php
/*
  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

   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]);
          unset($TO[$var]);   // double unset to work around ZE-num/assoc-hashcode bug
       }
    }
 }
 function ewiki_recursive_stripslashes(&$var) {
    if (is_array($var)) {
       foreach ($var as $key=>$item) {
          ewiki_recursive_stripslashes($var[$key]);
       }
    }
    else {
       $var = stripslashes($var);
    }
 }

?>

Added ext/contrib/header_errors.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
/*
   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) {

   static $error_types = array(
      E_PARSE => "PARSE ERROR",
      E_ERROR => "ERROR",
      E_WARNING => "WARNING",
      E_NOTICE => "NOTICE",
      E_STRICT => "STRICT",
      E_USER_ERROR => "USER ERROR",
      E_USER_WARNING => "USER WARNING",
      E_USER_NOTICE => "USER NOTICE",
   );
   ($errtype = $error_types[$errno]) or ($errtype = "UNDEF ERROR");
   
   #-- check for @ and disabled errors
   $emask = get_cfg_var("error_reporting");
   if (! ($emask & $errno)) {
      return;
   }

   #-- output
   $msg = strtr($msg, "\r\n\t\f", "    ");
   $msg = "$errtype: $msg in $file, line #$line";
   if (headers_sent()) {
      print "\n<!--<div class=\"php-error\">$msg</div>-->\n";
   }
   else {
      $no = crc32($msg);
      $no = ($no & 0xFFFF) ^ ($no >> 16);
      header("X-Error-$no: $msg");
      if ($errno == E_FATAL) { header("Status: 500 Something bad happened"); }
   }
}

?>

Deleted ext/contrib/hiddenerrors.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
/*
   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) {

   static $error_types = array(
      E_PARSE => "PARSE ERROR",
      E_ERROR => "ERROR",
      E_WARNING => "WARNING",
      E_NOTICE => "NOTICE",
      E_STRICT => "STRICT",
      E_USER_ERROR => "USER ERROR",
      E_USER_WARNING => "USER WARNING",
      E_USER_NOTICE => "USER NOTICE",
   );
   ($errtype = $error_types[$errno]) or ($errtype = "UNDEF ERROR");
   
   #-- check for @ and disabled errors
   $emask = get_cfg_var("error_reporting");
   if (! ($emask & $errno)) {
      return;
   }

   #-- output
   $msg = strtr($msg, "\r\n\t\f", "    ");
   $msg = "$errtype: $msg in $file, line #$line";
   if (headers_sent()) {
      print "\n<!--<div class=\"php-error\">$msg</div>-->\n";
   }
   else {
      $no = crc32($msg);
      $no = ($no & 0xFFFF) ^ ($no >> 16);
      header("X-Error-$no: $msg");
      if ($errno == E_FATAL) { header("Status: 500 Something bad happened"); }
   }
}

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


































































































Deleted ext/contrib/http.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
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
<?php
/*
  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

   This snippet implements HTTP queries, and allows for most request
   methods, content types and encodings. It is useful for contacting
   scripts made to serve HTML forms.
    - does neither depend upon wget or curl, nor any other extension
    - you can add ->$params (form variables) on the fly, it's a hash
    - if the initial URL contains a query string, the vars will be
      extracted first
    - set the ->$enc very carefully, because many CGI apps and HTTP
      servers can't deal with it (else "gzip" and "deflate" are nice)
    - there are abbreviations for the content ->$type values (namely
      "form" , "url" and "php")
    - user:password@ pairs may be included in the initially given URL
    - headers always get normalized to "Studly-Caps"
    - won't support keep-alive connections
    - for PUT and other methods, the ->$params var may just hold the
      request body
    - files can be added to the ->params array as hash with specially
      named fields: "content"/"data", and "filename"/"name" , "type"
    - you can add authentication information using the standard notation
      "http://user:passw@www.example.com/..." for ->$url and ->$proxy

   A response object will have a ->$content field, ->$headers[] and
   ->len, ->type attributes as well. You could also ->decode() the
   body, if it is app/vnd.php.serialized or app/x-www-form-urlencoded.
   
   Public Domain (use freely, transform into any other license, like
   LGPL, BSD, MPL, ...; but if you change this into GPL please be so
   kind and leave your users a hint where to find the free version).
*/


#-- request objects
class http_request {

   var $method = "GET";
   var $proto = "HTTP/1.1";
   var $url = "";
   var $params = array();   // URL/form post vars, or single request body str
   var $headers = array();
   var $cookies = array();
   var $type = "url";       // content-type, abbrv. for x-www-form-...
   var $enc = false;        // "gzip" or "deflate"
   var $error="", $io_err=0, $io_err_s="";
   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, "?");
         if ($uu = strtok("\000")) {
            $this->setQueryString($uu);
         }
      }
      else {
         $this->url = $url;
      }
   }
   
   
   #-- decodes a query strings vars into the $params hash
   function setQueryString($qs) {
      $qs = ltrim($qs, "?");
      parse_str($qs, $this->params);
   }


   #-- returns params as querystring for GET requests
   function getQueryString() {
      $qs = "";
      if (function_exists("http_build_query")) {
         $qs = http_build_query($this->params);
      }
      else {
         foreach ($this->params as $n=>$v) {
            $qs .= "&" . urlencode($n) . "=" . urlencode($v);
         }
         $qs = substr($qs, 1);
      }
      return($qs);
   }


   #-- transforms $params into request body
   function pack(&$path) {
      $m = strtoupper($this->method);

      #-- GET, HEAD
      if (($m == "GET") || ($m == "HEAD")) {
         $BODY = "";
         $path .= (strpos($path, "?") ? "&" : "?") . $this->getQueryString();
      }

      #-- POST
      elseif (($m == "POST") && is_array($this->params)) {

         #-- known encoding types
         $type = $this->type($this->type, 0);
         if ($type == "url") {
            $BODY = $this->getQueryString($prep="");
         }
         elseif ($type == "php") {
            $BODY = serialize($this->params);
         }
         elseif ($type == "form") {
            // boundary doesn't need checking, unique enough
            $bnd = "snip-".dechex(time())."-".md5(serialize($this->params))
                 . "-".dechex(rand())."-snap";
            $BODY = "";
            foreach ($this->params as $i=>$v) {
               $ct = "text/plain";
               $inj = "";
               if (is_array($v)) {
                  ($ct = $v["ct"].$v["type"].$v["content-type"]) || ($ct = "application/octet-stream");
                  $inj = ' filename="' . urlencode($v["name"].$v["file"].$v["filename"]) . '"';
                  $v = $v["data"].$v["content"].$v["body"];
               }
               $BODY .= "--$bnd\015\012"
                     . "Content-Disposition: form-data; name=\"".urlencode($i)."\"$inj\015\012"
                     . "Content-Type: $ct\015\012"
                     . "Content-Length: " . strlen($v) . "\015\012"
                     . "\015\012$v\015\012";
            }
            $BODY .= "--$bnd--\015\012";
            $ct = $this->type("form") . "; boundary=$bnd";
         }
         #-- ignore
         else {
            $this->error = "unsupported POST encoding";
          // return(false);
            $BODY = & $this->params;
         }

         $this->headers["Content-Type"] = isset($ct) ? $ct : $this->type($type, 1);
      }

      #-- PUT, POST, PUSH, P*
      elseif ($m[0] == "P") {
         $BODY = & $this->$params;
      }

      #-- ERROR (but don't complain)
      else {
         $this->error = "unsupported request method '{$this->method}'";
       //  return(false);
         $BODY = & $this->params;
      }

      return($BODY);
   }


   #-- converts content-type strings from/to shortened nick
   function type($str, $long=1) {
      $trans = array(
         "form" => "multipart/form-data",
         "url" => "application/x-www-form-urlencoded",
         "php" => "application/vnd.php.serialized",
      );
      $trans["multi"] = &$trans["form"];
      if ($long) {
         $new = $trans[$str];
      }
      else {
         $new = array_search($str, $trans);
      }
      return( $new ? $new : $str );
   }


   #-- initiate the configured HTTP request ------------------------------
   function go($force=0, $asis=0) {

      #-- prepare parts
      $url = $this->prepare_url();
      if (!$url && !$force) { return; }
      $BODY = $this->body($url);
      if (($BODY===false) && !$force) { return; }
      $HEAD = $this->head($url);

      #-- open socket
      if (!$this->connect($url)) {
         return;
      }

      #-- send request data
      fwrite($this->socket, $HEAD);
      fwrite($this->socket, $BODY);
      $HEAD = false;
      $BODY = false;

      #-- read response, end connection
      while (!feof($this->socket) && (strlen($DATA) <= 1<<22)) {
         $DATA .= fread($this->socket, 32<<10);
#echo "fread(".strlen($DATA).") ";
      }
      fclose($this->socket);
      unset($this->socket);

      #-- for raw http pings
      if ($asis) { 
         return($DATA);
      }

      #-- decode response
      $r = new http_response();
      $r->from($DATA);        // should auto-unset $DATA

      #-- handle redirects
      if ($this->active_client) {
         $this->auto_actions($r);
      }

      #-- fin      
      return($r);
   }

   #-- alias
   function start($a=0, $b=0) { 
      return $this->go($a, $b);
   }
   
   
   #-- creates socket connection
   function connect(&$url) {
      if ((isset($this->socket) and !feof($this->socket))
      or ($this->socket = fsockopen($url["host"], $url["port"], $this->io_err, $this->io_err_s, $this->timeout))) {
         socket_set_blocking($this->socket, true);
         socket_set_timeout($this->socket, $this->timeout, 555);
         return(true);
      }
      else {
         $this->error = "no socket/connection";
         return(false);
      }
   }


   #-- separate URL into pieces, prepare special headers
   function prepare_url() {
      $this->setURL($this->url);
      if (!$this->proxy) {
         $url = parse_url($this->url);
         if (strtolower($url["scheme"]) != "http") {
            $this->error = "unsupported protocol/scheme";
            return(false);
         }
         if (!$url["host"]) { return; }
         if (!$url["port"]) { $url["port"] = 80; }
         if (!$url["path"]) { $url["path"] = "/"; }
         if ($url["query"]) { $url["path"] .= "?" . $url["query"]; }
         $proxy = "";
      }
      else {
         $url = parse_url($this->proxy);
         $url["path"] = $this->url;
         $proxy = "Proxy-";
         $this->headers["Proxy-Connection"] = $this->headers["Connection"];
      }

      #-- inj auth headers
      if ($url["user"] || $url["pass"]) {
         $this->headers[$proxy."Authorization"] = "Basic " . base64_encode("$url[user]:$url[pass]");
      }
      
      return($url);
   }


   #-- generates request body (if any), must be called before ->head()
   function body(&$url) {

      #-- encoding of variable $params as request body (according to reqmethod)
      $BODY = $this->pack($url["path"]);
      if ($BODY === false) {
         return false;
      }
      elseif ($len = strlen($BODY)) {
         $this->headers["Content-Length"] = $len;
      }
      $enc_funcs = array("gzip"=>"gzencode", "deflate"=>"gzinflate", "bzip2"=>"bzcompress", "x-bzip2"=>"bzcompress", "compress"=>"gzcompress");
      if ((strlen($BODY) >= 1024) && ($f = $enc_funcs[$this->enc]) && function_exists($f)) {
         $BODY = $f($BODY);
         $this->headers["Content-Encoding"] = $this->enc;
         $this->headers["Content-Length"] = strlen($BODY);
      }
      return($BODY);
   }


   #-- generates request head part
   function head(&$url) {
   
      #-- inject cookie header (if any)
      if ($this->cookies) {
         $c = "";
         foreach ($this->cookies as $i=>$v) {
            $c .= "; " . urlencode($i) . "=" . urlencode($v);
         }
         $this->headers["Cookie"] = substr($c, 2);
         $this->headers["Cookie2"] = '$Version="1"';
      }
      
      #-- request head
      $CRLF = "\015\012";
      $HEAD  = "{$this->method} {$url[path]} {$this->proto}$CRLF";
      $HEAD .= "Host: {$url[host]}$CRLF";
      foreach ($this->headers as $h=>$v) {
         $HEAD .= trim($h) . ": " . strtr(trim($v), "\n", " ") . $CRLF;
      }
      $HEAD .= $CRLF;
      return($HEAD);
   }

   #-- perform some things automatically (redirects)
   function auto_actions(&$r) {

      #-- behaviour table
      static $bhv = array(
         "failure" => "204,300,304,305,306",
         "clean_::POST" => "300,301,302,303,307",
         "clean_::PUT" => "300,301,302,303,307",
         "clean_::GET" => "300",  // $params:=undef
         "GET_::POST" => "303",
         "GET_::PUT" => "303",    // downgrade $method:=GET
      );
   
      #-- failure
      if (strstr($this->behaviour_table["failure"], $r->status)) {
         return;
      }

      #-- HTTP redirects
      if (($pri_url=$r->headers["Location"]) || ($pri_url=$r->headers["Uri"])) {

         if ((($this->redirects--) >= 0) && ($r->status >= 300) && ($r->status < 400)) {
            $m = strtoupper($this->method);
            if (strstr($this->behaviour_table["clean_::$m"], $r->status)) {
               unset($this->params);
            }
            if (strstr($this->behaviour_table["GET_::$m"], $r->status)) {
               $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() {
   }
   

   #-- fill object from given HTTP response BLOB   
   function from(&$SRC) {
      $this->breakHeaders($SRC);  // split data into body + headers
      $SRC = false;
      $this->decodeHeaders();     // normalize header names
      $this->headerMeta();
      $this->decodeTransferEncodings();    // chunked
      $this->decodeContentEncodings();     // gzip, deflate
      $this->len = strlen($this->content);
   }


   #-- separates headers block from response body part
   function breakHeaders(&$DATA) {
      $l = strpos($DATA, "\012\015\012"); $skip = 3;
      $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
      $str = & $this->headers_str;
//      $str = str_replace("\n ", " ", $str);
      $str = str_replace("\r", "", $str);
      
      #-- strip headline
      $nl = strpos($str, "\n") + 1;
      $this->proto = strtok(substr($str, 0, $nl), " ");
      $this->status = (int) strtok(" ");
      $this->status_str = strtok("\000\r\n");
      if ($this->status == 100) {
         $this->full_duplex = 1;
      }

      #-- go through lines, split name:value pairs
      foreach (explode("\n", substr($str, $nl)) as $line) {

         $i = trim(strtok($line, ":"));
         $v = trim(strtok("\000"));

         #-- normalize name look&feel
         $i = strtr(ucwords(strtolower(strtr($i, "-", " "))), " ", "-");

         #-- add to, if key exists
         if (!empty($this->headers[$i])) {
            $this->headers[$i] .= ", ".$v;
         }
         else {
            $this->headers[$i] = $v;
         }

      }
   }


   #-- extract interesting values
   function headerMeta() {
      $this->len = strlen($this->content);
      $this->type = trim(strtok(strtolower($this->headers["Content-Type"]), ";"));
   }
   

   #-- strip any content transformation
   function decodeTransferEncodings() {
      $enc = trim(strtok(strtolower($this->headers["Transfer-Encoding"]), ",;"));
      if ($enc) {
         switch ($enc) {
#echo "ENC($enc) ";
            case "chunked":
               $this->decodeChunkedEncoding();
               break;
            case "base64":
               $this->content = base64_decode($this->content);
               $this->len = strlen($this->content);
               break;
            case "identity": case "binary":
            case "7bit": case "8bit":
               break;
            default:
               trigger_error("http_response::decodeTransferEncodings: unkown TE of '$enc'\n", E_WARNING);
         }
      }
   }


   #-- scripts on HTTP/1.1 servers may send fragmented response
   function decodeChunkedEncoding() {

      $data = "";	# decoded data
      $p = 0;		# current string position
#file_put_contents("/tmp/1", $this->content);

      while ($p < strlen($this->content)) {
         #-- read len token
         $n = strtok(substr($this->content, $p, 20), "\n");
#echo "CHUNK($p,$n) ";
         $p += strlen($n)+1;
#echo "CHUNK2($p,$n) ";

         #-- make integer
         $n = hexdec(trim($n));
         if ($n===0) {
            break;
         }
         elseif (!$n) {
            break; //WARN
         }
         $n += 1;

         #-- read data
         $data .= substr($this->content, $p, $n);
         $p += $n + 1;
#echo "CHUNK3($p,$n) ";
      }

      $this->content = $data;
      unset($data);
      $this->len = strlen($this->content);
   }


   #-- uncompress response body
   function decodeContentEncodings() {
      $enc = trim(strtok(strtolower($this->headers["Content-Encoding"]), ";,"));
      $dat = &$this->content;
      if ($enc == "deflate") {
         $dat = gzinflate($dat);
      }
      elseif (($enc == "gzip") || ($enc == "x-gzip")) {
         if (function_exists("gzdecode")) {
            $dat = gzdecode($dat);
         }
         else {
            $dat = gzinflate(substr($dat, 10, strlen($dat)-18));
         }
      }
      elseif ($enc == "compress") {
         $dat = gzuncompress($dat);
      }
      elseif (($enc == "x-bzip2") || ($enc == "bzip2")) {
         if (function_exists("bzdecompress")) {
            $dat = bzdecompress($dat);
         }
         else trigger_error("http_response::decodeContentEncoding: bzip2 decoding isn't supported with this PHP interpreter version", E_WARNING);
      }
      $this->len = strlen($this->content);
   }


   #-- can handle special content-types (multipart, serialized, form-data)
   function decode() {
      $t = http_request::type($this->type, 0);
      if ($t == "php") {
         return(unserialize($this->content));
      }
      elseif ($t == "url") {
         parse_str($this->content, $r);
         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;
         }
      }
   }
}



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




































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted ext/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. 



<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




























































































































































































































































































































































































































































































































































Added ext/contrib/http_query.class.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
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
<?php
/*
  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

   This snippet implements HTTP queries, and allows for most request
   methods, content types and encodings. It is useful for contacting
   scripts made to serve HTML forms.
    - does neither depend upon wget or curl, nor any other extension
    - you can add ->$params (form variables) on the fly, it's a hash
    - if the initial URL contains a query string, the vars will be
      extracted first
    - set the ->$enc very carefully, because many CGI apps and HTTP
      servers can't deal with it (else "gzip" and "deflate" are nice)
    - there are abbreviations for the content ->$type values (namely
      "form" , "url" and "php")
    - user:password@ pairs may be included in the initially given URL
    - headers always get normalized to "Studly-Caps"
    - won't support keep-alive connections
    - for PUT and other methods, the ->$params var may just hold the
      request body
    - files can be added to the ->params array as hash with specially
      named fields: "content"/"data", and "filename"/"name" , "type"
    - you can add authentication information using the standard notation
      "http://user:passw@www.example.com/..." for ->$url and ->$proxy

   A response object will have a ->$content field, ->$headers[] and
   ->len, ->type attributes as well. You could also ->decode() the
   body, if it is app/vnd.php.serialized or app/x-www-form-urlencoded.
   
   Public Domain (use freely, transform into any other license, like
   LGPL, BSD, MPL, ...; but if you change this into GPL please be so
   kind and leave your users a hint where to find the free version).
*/


#-- request objects
class http_request {

   var $method = "GET";
   var $proto = "HTTP/1.1";
   var $url = "";
   var $params = array();   // URL/form post vars, or single request body str
   var $headers = array();
   var $cookies = array();
   var $type = "url";       // content-type, abbrv. for x-www-form-...
   var $enc = false;        // "gzip" or "deflate"
   var $error="", $io_err=0, $io_err_s="";
   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, "?");
         if ($uu = strtok("\000")) {
            $this->setQueryString($uu);
         }
      }
      else {
         $this->url = $url;
      }
   }
   
   
   #-- decodes a query strings vars into the $params hash
   function setQueryString($qs) {
      $qs = ltrim($qs, "?");
      parse_str($qs, $this->params);
   }


   #-- returns params as querystring for GET requests
   function getQueryString() {
      $qs = "";
      if (function_exists("http_build_query")) {
         $qs = http_build_query($this->params);
      }
      else {
         foreach ($this->params as $n=>$v) {
            $qs .= "&" . urlencode($n) . "=" . urlencode($v);
         }
         $qs = substr($qs, 1);
      }
      return($qs);
   }


   #-- transforms $params into request body
   function pack(&$path) {
      $m = strtoupper($this->method);

      #-- GET, HEAD
      if (($m == "GET") || ($m == "HEAD")) {
         $BODY = "";
         $path .= (strpos($path, "?") ? "&" : "?") . $this->getQueryString();
      }

      #-- POST
      elseif (($m == "POST") && is_array($this->params)) {

         #-- known encoding types
         $type = $this->type($this->type, 0);
         if ($type == "url") {
            $BODY = $this->getQueryString($prep="");
         }
         elseif ($type == "php") {
            $BODY = serialize($this->params);
         }
         elseif ($type == "form") {
            // boundary doesn't need checking, unique enough
            $bnd = "snip-".dechex(time())."-".md5(serialize($this->params))
                 . "-".dechex(rand())."-snap";
            $BODY = "";
            foreach ($this->params as $i=>$v) {
               $ct = "text/plain";
               $inj = "";
               if (is_array($v)) {
                  ($ct = $v["ct"].$v["type"].$v["content-type"]) || ($ct = "application/octet-stream");
                  $inj = ' filename="' . urlencode($v["name"].$v["file"].$v["filename"]) . '"';
                  $v = $v["data"].$v["content"].$v["body"];
               }
               $BODY .= "--$bnd\015\012"
                     . "Content-Disposition: form-data; name=\"".urlencode($i)."\"$inj\015\012"
                     . "Content-Type: $ct\015\012"
                     . "Content-Length: " . strlen($v) . "\015\012"
                     . "\015\012$v\015\012";
            }
            $BODY .= "--$bnd--\015\012";
            $ct = $this->type("form") . "; boundary=$bnd";
         }
         #-- ignore
         else {
            $this->error = "unsupported POST encoding";
          // return(false);
            $BODY = & $this->params;
         }

         $this->headers["Content-Type"] = isset($ct) ? $ct : $this->type($type, 1);
      }

      #-- PUT, POST, PUSH, P*
      elseif ($m[0] == "P") {
         $BODY = & $this->$params;
      }

      #-- ERROR (but don't complain)
      else {
         $this->error = "unsupported request method '{$this->method}'";
       //  return(false);
         $BODY = & $this->params;
      }

      return($BODY);
   }


   #-- converts content-type strings from/to shortened nick
   function type($str, $long=1) {
      $trans = array(
         "form" => "multipart/form-data",
         "url" => "application/x-www-form-urlencoded",
         "php" => "application/vnd.php.serialized",
      );
      $trans["multi"] = &$trans["form"];
      if ($long) {
         $new = $trans[$str];
      }
      else {
         $new = array_search($str, $trans);
      }
      return( $new ? $new : $str );
   }


   #-- initiate the configured HTTP request ------------------------------
   function go($force=0, $asis=0) {

      #-- prepare parts
      $url = $this->prepare_url();
      if (!$url && !$force) { return; }
      $BODY = $this->body($url);
      if (($BODY===false) && !$force) { return; }
      $HEAD = $this->head($url);

      #-- open socket
      if (!$this->connect($url)) {
         return;
      }

      #-- send request data
      fwrite($this->socket, $HEAD);
      fwrite($this->socket, $BODY);
      $HEAD = false;
      $BODY = false;

      #-- read response, end connection
      while (!feof($this->socket) && (strlen($DATA) <= 1<<22)) {
         $DATA .= fread($this->socket, 32<<10);
#echo "fread(".strlen($DATA).") ";
      }
      fclose($this->socket);
      unset($this->socket);

      #-- for raw http pings
      if ($asis) { 
         return($DATA);
      }

      #-- decode response
      $r = new http_response();
      $r->from($DATA);        // should auto-unset $DATA

      #-- handle redirects
      if ($this->active_client) {
         $this->auto_actions($r);
      }

      #-- fin      
      return($r);
   }

   #-- alias
   function start($a=0, $b=0) { 
      return $this->go($a, $b);
   }
   
   
   #-- creates socket connection
   function connect(&$url) {
      if ((isset($this->socket) and !feof($this->socket))
      or ($this->socket = fsockopen($url["host"], $url["port"], $this->io_err, $this->io_err_s, $this->timeout))) {
         socket_set_blocking($this->socket, true);
         socket_set_timeout($this->socket, $this->timeout, 555);
         return(true);
      }
      else {
         $this->error = "no socket/connection";
         return(false);
      }
   }


   #-- separate URL into pieces, prepare special headers
   function prepare_url() {
      $this->setURL($this->url);
      if (!$this->proxy) {
         $url = parse_url($this->url);
         if (strtolower($url["scheme"]) != "http") {
            $this->error = "unsupported protocol/scheme";
            return(false);
         }
         if (!$url["host"]) { return; }
         if (!$url["port"]) { $url["port"] = 80; }
         if (!$url["path"]) { $url["path"] = "/"; }
         if ($url["query"]) { $url["path"] .= "?" . $url["query"]; }
         $proxy = "";
      }
      else {
         $url = parse_url($this->proxy);
         $url["path"] = $this->url;
         $proxy = "Proxy-";
         $this->headers["Proxy-Connection"] = $this->headers["Connection"];
      }

      #-- inj auth headers
      if ($url["user"] || $url["pass"]) {
         $this->headers[$proxy."Authorization"] = "Basic " . base64_encode("$url[user]:$url[pass]");
      }
      
      return($url);
   }


   #-- generates request body (if any), must be called before ->head()
   function body(&$url) {

      #-- encoding of variable $params as request body (according to reqmethod)
      $BODY = $this->pack($url["path"]);
      if ($BODY === false) {
         return false;
      }
      elseif ($len = strlen($BODY)) {
         $this->headers["Content-Length"] = $len;
      }
      $enc_funcs = array("gzip"=>"gzencode", "deflate"=>"gzinflate", "bzip2"=>"bzcompress", "x-bzip2"=>"bzcompress", "compress"=>"gzcompress");
      if ((strlen($BODY) >= 1024) && ($f = $enc_funcs[$this->enc]) && function_exists($f)) {
         $BODY = $f($BODY);
         $this->headers["Content-Encoding"] = $this->enc;
         $this->headers["Content-Length"] = strlen($BODY);
      }
      return($BODY);
   }


   #-- generates request head part
   function head(&$url) {
   
      #-- inject cookie header (if any)
      if ($this->cookies) {
         $c = "";
         foreach ($this->cookies as $i=>$v) {
            $c .= "; " . urlencode($i) . "=" . urlencode($v);
         }
         $this->headers["Cookie"] = substr($c, 2);
         $this->headers["Cookie2"] = '$Version="1"';
      }
      
      #-- request head
      $CRLF = "\015\012";
      $HEAD  = "{$this->method} {$url[path]} {$this->proto}$CRLF";
      $HEAD .= "Host: {$url[host]}$CRLF";
      foreach ($this->headers as $h=>$v) {
         $HEAD .= trim($h) . ": " . strtr(trim($v), "\n", " ") . $CRLF;
      }
      $HEAD .= $CRLF;
      return($HEAD);
   }

   #-- perform some things automatically (redirects)
   function auto_actions(&$r) {

      #-- behaviour table
      static $bhv = array(
         "failure" => "204,300,304,305,306",
         "clean_::POST" => "300,301,302,303,307",
         "clean_::PUT" => "300,301,302,303,307",
         "clean_::GET" => "300",  // $params:=undef
         "GET_::POST" => "303",
         "GET_::PUT" => "303",    // downgrade $method:=GET
      );
   
      #-- failure
      if (strstr($this->behaviour_table["failure"], $r->status)) {
         return;
      }

      #-- HTTP redirects
      if (($pri_url=$r->headers["Location"]) || ($pri_url=$r->headers["Uri"])) {

         if ((($this->redirects--) >= 0) && ($r->status >= 300) && ($r->status < 400)) {
            $m = strtoupper($this->method);
            if (strstr($this->behaviour_table["clean_::$m"], $r->status)) {
               unset($this->params);
            }
            if (strstr($this->behaviour_table["GET_::$m"], $r->status)) {
               $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() {
   }
   

   #-- fill object from given HTTP response BLOB   
   function from(&$SRC) {
      $this->breakHeaders($SRC);  // split data into body + headers
      $SRC = false;
      $this->decodeHeaders();     // normalize header names
      $this->headerMeta();
      $this->decodeTransferEncodings();    // chunked
      $this->decodeContentEncodings();     // gzip, deflate
      $this->len = strlen($this->content);
   }


   #-- separates headers block from response body part
   function breakHeaders(&$DATA) {
      $l = strpos($DATA, "\012\015\012"); $skip = 3;
      $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
      $str = & $this->headers_str;
//      $str = str_replace("\n ", " ", $str);
      $str = str_replace("\r", "", $str);
      
      #-- strip headline
      $nl = strpos($str, "\n") + 1;
      $this->proto = strtok(substr($str, 0, $nl), " ");
      $this->status = (int) strtok(" ");
      $this->status_str = strtok("\000\r\n");
      if ($this->status == 100) {
         $this->full_duplex = 1;
      }

      #-- go through lines, split name:value pairs
      foreach (explode("\n", substr($str, $nl)) as $line) {

         $i = trim(strtok($line, ":"));
         $v = trim(strtok("\000"));

         #-- normalize name look&feel
         $i = strtr(ucwords(strtolower(strtr($i, "-", " "))), " ", "-");

         #-- add to, if key exists
         if (!empty($this->headers[$i])) {
            $this->headers[$i] .= ", ".$v;
         }
         else {
            $this->headers[$i] = $v;
         }

      }
   }


   #-- extract interesting values
   function headerMeta() {
      $this->len = strlen($this->content);
      $this->type = trim(strtok(strtolower($this->headers["Content-Type"]), ";"));
   }
   

   #-- strip any content transformation
   function decodeTransferEncodings() {
      $enc = trim(strtok(strtolower($this->headers["Transfer-Encoding"]), ",;"));
      if ($enc) {
         switch ($enc) {
#echo "ENC($enc) ";
            case "chunked":
               $this->decodeChunkedEncoding();
               break;
            case "base64":
               $this->content = base64_decode($this->content);
               $this->len = strlen($this->content);
               break;
            case "identity": case "binary":
            case "7bit": case "8bit":
               break;
            default:
               trigger_error("http_response::decodeTransferEncodings: unkown TE of '$enc'\n", E_WARNING);
         }
      }
   }


   #-- scripts on HTTP/1.1 servers may send fragmented response
   function decodeChunkedEncoding() {

      $bin = "";	# decoded data
      $p = 0;		# current string position
#file_put_contents("/tmp/1", $this->content);

      while ($p < strlen($this->content)) {
         #-- read len token
         $n = strtok(substr($this->content, $p, 20), "\n");
#echo "CHUNK($p,$n) ";
         $p += strlen($n)+1;
#echo "CHUNK2($p,$n) ";

         #-- make integer
         $n = hexdec(trim($n));
         if ($n===0) {
            break;
         }
         elseif (!$n) {
            break; //WARN
         }
         $n += 1;

         #-- read data
         $bin .= substr($this->content, $p, $n);
         $p += $n + 1;
#echo "CHUNK3($p,$n) ";
      }

      $this->content = $bin;
      unset($bin);
      $this->len = strlen($this->content);
   }


   #-- uncompress response body
   function decodeContentEncodings() {
      $enc = trim(strtok(strtolower($this->headers["Content-Encoding"]), ";,"));
      $dat = &$this->content;
      if ($enc == "deflate") {
         $dat = gzinflate($dat);
      }
      elseif (($enc == "gzip") || ($enc == "x-gzip")) {
         if (function_exists("gzdecode")) {
            $dat = gzdecode($dat);
         }
         else {
            $dat = gzinflate(substr($dat, 10, strlen($dat)-18));
         }
      }
      elseif ($enc == "compress") {
         $dat = gzuncompress($dat);
      }
      elseif (($enc == "x-bzip2") || ($enc == "bzip2")) {
         if (function_exists("bzdecompress")) {
            $dat = bzdecompress($dat);
         }
         else trigger_error("http_response::decodeContentEncoding: bzip2 decoding isn't supported with this PHP interpreter version", E_WARNING);
      }
      $this->len = strlen($this->content);
   }


   #-- can handle special content-types (multipart, serialized, form-data)
   function decode() {
      $t = http_request::type($this->type, 0);
      if ($t == "php") {
         return(unserialize($this->content));
      }
      elseif ($t == "url") {
         parse_str($this->content, $r);
         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 ext/contrib/http_query.class.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. 



Added ext/contrib/input.README.pdf.

cannot compute difference between binary files

Added ext/contrib/input.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
<?php
 /**
  * type: interface
  * title: $_REQUEST var object-wrappers
  * description: provides sanitization by encapsuling request variables against raw access
  * version: 0.1
  * license: public domain (=anything you want)
  * depends: php:filter, php >5.1
  * x-throws: E_NOTICE
  * 
  * Object wrappers for HTTP input variables sanitize incoming data,
  * and prevent casual unverified access. Using them ensures a single
  * entry point and verification spot for all user data.
  *
  *   $_REQUEST = new input($_REQUEST);
  *   $_GET = new input($_GET);
  *   $_POST = new input($_POST);
  *   $_SERVER = new input($_SERVER);
  *
  * Provides convenient access to data over various filter methods:
  *
  *   print $_GET->int("search_q");
  *   mysql_query("  SELECT * FROM x WHERE y='{$_POST->sql(y)}'  ");
  *   require($_SERVER->name("SERVER_NAME").".htm");
  *
  * Available filter methods are:
  *   ->int
  *   ->name
  *   ->raw
  *   ->text
  *   ->regex
  *   ->array_int
  *   ->sql
  * and most sanitizers that the php filter_ extension provides.
  *
  * With PHP5 you can also access the filtered variables simply as
  * $_GET->int->varname  and  $_GET->int["varname"] instead of just
  * with the ordinary method $_GET->int("varname") way. PHP filter_
  * extension methods can be used with the method syntax only.
  *
  *
  * Input validation of course is no substitute for secure application
  * logic, parameterized sql and proper output encoding. But this
  * method is a good start, and streamlines input data handling.
  *
  */



/**
 * @package Request variable input wrapper.
 *
 */  
class input {


    /**
     * previous suberglobal input array
     * @var array
     * @access private
     */
    var $vars;
    
    
    /**
     * Initialize object from
     * @param array  one of $_REQUEST, $_GET or $_POST etc.
     */
    function __construct($in) {
    
        # save superglobal
        $this->vars = (array)$in;

        # provides convenience access ->filter->var and ->filter["trick"]
        foreach (get_class_methods(__CLASS__) as $sub) {
            $this->{$sub} = new input___sub($this, "$sub");
        }
    }
    
    
    /**
     * Generic array features. (has no keys)
     *  ->has(isset)  ->no(empty)  ->keys()
     */
    function has($name) {
        return isset($this->vars[$name]);
    }
    function no($name) {
        return empty($this->vars[$name]);
    }
    function keys($name) {
        return array_keys($this->vars);
    }
   


    
    

    
    #--- sanitization functions ---



    # this should obviously be avoided
    function raw($name) {
        trigger_error("Unfiltered input variable '$name' accessed.", E_USER_NOTICE);
        return $this->vars[$name];
    }

    # integer
    function int($name) {
        return (int)$this->vars[$name];
    }
    
    # proper identifiers (e.g. var names, only letters)
    function name($name) {
        return preg_replace("/[^\w_]+/", "", $this->vars[$name]);
    }
    
    # human-readable ascii text without control characters
    function text($name) {
        return preg_replace("/[^\w\d\s,._]+/U", "", strip_tags($this->vars[$name]));
    }

    # regular expression filter / or data match
    function regex($name, $rx="", $match=1) {
        # validating
        if (strpos($rx, "(")) {
            if (preg_match($rx, $this->vars[$name], $result)) {
                return($result[$match]);
            }
        }
        # cropping
        elseif (strpos($rx, "[^")) {
            return preg_replace($rx, "", $this->vars[$name]);
        }
    }
    
    # max length string
    function length($name, $max=65535) {
       return substr($this->text($name), 0, $max);
    }
    
    
    
    #--- custom functions ---
    
    
    
    # escape for concatenating data into sql query (= not good, folks!)
    function sql($name) {
        trigger_error("SQL escaping of input variable '$name'. Use of parameterized SQL is recommended for speed and security reasons.", E_USER_NOTICE);
        return mysql_real_escape_string/*seriously?!*/($this->vars[$name]);
    }
    
    # identifiers with underscores and dots, like "xvar.1_2.x"
    function id($name) {
        return preg_replace("#(^[^a-z_]+)|[^\w\d_.]+|([^\w_]$)#i", "", $this->vars[$name]);
    }
    

    
    // function email($name) { ... }   // provided by filter extension

    // function url($name) {  return preg_replace("/[^-\w\d\$.+!*'(),{}\|\\~\^\[\]\`<>#%\";\/?:@&=]+/", "", $this->vars[$name]); }

    // function json($name) { ... }
    
    // function datetime($name) { ... }  // as in HTML5
    
    /*function html($name) {
        $h = new HTML_Purifier;
        return $h->purify( $this->vars[$name] );
    }*/
    


    #--- application logic tailored ---


    /*function category_id($name) {
        $s = $this->name(vars[$name]);
        if (!isset($GLOBALS["app_config"]["categories"][$s])) {
            error_log("Security breach: User tried access with invalid &category= parameter, {$_SERVER->text(REMOTE_ADDR)}", 0);
        }
        else return $s;
    }*/
    
    // function session_id($name) { ... }  // e.g. verify last IP, stale session, user-agent

    // function range($name, $min, $max) { ... } //


    
    
    
    #--- array variants ---
    
    
    
    # input variable is an array of integers
    function array_int($name) {
        return $this->array_($name, "intval");
    }
    function array_($name, $func) {
        $tmp = (array)($this->vars[$name]);
        foreach ($tmp as $i=>$v) {
            $tmp[$i] = $func($v);
        }
        return $tmp;
    }
    
   
    
    
    #--- magic functions ---
    
    
    /**
     * If a bare variable access $_SERVER->SERVER_NAME occours,
     * refer to ->name() because this is the most commonly desired effect.
     */
    function __get($name) {
        return $this->name($name);
    }

    
    /**
     * Unkown methods are just passed on to the native PHP filter extension,
     * use ->array_WHATEVER() for recursive sanitiziation
     * or ->filter_validate_thingy() for native filter names
     */
    function __call($method, $args) {

        $map = array(
            "float" => "filter_number_float",
            "ip" => "filter_validate_ip",
            "hex" => array("filter_validate_int", "filter_flag_allow_hex"),
        );
        $name = $args[0];
        $flags = isset($args[1]) ? $args[1] : 0;
        $array_walk = (0 == strncmp($method, "array_", 6)) && ($method = substr($method, 6));

        # defer filter method
        if (isset($map[$method])) {
            $filter = $map[$method];
            if (is_array($filter)) {
                list($filter, $flags) = $filter;
            }
            $filter = strtoupper($filter);
            $flags = strtoupper($flags);
        }
        else {
            $filter = strtoupper($method);
            if (strpos($method, "validate") !== false) {
                $filter = "FILTER_SANITIZE_" . $filter;
            }
        }
       
        # whichnow?
        $filter_id = defined($filter) ? constant($filter) : filter_id($method);
        $flags_id = is_int($flags) ? $flags : (strlen($flags)>2 ? constant($flags) : 0);
        /* int, boolean, float, validate_url, validate_email, validate_ip,
        string, stripped, encoded, special_chars, unsafe_raw, email, url,
        number_int, number_float, magic_quotes */

        # pass on
        if ($filter_id === false) {
            trigger_error("no filter '$method'", E_USER_ERROR);
        }
        elseif ($array_walk) {
            $tmp = $this->vars[$name];
            foreach ($tmp as $i=>$v) {
                filter_var($tmp[$i], $filter_id, $flags_id);
            }
            return $tmp;
        }
        else {
            return filter_var($this->vars[$name], $filter_id, $flags_id);
        }

    }


}


/**
 * Allows additional access methods to input variables:
 *   $_REQUEST->name->VARNAME
 * and:
 *   $_REQUEST->name["invar"]
 *
 * @subpackage methodarray
 */
class input___sub implements ArrayAccess {
    function __construct($parent, $func) {
        $this->parent = $parent;
        $this->func = $func;
    }
    function __get($name) {
        return $this->parent->{$this->func}($name);
    }
    function offsetExists($name) { 
        return isset($this->parent->vars[$name]);
    }
    function offsetGet($name) {
        return $this->__get($name);
    }
    function offsetSet($name, $value) { /*forget it*/}
    function offsetUnset($name) { 0; }
}





/**
 * @code Initialize automatically.
 *
 */

$_SERVER = new input($_SERVER);
$_REQUEST = new input($_REQUEST);
$_GET = new input($_GET);
$_POST = new input($_POST);
$_COOKIE = new input($_COOKIE);
#$_SESSION = new input($_SESSION);
#$_ENV = new input($_ENV);
#$_FILES cannot be used that way

?>

Deleted ext/contrib/pdo-2006-01-29.tar.gz.

cannot compute difference between binary files

Added ext/contrib/php4_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, similiar to Javas. 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 you'd 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 similiar 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("$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")) {
   // quick hack, should use a different func name
   function set_exception_handler($func) {
      global $_EXCEPTION;
      $_EXCEPTION = $func;
   }
}


?>

Added ext/contrib/php5_clone.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
<?php
/**
 * Some functions from PHP5, that aren't actually senseful to replicate
 * for PHP4. The new native object semantics cannot be emulated anyhow.
 *
 * - see also ext/contrib/exceptions.php
 *
 */



 
/**
 * Make a real object copy. This is a token in PHP5, not a function.
 *
 * Uses serialize-trick from PHP_Compat, because PHP4 references can
 * neither be detected nor resolved otherwise.
 *
 * @stub
 * @since 5.0
 */
if (!function_exists("clone") && PHP_VERSION < "5.0") {
   eval('
   function clone($obj) {
   
      // this however duplicates sub-objects and arrays too
      $new = unserialize(serialize(($obj));
     
      if (method_exists($new, "__clone")) {
         $new->__clone();
      }

      return $new;
   }
   ');
}


?>

Deleted ext/contrib/php5oo.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
<?php
/**
 * Some functions from PHP5, that aren't actually senseful to replicate
 * for PHP4. The new native object semantics cannot be emulated anyhow.
 *
 * - see also ext/contrib/exceptions.php
 *
 */



 
/**
 * Make a real object copy. This is a token in PHP5, not a function.
 *
 * Uses serialize-trick from PHP_Compat, because PHP4 references can
 * neither be detected nor resolved otherwise.
 *
 * @stub
 * @since 5.0
 */
if (!function_exists("clone") && PHP_VERSION < "5.0") {
   eval('
   function clone($obj) {
   
      // this however duplicates sub-objects and arrays too
      $new = unserialize(serialize(($obj));
     
      if (method_exists($new, "__clone")) {
         $new->__clone();
      }

      return $new;
   }
   ');
}


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














































































Deleted ext/contrib/phprequest.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
<?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");
      $_POST = fread($f, 1<<22);
      fclose($f);
   }

   #-- uncompress and decode, if something found
   if ($_POST) {

      #-- strip known/supported encodings
      $enc = trim(strtok(strtolower($_SERVER["HTTP_CONTENT_ENCODING"]), ",;"));
      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) {
         $_POST = unserialize($_POST);
      }
      #-- merge
      if ($_POST) {
         $_REQUEST = array_merge($_REQUEST, $_POST);
      }

   }
}

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








































































































Deleted ext/contrib/xmlrpc.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
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
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
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
965
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
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
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
<?php define("XMLRPC_VERSION", "0.3.10");
# 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
#
#  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
#     XXXXXXX   MMMMM MMMMM LLL      +++     RRR   RRR PPP   PPP CCC    CCC
#      XXXXX    MMMMMMMMMMM LLL  +++++++++++ RRR   RRR PPP   PPP CCC
#       XXX     MMM MMM MMM LLL  +++++++++++ RRRRRRRR  PPPPPPPP  CCC
#      XXXXX    MMM  M  MMM LLL      +++     RRRRRRR   PPPPPPP   CCC
#     XXXXXXX   MMM     MMM LLL      +++     RRR  RRR  PPP       CCC    CCC
#    XXXX XXXX  MMM     MMM LLLLLLL          RRR   RRR PPP       CCCCCCCCC
#   XXXX   XXXX MMM     MMM LLLLLLL          RRR   RRR PPP        CCCCCCC
#
#  This is Public Domain. (c) 2004 WhoEver wants to. [milky*erphesfurt·de]


#-- config
define("XMLRPC_PLUS", 0);        # use XML+RPC per default
define("XMLRPC_AUTO_TYPES", 0);  # detect base64+datetime strings and automatically generate the according xmlrpc object representations then
define("XMLRPC_AUTO_UTF8", 1);   # de/convert anything from and to UTF-8 automatically - if yourscripts use Latin1 natively, but the RPC server expects/sends UTF-8
define("XMLRPC_CHARSET", "utf-8");  # used in responses and requests
define("XMLRPC_AUTODISCOVERY", 0);  # "connections" automatically create methods
define("XMLRPC_FAST", 1);        # use PHPs XML-RPC extension where possible
define("XMLRPC_OO", 1);          # return XML-RPC/HTTP errors as objects
define("XMLRPC_DEBUG", 0);       # output error hints, write /tmp dumps - set this to 1, 2 or 3

#-- _server() settings
define("XMLRPC_LOG", "/tmp/xmlrpc.".@$_SERVER["SERVER_NAME"].".log");

#-- general data
#  (don't change the following, most are auto-configured values)
define("XMLRPC_UA", "xml+rpc/".XMLRPC_VERSION." (PHP/".PHP_VERSION."; ".PHP_OS.")");
define("XMLRPC_MIME_NEW", "application/rpc+xml");
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                                                             #
#                                                                          #
############################################################################


#-- Issue a request, call can take any number of arguments.
#     $result = xmlrpc("http://example.com/RPC2/", "method1", $arg1 ...);
#     $result = xmlrpc("xml+rpc://here.org/RPC3/", "ns.function", ...);
#   Results automatically have <datetime> values converted into Unix
#   timestamps and <base64> unpacked into strings.
#
function xmlrpc($server, $method=NULL /*, ... */) {
   if ($method) {
      $params = func_get_args();
      shift($params); shift($params);
      return
        xmlrpc_request($server, $method, $params);
   }
   else {
      return
        new xmlrpc_connection($server);
   }
}



#--  Generate and send request, decode response.
function xmlrpc_request($url, $method, $params=array(), $plus=XMLRPC_PLUS, $gzip=0) {
   global $xmlrpc_response_headers, $xmlrpc_error;
   
   #-- init whole lib for request (we are not-OO here)
   $xmlrpc_error = false;
   $xmlrpc_response_headers = array();
   
   #-- encapsulate req, transmit it
   $socket = xmlrpc_request_send($url, $method, $params, $plus, $gzip);
   if (!$socket) {
      return xmlrpc_error(-32768, "no connection", 0, "GLOBALVARS");
   }

   #-- wait for, read response
   $response = "";
   while (!feof($socket) && (strlen($DATA) <= 768<<10)) {
      $response .= fread($socket, 4<<10);
   }
   fclose($socket);
   if (XMLRPC_DEBUG >= 3) {
      echo "<code>$response</code>";
   }

   #-- decode answer and give results
   return xmlrpc_response_decode($response);
}


#-- an alias
function xmlrpc_call($url, $method, $params=array(), $plus=XMLRPC_PLUS, $gzip=0) {
   return xmlrpc_request($url, $method, $params, $plus, $gzip);
}



#-- marshall request parameters into array, hash, xml string
function xmlrpc_request_send($url, $method, &$params, $plus, $gzip, $blocking=true) {

   #-- get connection data
   $c = parse_url($url);
   ($host = $c["host"]);
   ($port = @$c["port"]) or ($port = 80);
   ($path = $c["path"]) or ($path = "/");
   if (strpos($c["scheme"], "+")) {
      $plus++;
   }
   if (strpos($c["scheme"], "gzip")) {
      $gzip++;
   }
   if (!$host) { return(NULL); }
   $inj = "";
   if ($str = $c["user"]) {
      if ($c["pass"]) { $str .= ":" . $c["pass"]; }
      $inj = "Authorization: Basic " . base64_encode($str) . "\n";
   }
   
   #-- mk request HTTP+XML block from params
   $request = xmlrpc_request_marshall($method, $params);
   $request = xmlrpc_request_http($request, $path, $host, $plus, $gzip, $inj);

   #-- connect, send request
   if ($socket = fsockopen($host, $port, $io_err, $io_err_s, 30)) {
      socket_set_blocking($socket, $blocking);
      socket_set_timeout($socket, 17, 555);
   }
   else {
      echo "Could not connect to '<b>$host</b>:$port$path' - error $io_err: $io_err_s.<br>\n";
      return(NULL);
   }
   fputs($socket, $request);

   #-- done here
   return($socket);
}


#-- marshall function call into XML+HTTP string
function xmlrpc_request_marshall($method, &$params) {

   #-- use xmlrpc-epi
   if (XMLRPC_FAST && XMLRPC_EPI) {
      $query = xmlrpc_encode_request($method, $params);
      return($query);
   }

   #-- build query
   $query = array(
      "methodCall" => array(
         "methodName" => array( ",0"=>$method ),
         "params" => array()
      )
   );
   foreach ($params as $i=>$p) {
      $query["methodCall"]["params"]["param,$i"] = xmlrpc_compact_value($p);
   }
   $query = array2xml($query, 1, 'encoding="'.XMLRPC_CHARSET.'" ');

   #-- encode?
   if (XMLRPC_AUTO_UTF8) {
      $query = utf8_encode($query);
   }
   
   return($query);   
}


#-- enclose body into HTTP request string
function xmlrpc_request_http(&$query, $path, $host, $plus, $gzip, $inj_header="") {

   #-- build request
   $n = "\015\012";
   $request = "POST $path HTTP/1.0$n"
            . "Host: $host$n"
            . ($inj_header ? str_replace("\n", $n, $inj_header) : "")
            . "User-Agent: " . XMLRPC_UA . "$n"
            . "Accept: ".XMLRPC_ACCEPT."$n"
            . (!XMLRPC_DEBUG ? "Accept-Encoding: deflate$n" : "")
            . "Content-Type: ".($plus ? XMLRPC_MIME_NEW : XMLRPC_MIME_OLD)
                              ."; charset=".XMLRPC_CHARSET."$n";

   #-- compress?
   if ($gzip) {
      $query = gzdeflate($query);
      $request .= "Content-Encoding: deflate$n";
   }
   $request .= "Content-Length: " . strlen($query) . "$n" . "$n";
   $request .= $query . "$n";

   return($request);
}


#-- unpack response from HTTP and XML representation
function xmlrpc_response_decode(&$response) {
   global $xmlrpc_response_headers;

   #-- split into headers and content
   $l1 = strpos($response, "\n\n");
   $l2 = strpos($response, "\n\r\n");
   if ($l2 && (!$l1 || ($l2<$l1))) {
      $head = substr($response, 0, $l2);
      $response = substr($response, $l2+3);
   }
   else {
      $head = substr($response, 0, $l1);
      $response = substr($response, $l2+2);
   }

   #-- decode headers, decompress body
   foreach (explode("\n", $head) as $line) {
      $xmlrpc_response_headers[strtolower(trim(strtok($line, ":")))] = trim(strtok("\000"));
   }
   if ($enc = trim(@$xmlrpc_response_headers["content-encoding"])) {
      if (($enc == "gzip") || ($enc == "x-gzip")) {
         $response = gzinflate(substr($response, 10, strlen($response)-18));
      }
      elseif (($enc == "compress") || ($enc == "x-compress")) {
         $response = gzuncompress($response);
      }
      elseif (($enc == "deflate") || ($enc == "x-deflate")) {
         $response = gzinflate($response);
      }
   }

   $r = xmlrpc_response_unmarshall($response);
   if (XMLRPC_DEBUG) {var_dump($r);}
   return($r);
}


#-- decode XML-RPC from string into array and extract its actual meaning
function xmlrpc_response_unmarshall(&$response) {
   global $xmlrpc_response_headers;

   #-- strip encoding
   if (XMLRPC_AUTO_UTF8) {
      xmlrpc_decode_utf8xml($response, @$xmlrpc_response_headers["content-type"].@$xmlrpc_response_headers["content-charset"]);
   }

   if (XMLRPC_DEBUG >= 4) { fwrite(fopen("/tmp/xmlrpc:resp_in_xml","w"), $response); }
   
   #-- use xmlrpc-epi
   if (XMLRPC_FAST && XMLRPC_EPI) {
      $r = xmlrpc_decode_request($response, $uu);
      xmlrpc_epi_decode_xtypes($r);
      if (is_array($r) && (count($r)==2) && isset($r["faultCode"]) && isset($r["faultString"])) {
         return xmlrpc_error($r["faultCode"], $r["faultString"], 1, "GLOBALVARS");
      }
      else {
         return($r);
      }
   }


   #-- unmarshall XML
   $response = xml2array($response);

   #-- fetch content (one returned element)
   if ($r = @$response["methodResponse,0"]["params,0"]["param,0"]["value,0"]) {
      $r = xmlrpc_decode_value($r);
      return($r);
   }
  
   #-- error cases
   #  (we should rather return an error object here)
   if (($r = @$response["methodResponse,0"]["fault,0"]["value,0"]) && ($r = xmlrpc_decode_value($r))) { 
      return xmlrpc_error($r["faultCode"], $r["faultString"], 1, "GLOBALVARS");
   }
   else {
      return xmlrpc_error(-32600, "xml+rpc: invalid response", 0, "GLBLVRS");
   }
   return(NULL);
}



#-- Establish a virtual XML+RPC or XML-RPC server connection (a pseudo
#   handshake is used to determine supported protocol / extensions).
class xmlrpc_connection {

   #-- init
   function xmlrpc_connection($url, $autodiscovery=0) {
      global $xmlrpc_response_headers;
      $this->server = $url;
      $this->plus = 0;
      $this->gzip = 0;

      #-- handshake to check supported protocol
      $funcs = $this->call("system.getVersion");
      $this->plus = (strpos($xmlrpc_response_headers["accept"], XMLRPC_MIME_NEW) !== false);
      $this->gzip = (strpos($xmlrpc_response_headers["accept_encoding"], "deflate") !== false);
      
      #-- auto-discovery, create 'method' names
      if ($funcs && (XMLRPC_AUTODISCOVERY || $autodiscovery)) {
         foreach ($funcs as $fn) {
            $short = $fn;
            if ($l = strpos($fn, ".")) {
               $short = substr($fn, $l + 1);
               if (substr($fn, 0, $l) == "system") { continue; }
            }
            $this->short = create_function("", "return xmlrpc_request('{$this->server}','$fn',func_get_args(),{$this->plus},{$this->gzip});");
         }
      }
   }
   
   #-- generical call (needs func name)
   function call($method /*, ... */) {
      $params = func_get_args();
      shift($params);
      $r = xmlrpc_request($this->serverm, $method, $params, $this->plus, $this->gzip);
      return($r);
   }
}

#-- an alias
class xmlrpc extends xmlrpc_connection {
}




############################################################################
#                                                                          #
#  server implementation                                                   #
#                                                                          #
############################################################################


#-- Check request and execute function if registered in $xmlrpc_methods[]
#   array.
function xmlrpc_server() {

   global $xmlrpc_methods;

   #-- server is active
   define("XMLRPC_SERVER", getmypid());
   if (XMLRPC_DEBUG) { error_reporting(E_ALL^E_NOTICE); }
   ob_start();

   #-- standard reply headers
   header("Accept: ".XMLRPC_MIME_NEW.", ".XMLRPC_MIME_OLD."; q=0.5");
   header("Accept-Encoding: deflate");
   header("X-Server: " . XMLRPC_UA);
   header("Connection: close");
   header("Cache-Control: private");

   #-- fixes for PHP/Apache
   if (function_exists("getallheaders")) {
      foreach (getallheaders() as $i=>$v) {
         $_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");
      }
   }
   if (!($xml_request = xmlrpc_fetch_post_chunk())) {
      header("Status: 500 How Sad");
      die("<h2>Error</h2>Could not fetch POST data.\n");
   }

   #-- decipher incoming XML request string
   $method = "";
   if (XMLRPC_FAST && XMLRPC_EPI) {
      $params = xmlrpc_decode_request($xml_request, $method);
      xmlrpc_epi_decode_xtypes($params);
   }
   else {
      $params = xmlrpc_request_unmarshall($xml_request, $method);
   }

   
   #-- add the few system.methods()
   //if (empty($xmlrpc_methods)) {
   //   $xmlrpc_methods = get_defined_functions();
   //}
   $xmlrpc_methods["system"] = "xmlrpc_system_methods";   # a class

   #-- call
   $result = xmlrpc_exec_method($method, $params);

   #-- send back result
   if (isset($result)) {
      if (isset($result)) {
         $resp["methodResponse"]["params"]["param"] = xmlrpc_compact_value($result);
      }
      else {
         $resp["methodResponse"]["params"] = array();
      }

      xmlrpc_send_response($resp);
   }
   else {
      $result = xmlrpc_error(0, "No Result");
      xmlrpc_send_response($result);
   }
}



#-- 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"];
   if (!$call) {
      xmlrpc_send_response(xmlrpc_error(-32600, "Bad Request, <methodCall> missing"));
   }
   $method = $call["methodName,0"][",0"];
   if (!$method) {
      xmlrpc_send_response(xmlrpc_error(-32600, "Bad Request, <methodName> missing"));
   } 

   $params = array();
   foreach ($call["params,1"] as $uu => $param) {
      $params[] = xmlrpc_decode_value($param["value,0"]);
   }

   return($params);
}



#-- Call the requested method (using the XML-method to PHP-function mapping
#   table and hints).
function xmlrpc_exec_method($method, $params) {

   global $xmlrpc_methods;
   if (XMLRPC_DEBUG >= 2) { error_reporting(E_ALL^E_NOTICE); }

   #-- check if allowed call
   $rf = strtr($method, ".", "_");
   $cl = strtok($method, ".");
   if (!$xmlrpc_methods[$method] && !$xmlrpc_methods[$cl]
      && !in_array($method, $xmlrpc_methods)
      && !in_array($rf, $xmlrpc_methods) && !in_array($cl, $xmlrpc_methods) )
   {
      xmlrpc_send_response(xmlrpc_error(-32601));
   }

   #-- real function call
   if ($php_func_name = $xmlrpc_methods[$method]) {
      $rf = $method = $php_func_name;
   }
   if (function_exists($rf)) {
      $result = call_user_func_array($rf, $params);
      if (XMLRPC_DEBUG >= 4) { fwrite(fopen("/tmp/xmlrpc:func_call_res","w"),serialize(array($rf,$result,$params))); }
      return($result);
   }
   #-- PHP object method calls
   else {
      $class = strtok($method, ".");
      $method = strtok("\000");
      if ($uu = $xmlrpc_methods[$class]) {
         $class = $uu;
      }
      if ($class && class_exists($class) && $method) {
         $obj = new $class;
         if (method_exists($obj, $method)) {
            $result = call_user_method_array($method, $obj, $params);  //<DEPRECATED>
            return($result);
         }
      }
   }

   #-- else error
   xmlrpc_send_response(xmlrpc_error(-32601));
}



#-- Get POST data from PHP (if it gives it to us).
function xmlrpc_fetch_post_chunk() {
   global $HTTP_RAW_POST_DATA;

   $data = false;
   if ($f = fopen("php://input", "rb")) {
      $data = fread($f, 0x0100000);
      fclose($f);
   }
   if (empty($data)) {
      ini_set("always_populate_raw_post_data", "true");  // well, maybe(!?)
      $data = $HTTP_RAW_POST_DATA;
      $HTTP_RAW_POST_DATA = "";
   }
   $enc = trim(strtolower($_SERVER["HTTP_CONTENT_ENCODING"]));
   $funcs = array("deflate"=>"gzinflate", "gzip"=>"gzdecode", "compress"=>"gzuncompress", "x-gzip"=>"gzdecode", "x-bzip2"=>"bzuncompress");
   if ($enc && ($pf = $funcs[$enc]) && function_exists($pf)) {
      $data = $pf($data);
   }
   return($data);
}


#-- converts UTF-8 documents into Latin-1 ones
function xmlrpc_decode_utf8xml(&$xml, $ct) {
   if (strpos(strtolower($ct), "utf-8") or preg_match('/<\?xml[^>]+encoding=["\']utf-8/i', $xml)) {
      $xml = utf8_decode($xml);
      $xml = preg_replace('/(<\?xml[^>]+encoding=["\'])utf-8(["\'])/i', '$1iso-8859-1$2', $xml, 1);
   }
}



#-- Creates an error object.
function xmlrpc_error($no=-32500, $str="", $type=1, $into_vars=0) {
   global $xmlrpc_error, $xmlrpc_errorcode;
   $errors = array(
           0 => "No Result",
      -32300 => "Transport error",
      -32400 => "Internal Server Error",
      -32500 => "Application error",
      -32600 => "Invalid message format / Bad request",
      -32601 => "Method does not exist",
      -32602 => "Parameter type mismatch",
      -32603 => "Internal XML-RPC error",
      -32604 => "Too many parameters",
      -32700 => "Not well-formed XML",
      -32701 => "Unsupported encoding - only ISO-8859-1 and UTF-8 capable",
      -32702 => "Invalid characters, encoding mismatch",
   );
   #-- build response xml/array
   if (!($str) && !($str = $errors[$no])) {
      $str = "Unknown Error";
   }
   if ($into_vars && !XMLRPC_OO) {
      $xmlrpc_error = $str;
      $xmlrpc_errorcode = $no;
      return(NULL);
   }
   else {
      return new xmlrpc_error($no, $str, $type);
   }
}


#-- error object
class xmlrpc_error {

   var $type = 1;   // else an HTTP error
   var $no;
   var $str;
   
   function xmlrpc_error($no, $str, $type=1) {
      $this->type = $type;
      $this->no = $no;
      $this->str = $str;
   }
   
   function send() {
      $error = xmlrpc_compact_value(array(
         "faultCode" => $no,
         "faultString" => $str,
      ));
      $resp = array(
         "methodResponse" => array(
            "fault" => $error
         )
      );
      xmlrpc_send_response($resp);
   }
}


#-- Sends a response.
function xmlrpc_send_response($r) {

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

   #-- compress answer?
   if (!headers_sent()) {
      $enc = trim(strtolower($_SERVER["HTTP_ACCEPT_ENCODING"]));
      $funcs = array("deflate"=>"gzdeflate", "gzip"=>"gzencode", "compress"=>"gzcompress", "x-gzip"=>"gzencode", "x-bzip2"=>"bzcompress");
      if ($enc && ($pf = $funcs[$enc]) && function_exists($pf)) {
         header("Content-Encoding: $enc");
         $r = $pf($r);
      }
   }

   #-- send
   if (ob_get_level()) {
      #-- this prevents that PHP errors appear as garbage in our response
      $add .= "<!--\n" . ob_get_contents() . "\n-->";
      ob_end_clean();
   }
   header("Content-Length: " . strlen($r));
   print $r . $add;
   die;
}



#-- Provides "system.*" method namespace.
class xmlrpc_system_methods {

   function listMethods() {
      global $xmlrpc_methods;
      $r = array();
      foreach ($xmlrpc_methods as $i=>$i2) {
         $real = is_int($i) ? $i2 : $i;
         if (class_exists($real) && ($i2=$real) || class_exists($i2)) {
            foreach (get_class_methods($i2) as $add) {
               $r[] = $real.".".$add;
            }
         }
         else {
            $r[] = $real;
         }
      }
      return($r);
   }

   function time() {
      return new xmlrpc_datetime(time());
   }
}


############################################################################
#                                                                          #
#  misc functions                                                          #
#                                                                          #
############################################################################


function xmlrpc_log($message) {
}

function xmlrpc_die($error="", $str="") {
}



############################################################################
#                                                                          #
#  data representation mangling                                            #
#                                                                          #
############################################################################


#-- Makes compact-array2xml datavar from a PHP variable.
function xmlrpc_compact_value($var, $n=0) {

   #-- create compact-array2xml tree
   $root = array(
      "value,$n" => array(),
   );
   $r = &$root["value,$n"];

   #-- detect PHP values to be complex types in XML-RPC
   if (XMLRPC_AUTO_TYPES && is_string($var)) {
      if ((strlen($var) >= 64) && preg_match('/^[\w]+=*$/', $var)) {
         $var = new xmlrpc_base64($var);
      }
      elseif ((strlen($var)==17) && ($var[8]=="T") && preg_match('/^\d{8}T\d\d:\d\d:\d\d$/', $var)) {
         $var = new xmlrpc_datetime($var);
      }
   }

   #-- complex types
   if (is_object($var)) {
      $r = $var->out();
   }
   #-- arrays and hashes(structs)
   elseif (is_array($var)) {
      if (isset($var[0]) || empty($var)) {
         $r = array("array,$n" => array("data,0" => array()));
         $r = &$r["array,$n"]["data,0"];
         foreach ($var as $n=>$val) {
            $r = array_merge($r, xmlrpc_compact_value($val, $n));
         }
      }
      else {
         $r = array("struct,$n"=>array());
         $r = &$r["struct,$n"];
         $n = 0;
         foreach ($var as $i=>$val) {
            $r["member,$n"] = array_merge(array(
               "name,0" => array(",0" => "$i"),
            ), xmlrpc_compact_value($val, 1));
            $n++;
         }
      }
   }
   #-- simple types
   elseif (is_bool($var)) {
      $r = array(
         "boolean,$n" => array(",0" => ($var?1:0)),
      );
   }
   elseif (is_int($var)) {
      $r = array(
         "int,$n" => array(",0" => $var),
      );
   }
   elseif (is_float($var)) {
      $r = array(
         "double,$n" => array(",0" => $var),
      );
   }
   elseif (is_string($var)) {
      $r = array(
         "string,$n" => array(",0" => $var),
      );
   }
   return($root);
}


#-- Makes a PHP array from a compact-xml2array representation. $value must
#   always be the xml2array elements _below_ the ["value,0"] or ["data,0"]
#   or ["member,N"] entry.
function xmlrpc_decode_value($value) {
   $val = NULL;
   foreach ($value as $i=>$d) {

      #-- use single (text) content xml2array entry as actual $d var
      if (is_array($d) && isset($d[",0"])) {
         $d = $d[",0"];
      }

      #-- convert into PHP var based on type
      $type = strtok($i, ",");
      switch ($type) {

         case "array":
            $val = array();
            foreach ($d["data,0"] as $i=>$value) {
               $val[] = xmlrpc_decode_value($value);
            }
            break;

         case "struct":
            $val = array();
            foreach ($d as $uu=>$d2) {
               if (($in=$d2["name,0"][",0"]) && ($pos2=1) || ($in=$d2["name,1"][",0"]) && ($pos2=0)) {
                  $val[$in] = xmlrpc_decode_value($d2["value,$pos2"]);
               }
            }
            break;

         case "":    # handles also '<value>s</value>' instead
         case "0":   # of '<value><string>s</string></value>'
         case "string":
            $val =  is_array($d) ? "" : (string)$d;
            break;

         case "base64":
            $val = (XMLRPC_AUTO_TYPES>=2) ? base64_decode($d) : (string)$d;
            if ((XMLRPC_AUTO_UTF8 >= 2) && ($uu = utf8_decode($val))) {
               $val = $uu;
            }
            break;
            
      // case "real":  case "float":   // neither is allowed
         case "double":
            $val = (double)$d;
            break;
         case "i4":
         case "int":
            $val = (int)$d;
            break;

         case "boolean":
            $val = (boolean)$d;
            break;

         case "dateTime.iso8601":
            $val = xmlrpc_strtotime($d);
            break;

         default:
            if (defined("XMLRPC_SERVER")) {
               xmlrpc_send_response(xmlrpc_error(-32600, "Unknown data type '$type'"));
            }
            else {
               echo $xmlrpc_error = "UNKNOWN XML-RPC DATA TYPE '$type'<br>\n";
               $xmlrpc_errorcode = -32207;
            }
#           echo "<!-- UNKNOWN TYPE $type -->\n";
#           xmlrpc_log("bad data type '$type' enountered");
      }
   }
   return($val);
}


#-- More complex XML-RPC data types need object representation to
#   distinguish them from ordinary string and integer vars.
class xmlrpc_xtype {
   var $scalar = "";
   var $xmlrpc_type = "string";
   var $tag = "string";
   function xmlrpc_type($str) {
      $this->data = $str;
   }
   function out() {
      return array($this->tag.",0" => array(",0"=>$this->scalar));
   }
}
class xmlrpc_base64 extends xmlrpc_xtype {
   function xmlrpc_base64($str) {
      $this->tag = "base64";
      $this->xmlrpc_type = "base64";
      if (XMLRPC_AUTO_UTF8 >= 2) {
         $str = utf8_encode($str);
      }
      if (!preg_match("/^[=\w\s]+$/", $str)) {
         $this->encode=1;
      }
      $this->scalar = $str;
   }
   function out() {
      if (isset($this->encode)) {
         $this->scalar = chunk_split(base64_encode($this->scalar), 74, "\n");
      }
      return xmlrpc_xtype::out();
   }
}
class xmlrpc_datetime extends xmlrpc_xtype {
   function xmlrpc_datetime($t) {
      $this->tag = "dateTime.iso8601";
      $this->xmlrpc_type = "datetime";
      if (($t > 0) && ($t[8] != "T")) {
         $this->timestamp = $t;
         $t = xmlrpc_timetostr($t);
      }
      $this->scalar = $t;
   }
}

#-- Further simplify use of the above ones.
function xmlrpc_base64($string) {
   return(new xmlrpc_base64($string));
}
function xmlrpc_datetime($timestr) {
   return(new xmlrpc_datetime($timestr));
}


#-- Deciphers ISO datetime string into UNIX timestamp.
function xmlrpc_strtotime($str) {
   $tm = explode(":", substr($str, 9));
   $t = mktime($tm[0], $tm[1], $tm[2], substr($str, 4, 2), substr($str, 6, 2), substr($str, 0, 4));
   return($t);
}
function xmlrpc_timetostr($time) {
   return(gmstrftime("%Y%m%dT%T", $time));
}


#-- helping hand for the xmlrpc-epi extension of php
function xmlrpc_epi_decode_xtypes(&$r) {
   if (is_object($r) && isset($r->xmlrpc_type)) {
      if (isset($r->timestamp)) {
         $r = $r->timestamp;
      }
      else {
         $r = $r->scalar;
      }
   }
   elseif (is_array($r)) {
      foreach ($r as $i=>$v) {
         xmlrpc_epi_decode_xtypes($r[$i]);
      }
   }
}




############################################################################
#                                                                          #
#  simplified XML parser                                                   #
#                                                                          #
############################################################################


#-- Encode the two chars & and < into htmlentities (there is nothing said
#   about the possible other entities in the XML-RPC spec).
function xml_entities($str) {
   $e = array(
      "&" => "&amp;",
      "<" => "&lt;",
//      ">" => "&gt;",
   );
   return(strtr($str, $e));
}
function xml_decode_entities($str) {
   $e = array(
      "&lt;" => "<",
      "&gt;" => ">",
      "&apos;" => "'",
      "&quot;" => '"',
      "&amp;" => "&",
   );
   if (strpos($e, "&#") !== false) {
      $e = preg_replace('/&#(\d+);/e', 'chr($1)', $e);
      $e = preg_replace('/&#x([\da-fA-F]+);/e', 'chr(hexdec("$1"))', $e);
   }
   return(strtr($str, $e));
}


#-- Can split simplified XML into a PHP array structure. The now used
#   'compact' format will yield tag sub arrays with an "*,0" index and
#   just [",0"] for text nodes.
function xml2array($xml, $compact="ALWAYS") {
   $r = array();
   if (function_exists("xml_parser_create") && (strlen($xml) >= 512)) {
      $r = xml2array_php($xml);
   }
   else {
      xml2array_parse($xml, $r, $compact);
   }
   return($r);
}


#-- Recursively builds an array of the chunks fetched via strtok() from
#   the original XML input string.
function xml2array_parse(&$string, &$r, $compact=1) {
   $n = 0;
   do {
      #-- split chunks
      $l = strpos($string, "<");
      $p = strpos($string, ">", $l);
      $text = $attr=$close = $tag = false;
      if ($l === false) {
         $text = $string;
         $string = false;
      }
      else {
         $tag = strtok(substr($string, $l+1, $p-$l-1), " ");
         if ((strncmp($tag, "![CDATA[", 8)==0) && ($p = strpos($string, "]]>", $l))) {
            $text = substr($string, $l+9, $p-$l-9);
         }
         else {
            if ($l) {
               $text = xml_decode_entities(substr($string, 0, $l));
            }
            $attr = strtok("\000");
            $close = $attr && ($attr[strlen($attr)-1]=="/");
            $string = substr($string, $p+1);
         }
      }
      #-- insert text/body content into array
      if (trim($text)) {
#         if ($compact) {
             $r[",$n"] = $text;
#         }
#         else {
#            $r[] = $text;
#         }
         $n++;
      }
      #-- recurse for tags
      if ($tag && ($tag[0] >= 'A')) {    #-- don't read <? <! </ pseudo-tags
#         if ($compact) {
             $r["$tag,$n"] = array();
             $new = &$r["$tag,$n"];
#         } else {
#            $r[] = array($tag => array());
#            $new = &$r[count($r)-1][$tag];
#         }
         if (!$close) {
            xml2array_parse($string, $new, $compact);
         }
         $n++;
      }
      #-- stop if no more tags or content
      if (empty($tag) && empty($text) || empty($string)) {
         $tag = "/";
      }
   } while ($tag[0] != "/");
}


#-- Uses the XML extension of PHP to convert an XML stream into the
#   compact array representation.
function xml2array_php(&$xml, $compact=1) {

   $p = xml_parser_create(xml_which_charset($xml));
   xml_parser_set_option($p, XML_OPTION_CASE_FOLDING, false);
   xml_parser_set_option($p, XML_OPTION_TARGET_ENCODING, "ISO-8859-1");

   xml_parse_into_struct($p, $xml, $struct);

   $a = array();  // will hold all tag nodes
   $tree = array(&$a);  // stack of pointers to last node of any tree level
   $in = &$a;           // pointer to last created node

   foreach ($struct as $t) {
      unset($value);
      extract($t);

      $depth = count($tree) - 1;
      $in = &$tree[$depth];
      $tag .= "," . count($in);
//echo "#$depth, TAG=\"$tag\", TYP=$type, LEV=$level, VAL=$value\n";

      switch ($type[1]) {

         #--  OpEN
         case "p":
            $in[$tag] = array();
            if ($type=="open") {
               $tree[] = &$in[$tag];
            }
            if (isset($value) && trim($value)) {
               $in[$tag][",0"] = $value;
            }
            break;

         #--  CoMPLETE
         case "o":
            $in[$tag] = array();
            if (isset($value) && trim($value)) {
               $in[$tag][",0"] = $value;
            }
            break;

         #--  ClOSE
         case "l":
            array_pop($tree);
            break;

         #--  CdATA - usually just whitespace
         case "d":
            if (isset($value) && trim($value)) {
               $in[",".count($in)] = $value;
            }
            break;
         
         default:
            // case "attribute":
            // and anything else we do not want
      }
      
   }
   
   return($a);
}



function xml_which_charset(&$xml) {
   return( strpos(strtok($xml, "\n"), '-8859-1"') ? "iso-8859-1" : "utf-8" );
}



############################################################################
#                                                                          #
#  simplified XML creator                                                  #
#                                                                          #
############################################################################


#-- This is the opposite of the above xml2array, and can also work with the
#   so called $compact format.
function array2xml($r, $compact=1, $ins="") {
   $string = "<?xml version=\"1.0\" $ins?>";
   array2xml_push($string, $r, $compact);
   return($string);
}


#-- Recursively throws out the XMLified tree generated by the xml2array()
#   'parser' function.
function array2xml_push(&$string, &$r, $compact, $ind=-1) {
   $old_ind = ++$ind - 1;
   if ($old_ind < 0) { $old_ind = 0; }
   foreach ($r as $i=>$d) {
      $d = &$r[$i];
      if (is_scalar($d)) {
         $string .= xml_entities($d);
      }
      elseif (is_array($d)) {
         if ($compact) {
            $i = strtok($i, ","); 
         }
         $ls = str_repeat(" ", $ind);
         $string .= "\n$ls<$i>";
         $string .=  array2xml_push($string, $d, $compact, $ind);
         $ls = str_repeat(" ", $old_ind);
         $string .= "</$i>\n$ls";
      }
   }
}




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










































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted ext/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.


<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




































































































































































































































































































































































































































































































































































































































































































































































































































Changes to ext/ctype.php.

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
   }
   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) {
      $r = true;
      for ($i=0; $i<strlen($text); $i++) {
         $c = ord($text{$i});
         $r = $r and (
                ($c>=65) && ($c<=90)    // A-Z
             or ($c>=97) && ($c<=122)   // a-z
             or ($c>=48) && ($c<=59)    // 0-9
             or ($c>=192)          // Latin-1 letters
         );
      }
      return($r);
   }


   #-- only letters in given string
   function ctype_alpha($text) {
      $r = true;
      for ($i=0; $i<strlen($text); $i++) {
         $c = ord($text{$i});
         $r = $r and (
                ($c>=65) && ($c<=90)    // A-Z
             or ($c>=97) && ($c<=122)   // a-z
             or ($c>=192)          // Latin-1 letters
         );
      }
      return($r);
   }


   #-- only numbers in string
   function ctype_digit($text) {
      $r = true;
      for ($i=0; $i<strlen($text); $i++) {
         $c = ord($text{$i});
         $r = $r and ($c>=48) && ($c<=59);   // 0-9
      }
      return($r);
   }


   #-- hexadecimal numbers only
   function ctype_xdigit($text) {
      $r = true;
      for ($i=0; $i<strlen($text); $i++) {
         $c = ord($text{$i});
         $r = $r and (
                ($c>=48) && ($c<=59)    // 0-9
             or ($c>=65) && ($c<=70)    // A-F
             or ($c>=97) && ($c<=102)   // a-f
         );
      }
      return($r);
   }


   #-- hexadecimal numbers only
   function ctype_cntrl($text) {
      $r = true;
      for ($i=0; $i<strlen($text); $i++) {
         $c = ord($text{$i});
         $r = $r and ($c < 32);
      }
      return($r);
   }


   #-- hexadecimal numbers only
   function ctype_space($text) {
      $r = true;
      for ($i=0; $i<strlen($text); $i++) {
         $c = $text{$i};
         $r = $r and (
              ($c == " ") or ($c == "\240")
           or ($c == "\n") or ($c == "\r")
           or ($c == "\t") or ($c == "\f")
         );
      }
      return($r);
   }


   #-- all-uppercase
   function ctype_upper($text) {
      $r = true;
      for ($i=0; $i<strlen($text); $i++) {
         $c = ord($text{$i});
         $r = $r and (
                ($c>=65) && ($c<=90)    // A-Z
             or ($c>=192) && ($c<=223)  // Latin-1 letters
         );
      }
      return($r);
   }


   #-- all-lowercase
   function ctype_lower($text) {
      $r = true;
      for ($i=0; $i<strlen($text); $i++) {
         $c = ord($text{$i});
         $r = $r and (
                ($c>=97) && ($c<=122)   // a-z
             or ($c>=224) && ($c<=255)  // Latin-1 letters
         );
      }
      return($r);
   }


   #-- everything except spaces that produces a valid printable output
   #   (this probably excludes contral chars as well)
   function ctype_graph($text) {
      $r = true;
      for ($i=0; $i<strlen($text); $i++) {
         $c = ord($text{$i});
         $r = $r
           and ($c>=33)
           and ($c!=160)
           and (($c<=126) or ($c>=161));
      }
      return($r);
   }


   #-- everything printable, but no spaces+letters+digits
   function ctype_punct($text) {
      $r = true;
      for ($i=0; $i<strlen($text); $i++) {
         $c = ord($text{$i});
         $r = $r and (
                ($c>=33) && ($c<=47)   // !../
             or ($c>=58) && ($c<=64)   // :..@
             or ($c>=91) && ($c<=96)   // [..`
             or ($c>=123) && ($c<=126) // {..~
             or ($c>=161) && ($c<=191) // Latin-1 everything else
         );
      }
      return($r);
   }



//   - no idea what this means exactly
//
//   function ctype_print($text) {
//   }


}


</old>***/

?>







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<

41
42
43
44
45
46
47


































































































































































48
   }
   function ctype_print($text) {
      return ctype_punct($text) && ctype_graph($text);
   }

}



































































































































































?>

Deleted 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 these, 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 list 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/nonstandard/base16.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
<?php
/**
 *
 * This script implements the base64-encoding functions and base32 and
 * base16 as described in RFC3548.
 *
 * @since never
 * @nonstandard
 *
 */
if (!function_exists("base16_encode")) {


   #-- URL and filename safe variants of base64-encoding
   function base64_encode_safe($str) {
      return strtr(base64_encode($str), "+/", "-_");
   }
   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,="
   }

}
?>

Deleted ext/nonstandard/base64.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
<?php
/**
 *
 * This script implements the base64-encoding functions and base32 and
 * base16 as described in RFC3548.
 *
 * @since never
 * @nonstandard
 *
 */
if (!function_exists("base16_encode")) {


   #-- URL and filename safe variants of base64-encoding
   function base64_encode_safe($str) {
      return strtr(base64_encode($str), "+/", "-_");
   }
   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/php40array.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
<?php
/**
 *
 *  Extended PHP array functions - _diff and _intersect() for associative
 *  arrays and/or with callback functions (for keys and/or values). These
 *  are too rarely used and exotic to be part of the core "upgrade.php"
 *  script.
 *  
 *  NOTHING IN HERE WAS SERIOUSLY TESTED. Please grab the definitions from
 *  PEAR::PHP_Compat if you want reliable and tested versions.
 *
 *
 *  @group ARRAY_FUNCS_4_0
 *  @since 4.0
 *  @untested
 *
 */


#-- diff associative arrays with two user callbacks
#   (if this looks complicated to you, don't even try to look at the manual)
if (!function_exists("array_udiff_uassoc")) {
   function array_udiff_uassoc() {
      $in = func_get_args();
      $key_cb = array_pop($in);
      $val_cb = array_pop($in);
      $arr1 = array_shift($in);
      $r = array();
      
      foreach ($arr1 as $i=>$v) {
         #-- in each array, compare against each key/value pair
         foreach (array_keys($in) as $c) {
            foreach ($in[$c] as $i2=>$v2) {
               
               $key_cmp = call_user_func_array($key_cb, array($i, $i2));
               if ($key_cmp == 0) {

                  #-- ok, in this case we must compare the data as well
                  $val_cmp = call_user_func_array($val_cb, array($v, $v2));
                  if ($val_cmp == 0) {
                     continue 3;
                  }
               }
            }
         }

         #-- this combination isn't really found anywhere else
         $r[$i] = $v;
      }
      return($r);
   }
}


#-- same, but that keys now are compared normally (without callback)
if (!function_exists("array_udiff_assoc")) {
   function array_udiff_assoc() {
      $in = func_get_args();
      $val_cb = array_pop($in);
      $arr1 = array_shift($in);
      $r = array();
      
      #-- compare against each key/value pair in other arrays
      foreach ($arr1 as $i=>$v) {
         foreach (array_keys($in) as $c) {
            if (isset($in[$c][$i])) {
               #-- now compare data by callback
               $cmp = call_user_func_array($val_cb, array($v, $in[$c][$i]));
               if ($cmp == 0) {
                   continue 2;
               }
            }
         }
         #-- everything exists only in array1
         $r[$i] = $v;
      }
      return($r);
   }
}


#-- ....
if (!function_exists("array_diff_uassoc")) {
   function array_diff_uassoc() {
      $in = func_get_args();
      $key_cb = array_pop($in);
      $arr1 = array_shift($in);
      $num = count($in);
      $r = array();
      
      foreach ($arr1 as $i=>$v) {
         #-- in other arrays?
         for ($c=0; $c<$num; $c++) {
            foreach ($in[$c] as $i2=>$v2) {
               if ($v == $v2) {
                  $cmp = call_user_func_array($key_cb, array($i, $i2));
                  if ($cmp == 0) {
                     continue 3;
                  }
               }
            }
         }
         #-- exists only in array1
         $r[$i] = $v;
      }
      return($r);
   }
}


#-- diff array, keys ignored, callback for comparing values
if (!function_exists("array_udiff")) {
   function array_udiff() {
      $in = func_get_args();
      $val_cb = array_pop($in);
      $arr1 = array_shift($in);
      $num = count($in);
      $r = array();
      foreach ($arr1 as $i=>$v) {
         #-- check other arrays
         for ($c=0; $c<$num; $c++) {
            foreach ($in[$c] as $v2) {
               $cmp = call_user_func_array($val_cb, array($v, $v2));
               if ($cmp == 0) {
                  continue 3;
               }
            }
         }
         #-- exists only in array1
         $r[$i] = $v;
      }
      return($r);
   }
}












#-- same for intersections
if (!function_exists("array_uintersect_uassoc")) {
   function array_uintersect_uassoc() {
      $in = func_get_args();
      $key_cb = array_pop($in);
      $val_cb = array_pop($in);
      $all = array();
      $conc = count($in);
      foreach ($in[0] as $i=>$v) {
         #-- must exist in each array (at least once, callbacks may match fuzzy)
         for ($c=1; $c<$conc; $c++) {
            $ok = false;
            foreach ($in[$c] as $i2=>$v2) {
               $key_cmp = call_user_func_array($key_cb, array($i, $i2));
               $val_cmp = call_user_func_array($val_cb, array($v, $v2));
               if (($key_cmp == 0) && ($val_cmp == 0)) {
                  $ok = true;
                  break;
               }
            }
            if (!$ok) {
               continue 2;
            }
         }
         #-- exists in all arrays
         $all[$i] = $v;
      }
      return($all);
   }
}




#-- intersection again
if (!function_exists("array_uintersect_assoc")) {
   function array_uintersect_assoc() {
      $in = func_get_args();
      $val_cb = array_pop($in);
      $all = array();
      $conc = count($in);
      foreach ($in[0] as $i=>$v) {
         #-- test for that entry in any other array
         for ($c=1; $c<$conc; $c++) {
            if (isset($in[$c][$i])) {
               $cmp = call_user_func_array($val_cb, array($v, $in[$c][$i]));
               if ($cmp == 0) { continue; }
            }
            #-- failed
            continue 2;
         }
         #-- exists in all arrays
         # (but for fuzzy matching: only the first entry will be returned here)
         $all[$i] = $v;
      }
      return($all);
   }
}





#-- array intersection, no keys compared, but callback for values
if (!function_exists("array_uintersect")) {
   function array_uintersect() {
      $in = func_get_args();
      $val_cb = array_pop($in);
      $arr1 = array_shift($in);
      $num = count($in);
      $r = array();

      foreach ($arr1 as $i=>$v) {
         #-- must have equivalent value in all other arrays
         for ($c=0; $c<$num; $c++) {
            foreach ($in[$c] as $i2=>$v2) {
               $cmp = call_user_func_array($val_cb, array($v, $v2));
               if ($cmp == 0) {
                  continue 2; //found
               }
            }
            continue 2; //failed
         }
         #-- everywhere
         $r[$i] = $v;
      }
      return($r);
   }
}




#-- diff array, keys ignored, callback for comparing values
if (!function_exists("array_intersect_uassoc")) {
   function array_intersect_uassoc() {
      $args = func_get_args();
      $key_cb = array_pop($args);
      $array1 = array_shift($args);
      $num = count($args);
      $all = array();
      foreach ($array1 as $i=>$v) {
         #-- look through other arrays
         for ($c=0; $c<$num; $c++) {
            $ok = 0;
            foreach ($args[$c] as $i2=>$v2) {
               $cmp = call_user_func_array($key_cb, array($i, $i2));
               if (($cmp == 0) && ($v == $v2)) {
                  $ok = 1;
                  continue 2;
               }
            }
            if (!$ok) { 
               continue 2;
            }
         }
         #-- found in all arrays
         if ($ok) {
            $diff[$i] = $v;
         }
      }
      return($diff);
   }
}


?>

Changes to ext/stubs/zlib.php.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
/*
   This script simulates the gz*() functions, without actually providing
   compression functionality. The generated data streams will be correct,
   but reading compressed files isn't possible.
   
   Not very useful; should only be used if there is no other way. But if
   your provider seriously doesn't have PHP with builtin zlib support,
   you seriously were better off simply switching to someone else...
*/


 #-- fake zlib
 if (!function_exists("gzopen")) {

    function gzopen($fp, $mode) {








|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
/*
   This script simulates the gz*() functions, without actually providing
   compression functionality. The generated data streams will be correct,
   but reading compressed files isn't possible.
   
   Not very useful; should only be used if there is no other way. But if
   your provider seriously doesn't have PHP with builtin zlib support,
   you'd be better off simply switching to someone else...
*/


 #-- fake zlib
 if (!function_exists("gzopen")) {

    function gzopen($fp, $mode) {

Added ext/uncommon_functions.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 these, 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 list 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";
      }
   }
}


?>

Deleted ext/unfinished/bcmath.old.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
<?php
/**
 * These two alternate bcmath implementations, don't emulate arbitrary
 * precision at all. And therefore, have been removed from bcmath.php.
 *
 */


#-- GMP
if (!function_exists("bcadd") && function_exists("gmp_strval")) {
   function bcadd($a, $b) {
      return gmp_strval(gmp_add($a, $b));
   }
   function bcsub($a, $b) {
      return gmp_strval(gmp_sub($a, $b));
   }
   function bcmul($a, $b) {
      return gmp_strval(gmp_mul($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 bcpow($a, $b) {
      return gmp_strval(gmp_pow($a, $b));
   }
   function bcpowmod($x, $y, $mod) {
      return gmp_strval(gmp_powm($x, $y, $mod));
   }
   function bcsqrt($x) {
      return gmp_strval(gmp_sqrt($x));
   }
   function bccomp($a, $b) {
      return gmp_cmp($a, $b);
   }
   function bcscale($scale="IGNORED") {
      trigger_error("bcscale(): ignored", E_USER_ERROR);
   }
}//gmp emulation



#-- bigint
// @dl("php_big_int".PHP_SHLIB_SUFFIX))
if (!function_exists("bcadd") && function_exists("bi_serialize")) {
   function bcadd($a, $b) {
      return bi_to_str(bi_add($a, $b));
   }
   function bcsub($a, $b) {
      return bi_to_str(bi_sub($a, $b));
   }
   function bcmul($a, $b) {
      return bi_to_str(bi_mul($a, $b));
   }
   function bcdiv($a, $b) {
      return bi_to_str(bi_div($a, $b));
   }
   function bcmod($a, $b) {
      return bi_to_str(bi_mod($a, $b));
   }
   function bcpow($a, $b) {
      return bi_to_str(bi_pow($a, $b));
   }
   function bcpowmod($a, $b, $c) {
      return bi_to_str(bi_powmod($a, $b, $c));
   }
   function bcsqrt($a) {
      return bi_to_str(bi_sqrt($a));
   }
   function bccomp($a, $b) {
      return bi_cmp($a, $b);
   }
   function bcscale($scale="IGNORED") {
      trigger_error("bcscale(): ignored", E_USER_ERROR);
   }
}


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
























































































































































































Changes to ext/unfinished/filter.php.

510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
   elseif ($filter == FILTER_SANITIZE_MAGIC_QUOTES) {
      return addslashes($var);
   }


   #-- callback function
   elseif ($filter == FILTER_CALLBACK) {
      return call_user_func($callback);
   }

         
   #-- filter unknown         
   else {
      trigger_error(E_USER_ERROR, "Uh, oh. Unknown filter id #".$filter);
      return $FAILURE;







|







510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
   elseif ($filter == FILTER_SANITIZE_MAGIC_QUOTES) {
      return addslashes($var);
   }


   #-- callback function
   elseif ($filter == FILTER_CALLBACK) {
      return call_user_func($callback, $var);
   }

         
   #-- filter unknown         
   else {
      trigger_error(E_USER_ERROR, "Uh, oh. Unknown filter id #".$filter);
      return $FAILURE;

Changes to ext/unfinished/odbc.php.

1
2
3
4
5
6
7
8
9
10
<?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



|







1
2
3
4
5
6
7
8
9
10
<?php

die("'odbc.php' is incomplete. Will not be completed. Use PDO instead.\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

Deleted ext/unfinished/openssl.php.

1
2
3
4
5
<?php
/*
   Ok, that's a joke. (Not that this wasn't possible, though ...)
*/
?>
<
<
<
<
<










Deleted ext/unfinished/pdo.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
<?php
/*
   api: php
   type: class
   title: PDO
   priority: never
   status: unfinished
   
   TODO.
   
   PDO is a standardized SQL wrapper for PHP. It's meant to replace the
   plethora of mysql_/pgsql_ functions and former SQL wrappers PEARDB,
   MDB2, ADODB, ... and become what DBI is for Perl.
   
   However, PDO cannot be emulated fully, not on PHP4 especially, because
   the SPL and meta object semantics won't work there. Eventually a subset
   can be reimplemented however. (Would be more useful than ADO and PEARDB
   at least.)
   
   We'll only implement here:
   - PDO_MYSQL
*/


#-- stub
if (!function_exists()) {
   function pdo_drivers() {
      return array();
   }
}


#-- PDO
if (!class_exists("pdo")) {
   class PDO {
   }
}

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














































































Added ext/xmlentities.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
<?php
/**
 * api: php
 * title: future PHP functions
 * descriptions: functions, that are not yet in php.net releases
 *
 *
 *  
 */



/**
 * @nonstandard
 *
 * Encodes required named XML entities. It's like htmlentities().
 * Doesn't re-encode or fix numeric entities.
 *
 * @param string
 * @return string
 */
if (!function_exists("xmlentities")) {
   function xmlentities($str) {
      return strtr($str, array(
        "&#"=>"&#", "&"=>"&amp;", "'"=>"&apos;",
        "<"=>"&lt;", ">"=>"&gt;", "\""=>"&quot;", 
      ));
   }
}


?>

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
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
<?php
/**
 * api:		php
 * title:	WentPHP5 / upgrade.php
 * description:	Emulates functions from new PHP versions on older interpreters.
 * version:	15
 * license:	Public Domain
 * url:		http://freshmeat.net/p/upgradephp
 * type:	functions
 * category:	library
 * priority:	auto

 * sort:	-255
 * provides:	upgrade-php, api:php5
 *
 *
 * By loading this library you get PHP version independence. It provides
 * downwards compatibility to older PHP interpreters by emulating missing
 * functions or constants using IDENTICAL NAMES. So this doesn't slow down
 * script execution on setups where the native functions already exist. It
 * is meant as quick drop-in solution. It spares you from rewriting code or
 * using cumbersome workarounds, instead of the more powerful v5 functions.
 * 
 * It cannot mirror PHP5s extended OO-semantics and functionality into PHP4
 * however. A few features are added here that weren't part of PHP yet. And
 * some other function collections are separated out into the ext/ directory.
 * It doesn't produce many custom error messages (YAGNI), and instead leaves
 * reporting to invoked functions or for execution on native PHP.
 * 
 * And further this is PUBLIC DOMAIN (no copyright, no license, no warranty)
 * so therefore compatible to ALL open source licenses. You could rip this
 * paragraph out to republish this instead only under more restrictive terms
 * or your favorite license (GNU LGPL/GPL, BSDL, MPL/CDDL, Artistic/PHPL, ..)
 *
 * Any contribution is appreciated. <milky*users#sf#net>
 *
 */





/**
 *                                   ------------------------------ CVS ---
 * @group CVS
 * @since CVS
 *










 * planned, but as of yet unimplemented functions
 * - some of these might appear in 6.0 or ParrotPHP

























































































 *
 * @emulated










 *    sys_get_temp_dir



















 *



 */









































































































































/**
 * returns path of the system directory for temporary files

 *



 */
if (!function_exists("sys_get_temp_dir")) {
   function sys_get_temp_dir() {












      # check possible alternatives
      ($temp = ini_get("temp_dir"))
      or
      ($temp = $_SERVER["TEMP"])
      or
      ($temp = $_SERVER["TMP"])
      or
      ($temp = "/tmp");
      # fin
      return($temp);
   }
}





/**
 *                                   ------------------------------ 5.2 ---



|

|

|



>

|







|





|












>
>

|

|

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


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

>
>
>



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

<
>

>
>
>

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







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
<?php
/**
 * api:		php
 * title:	upgrade.php
 * description:	Emulates functions from new PHP versions on older interpreters.
 * version:	16
 * license:	Public Domain
 * url:		http://freshmeat.net/projects/upgradephp
 * type:	functions
 * category:	library
 * priority:	auto
 * load_if:     (PHP_VERSION<5.2)
 * sort:	-255
 * provides:	upgrade-php, api:php5, json
 *
 *
 * By loading this library you get PHP version independence. It provides
 * downwards compatibility to older PHP interpreters by emulating missing
 * functions or constants using IDENTICAL NAMES. So this doesn't slow down
 * script execution on setups where the native functions already exist. It
 * is meant as quick drop-in solution. It spares you from rewriting code or
 * using cumbersome workarounds instead of the more powerful v5 functions.
 * 
 * It cannot mirror PHP5s extended OO-semantics and functionality into PHP4
 * however. A few features are added here that weren't part of PHP yet. And
 * some other function collections are separated out into the ext/ directory.
 * It doesn't produce many custom error messages (YAGNI), and instead leaves
 * reporting to invoked functions or for native PHP execution.
 * 
 * And further this is PUBLIC DOMAIN (no copyright, no license, no warranty)
 * so therefore compatible to ALL open source licenses. You could rip this
 * paragraph out to republish this instead only under more restrictive terms
 * or your favorite license (GNU LGPL/GPL, BSDL, MPL/CDDL, Artistic/PHPL, ..)
 *
 * Any contribution is appreciated. <milky*users#sf#net>
 *
 */





/**
 *                                   --------------------- CVS / FUTURE ---
 * @group CVS
 * @since future
 *
 * Following functions aren't implemented in current PHP versions, but
 * might already be in CVS/SVN.
 *
 * @emulated
 *    gzdecode
 *
 * @moved out
 *    contrib/xmlentities
 *
 */





/**
 * @since 6.0
 *
 * Inflates a string enriched with gzip headers. Counterpart to gzencode().
 * Not yet in any Zend-PHP.
 *
 */
if (!function_exists("gzdecode")) {
   function gzdecode($gzdata, $maxlen=NULL) {

      #-- decode header
      $len = strlen($gzdata);
      if ($len < 20) {
         return;
      }
      $head = substr($gzdata, 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($gzdata, $len-8, 8));
      list($CRC32, $ISIZE) = array_values($head);

      #-- check gzip stream identifier
      if ($ID != 0x1f8b) {
         trigger_error("gzdecode: not in gzip format", E_USER_WARNING);
         return;
      }
      #-- check for deflate algorithm
      if ($CM != 8) {
         trigger_error("gzdecode: cannot decode anything but deflated streams", E_USER_WARNING);
         return;
      }

      #-- start of data, skip bonus fields
      $s = 10;
      if ($FLG & $FEXTRA) {
         $s += $XFL;
      }
      if ($FLG & $FNAME) {
         $s = strpos($gzdata, "\000", $s) + 1;
      }
      if ($FLG & $FCOMMENT) {
         $s = strpos($gzdata, "\000", $s) + 1;
      }
      if ($FLG & $FHCRC) {
         $s += 2;  // cannot check
      }
      
      #-- get data, uncompress
      $gzdata = substr($gzdata, $s, $len-$s);
      if ($maxlen) {
         $gzdata = gzinflate($gzdata, $maxlen);
         return($gzdata);  // no checks(?!)
      }
      else {
         $gzdata = gzinflate($gzdata);
      }
      
      #-- check+fin
      $chk = crc32($gzdata);
      if ($CRC32 != $chk) {
         trigger_error("gzdecode: checksum failed (real$chk != comp$CRC32)", E_USER_WARNING);
      }
      elseif ($ISIZE != strlen($gzdata)) {
         trigger_error("gzdecode: stream size mismatch", E_USER_WARNING);
      }
      else {
         return($gzdata);
      }
   }
}





/**
 *                                   ----------------------------- 5.3 ---
 * @group 5_3
 * @since 5.3
 *
 * Known additions of PHP 5.3
 *
 * @emulated
 *    ob_get_headers (stub)
 *    preg_filter
 *    lcfirst
 *    class_alias
 *    header_remove
 *    parse_ini_string
 *    array_replace
 *
 * @missing
 *    get_called_class
 *    str_getcsv
 *    quoted_printable_encode
 *    forward_static_call
 *    forward_static_call_array
 *    stream_context_get_params
 *    stream_context_set_default
 *    stream_supports_lock
 *    array_replace_recursive
 *    hash_copy
 *    date_create_from_format
 *    date_parse_from_format
 *    date_get_last_errors
 *    date_add
 *    date_sub
 *    date_diff
 *    date_timestamp_set
 *    date_timestamp_get
 *    timezone_location_get
 *    date_interval_create_from_date_string
 *    date_interval_format
 *
 * RANT: The PHP 5.3 \idiot\namespace\syntax (magic quotes 2.0) is not
 * reimplemented here.
 *
 */



/**
 * preg_replace() variant, which filters out any unmatched $subject.
 *
 */
if (!function_exists("preg_filter")) {
   function preg_filter($pattern, $replacement, $subject, $limit=NULL, $count=NULL) {
      $r = preg_replace($pattern, $replacement, $subject, $limit, $count);
      if (!is_array($subject)) {
         return preg_match($pattern, $subject) ? $r : NULL;
      }
      else {
         foreach ((array)$subject as $i=>$s) {
            if (!preg_match($pattern, $subject)) {
               unset($r[$i]);  // just post-remove unmatched entries
            }
         }
         return($r);
      }
      // optimize-wise you would do the match first and then the replacing; but this is shorter
   }
}



/**
 * Lowercase first character.
 *
 * @param string
 * @return string
 */
if (!function_exists("lcfirst")) {
   function lcfirst($str) {
      return strlen($str) ? strtolower($str[0]) . substr($str, 1) : "";
   }
}



/**
 * @stub  cannot be emulated, because output buffering functions
 *        already swallow up any sent http header
 * @since 5.3.?
 *
 * get all ob_ soaked headers(),
 *
 */
if (!function_exists("ob_get_headers")) {
   function ob_get_headers() {
      return (array)NULL;
   }
}



/**
 * @stub  Cannot be emulated correctly, but let's try.
 *
 */
if (!function_exists("header_remove")) {
   function header_remove($name) {
      if ($name = preg_replace("/[^-_.\w\d]+/", "", $name)) header("$name: \t");
      // Apache1.3? removed duplettes, empty header overrides previous.
      // ONLY if case was identical to previous header() call. (Very uncertain for applications which need to resort to such code smell.)
   }
}



/**
 * WTF?
 * At least an explaning reference was available on the php.net manual.
 * Why the parameters are supposed to be optional is a mystery.
 *
 */
if (!function_exists("class_alias")) {
   function class_alias($original, $alias) {
      $abstract = "";
      if (class_exists("ReflectionClass")) {
         $oc = new ReflectionClass($original);
         $abstract = $oc->isAbstract() ? "abstract" : "";
      }
      eval("$abstract class $alias extends $original { /* identical subclass */ }");
      return get_parent_class($alias) == $original;
   }
}




/**
 * Hey, reimplementin is fun.
 * (Could have used a data: wrapper for parse_ini_file, but that wouldn't work for php<5.2, and the data:// (!) wrapper is flaky anyway.)
 *
 */
if (!function_exists("parse_ini_string")) {
   function parse_ini_string($ini, $sectioned=false, $raw=0) {
      $r = array();
      $map = array("true"=>1, "yes"=>1, "1"=>1, "null"=>"", "false"=>"", "no"=>"", "0"=>0);
      $section = "";
      foreach (explode("\n", $ini) as $line) {
         if (!strlen($line)) {
         }
         // handle [sections]
         elseif (($line[0] == "[") and preg_match("/\[([-_\w ]+)\]/", $line, $uu)) {
            $section = $uu[1];
         }
         elseif (/*deprecated*/($line[0] != "#") && ($line[0] != ";") && ($i = strpos($line, "="))) {
            // key=value split
            $n = trim(substr($line, 0, $i));
            $v = trim(substr($line, $i+1));
            // replace special values
            if (!$raw) {
               $v=trim($v, '"');   // should actually use regex, to handle key="..\n.." multiline values
               $v=trim($v, "'");
               if (isset($map[$v])) {
                  $v=$map[$v];
               }
            }
            // special array[]= keys allowed
            if ($i = strpos($n, "[")) {
               $r[$section][substr($n, 0, $i)][] = $v;
            }
            else {
               $r[$section][$n] = $v;
            }
         }
      }
      return $sectioned ? $r : call_user_func_array("array_merge", $r);
   }
}




/**

 * Inject values from supplemental arrays into $target, according to its keys.
 *
 * @param array  $targt
 * @param+ array $supplements
 * @return array
 */
if (!function_exists("array_replace")) {
   function array_replace(/* & (?) */$target/*, $from, $from2, ...*/) {
      $merge = func_get_args();
      array_shift($merge);
      for ($i=0; $i<count($merge); $i++) {
         foreach ((array)$merge[$i] as $i=>$v) {
            if (isset($target[$i])) {
               $target[$i] = $v;
            }
         }
      }
      return $target;
   }
}

















/**
 *                                   ------------------------------ 5.2 ---
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228

229
230
231
232
233
234
235
 *    would scream error or explode.
 * @code
 *    This is state machine spaghetti code. Needs the extranous parameters to
 *    process subarrays, etc. When it recursively calls itself, $n is the
 *    current position, and $waitfor a string with possible end-tokens.
 *
 * @param   $json string   JSON encoded values
 * @param   $assoc bool    (optional) if outer shell should be decoded as object always
 * @return  mixed          parsed into PHP variable/array/object
 */
if (!function_exists("json_decode")) {
   function json_decode($json, $assoc=FALSE, /*emu_args*/$n=0,$state=0,$waitfor=0) {

      #-- result var
      $val = NULL;
      static $lang_eq = array("true" => TRUE, "false" => FALSE, "null" => NULL);
      static $str_eq = array("n"=>"\012", "r"=>"\015", "\\"=>"\\", '"'=>'"', "f"=>"\f", "b"=>"\b", "t"=>"\t", "/"=>"/");


      #-- flat char-wise parsing
      for (/*n*/; $n<strlen($json); /*n*/) {
         $c = $json[$n];

         #-= in-string
         if ($state==='"') {







|



|





>







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
 *    would scream error or explode.
 * @code
 *    This is state machine spaghetti code. Needs the extranous parameters to
 *    process subarrays, etc. When it recursively calls itself, $n is the
 *    current position, and $waitfor a string with possible end-tokens.
 *
 * @param   $json string   JSON encoded values
 * @param   $assoc bool    pack data into php array/hashes instead of objects
 * @return  mixed          parsed into PHP variable/array/object
 */
if (!function_exists("json_decode")) {
   function json_decode($json, $assoc=FALSE, $limit=512, /*emu_args*/$n=0,$state=0,$waitfor=0) {

      #-- result var
      $val = NULL;
      static $lang_eq = array("true" => TRUE, "false" => FALSE, "null" => NULL);
      static $str_eq = array("n"=>"\012", "r"=>"\015", "\\"=>"\\", '"'=>'"', "f"=>"\f", "b"=>"\b", "t"=>"\t", "/"=>"/");
      if ($limit<0) return /* __cannot_compensate */;

      #-- flat char-wise parsing
      for (/*n*/; $n<strlen($json); /*n*/) {
         $c = $json[$n];

         #-= in-string
         if ($state==='"') {
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
         #-> end of sub-call (array/object)
         elseif ($waitfor && (strpos($waitfor, $c) !== false)) {
            return array($val, $n);  // return current value and state
         }
         
         #-= in-array
         elseif ($state===']') {
            list($v, $n) = json_decode($json, 0, $n, 0, ",]");
            $val[] = $v;
            if ($json[$n] == "]") { return array($val, $n); }
         }

         #-= in-object
         elseif ($state==='}') {
            list($i, $n) = json_decode($json, 0, $n, 0, ":");   // this allowed non-string indicies
            list($v, $n) = json_decode($json, 0, $n+1, 0, ",}");
            $val[$i] = $v;
            if ($json[$n] == "}") { return array($val, $n); }
         }

         #-- looking for next item (0)
         else {
         
            #-> whitespace
            if (preg_match("/\s/", $c)) {
               // skip
            }

            #-> string begin
            elseif ($c == '"') {
               $state = '"';
            }

            #-> object
            elseif ($c == "{") {
               list($val, $n) = json_decode($json, $assoc, $n+1, '}', "}");

               if ($val && $n && !$assoc) {
                  $obj = new stdClass();
                  foreach ($val as $i=>$v) {
                     $obj->{$i} = $v;
                  }
                  $val = $obj;
                  unset($obj);
               }
            }
            #-> array
            elseif ($c == "[") {
               list($val, $n) = json_decode($json, $assoc, $n+1, ']', "]");
            }

            #-> comment
            elseif (($c == "/") && ($json[$n+1]=="*")) {
               // just find end, skip over
               ($n = strpos($json, "*/", $n+1)) or ($n = strlen($json));
            }







|






|
|



















|
>
|
<
|
<
|
<
<
|
|


|







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
         #-> end of sub-call (array/object)
         elseif ($waitfor && (strpos($waitfor, $c) !== false)) {
            return array($val, $n);  // return current value and state
         }
         
         #-= in-array
         elseif ($state===']') {
            list($v, $n) = json_decode($json, $assoc, $limit, $n, 0, ",]");
            $val[] = $v;
            if ($json[$n] == "]") { return array($val, $n); }
         }

         #-= in-object
         elseif ($state==='}') {
            list($i, $n) = json_decode($json, $assoc, $limit, $n, 0, ":");   // this allowed non-string indicies
            list($v, $n) = json_decode($json, $assoc, $limit, $n+1, 0, ",}");
            $val[$i] = $v;
            if ($json[$n] == "}") { return array($val, $n); }
         }

         #-- looking for next item (0)
         else {
         
            #-> whitespace
            if (preg_match("/\s/", $c)) {
               // skip
            }

            #-> string begin
            elseif ($c == '"') {
               $state = '"';
            }

            #-> object
            elseif ($c == "{") {
               list($val, $n) = json_decode($json, $assoc, $limit-1, $n+1, '}', "}");
               
               if ($val && $n) {

                  $val = $assoc ? (array)$val : (object)$val;

               }


            }

            #-> array
            elseif ($c == "[") {
               list($val, $n) = json_decode($json, $assoc, $limit-1, $n+1, ']', "]");
            }

            #-> comment
            elseif (($c == "/") && ($json[$n+1]=="*")) {
               // just find end, skip over
               ($n = strpos($json, "*/", $n+1)) or ($n = strlen($json));
            }
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
}




/**
 * @stub
 * @cannot-reimplement


 *
 */
if (!function_exists("preg_last_error")) {
   if (!defined("PREG_NO_ERROR")) { define("PREG_NO_ERROR", 0); }
   if (!defined("PREG_INTERNAL_ERROR")) { define("PREG_INTERNAL_ERROR", 1); }
   if (!defined("PREG_BACKTRACK_LIMIT_ERROR")) { define("PREG_BACKTRACK_LIMIT_ERROR", 2); }
   if (!defined("PREG_RECURSION_LIMIT_ERROR")) { define("PREG_RECURSION_LIMIT_ERROR", 3); }
   if (!defined("PREG_BAD_UTF8_ERROR")) { define("PREG_BAD_UTF8_ERROR", 4); }
   function preg_last_error() {
      return PREG_NO_ERROR;
   }
}


























/**
 * @stub
 *
 * Returns associative array with last error message.
 *
 */
if (!function_exists("error_get_last")) {
   function error_get_last() {
      return array(
         "type" => 0,
         "message" => $GLOBALS[php_errormsg],
         "file" => "unknonw",
         "line" => 0,
      );
   }
}




/**
 * @flag quirky, exec
 * @realmode
 *
 * Change owner of a symlink filename.
 *
 */
if (!function_exists("lchown")) {
   function lchown($fn, $user) {
      if (PHP_OS != "Linux") {
         return false;
      }
      $user = escapeshellcmd($user);
      $fn = escapeshellcmd($fn);
      exec("chown -h '$user' '$fn'", $uu, $state);
      return($state);
   }
}



/**
 * @flag quirky, exec
 * @realmode
 *
 * Change group of a symlink filename.
 *
 */
if (!function_exists("lchgrp")) {
   function lchgrp($fn, $group) {
      return lchown($fn, ":$group");







<
>
>















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




|

















|
<



















|
<







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
}




/**
 * @stub

 *
 * Should return last PCRE error.
 *
 */
if (!function_exists("preg_last_error")) {
   if (!defined("PREG_NO_ERROR")) { define("PREG_NO_ERROR", 0); }
   if (!defined("PREG_INTERNAL_ERROR")) { define("PREG_INTERNAL_ERROR", 1); }
   if (!defined("PREG_BACKTRACK_LIMIT_ERROR")) { define("PREG_BACKTRACK_LIMIT_ERROR", 2); }
   if (!defined("PREG_RECURSION_LIMIT_ERROR")) { define("PREG_RECURSION_LIMIT_ERROR", 3); }
   if (!defined("PREG_BAD_UTF8_ERROR")) { define("PREG_BAD_UTF8_ERROR", 4); }
   function preg_last_error() {
      return PREG_NO_ERROR;
   }
}




/**
 * returns path of the system directory for temporary files
 *
 * @since 5.2.1
 */
if (!function_exists("sys_get_temp_dir")) {
   function sys_get_temp_dir() {
      # check possible alternatives
      ($temp = ini_get("temp_dir"))
      or
      ($temp = $_SERVER["TEMP"])
      or
      ($temp = $_SERVER["TMP"])
      or
      ($temp = "/tmp");
      # fin
      return($temp);
   }
}



/**
 * @stub
 *
 * Should return associative array with last error message.
 *
 */
if (!function_exists("error_get_last")) {
   function error_get_last() {
      return array(
         "type" => 0,
         "message" => $GLOBALS[php_errormsg],
         "file" => "unknonw",
         "line" => 0,
      );
   }
}




/**
 * @flag quirky, exec, realmode

 *
 * Change owner of a symlink filename.
 *
 */
if (!function_exists("lchown")) {
   function lchown($fn, $user) {
      if (PHP_OS != "Linux") {
         return false;
      }
      $user = escapeshellcmd($user);
      $fn = escapeshellcmd($fn);
      exec("chown -h '$user' '$fn'", $uu, $state);
      return($state);
   }
}



/**
 * @flag quirky, exec, realmode

 *
 * Change group of a symlink filename.
 *
 */
if (!function_exists("lchgrp")) {
   function lchgrp($fn, $group) {
      return lchown($fn, ":$group");
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
      fwrite($fp, $line."\n");
   }
}



/**
 * @stub
 * @untested
 * @flag basic
 *
 * @compat
 *    only implements a few basic regular expression lookups
 *    no idea how to handle all of it
 */
if (!function_exists("strptime")) {
   function strptime($str, $format) {







|

<







910
911
912
913
914
915
916
917
918

919
920
921
922
923
924
925
      fwrite($fp, $line."\n");
   }
}



/**
 * @flag basic
 * @untested

 *
 * @compat
 *    only implements a few basic regular expression lookups
 *    no idea how to handle all of it
 */
if (!function_exists("strptime")) {
   function strptime($str, $format) {
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
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








/**
 *                                   --------------------------- FUTURE ---
 * @group FUTURE
 * @since future
 *
 * Following functions aren't implemented in current PHP versions allthough
 * they are logical and required counterparts to existing features or exist
 * in the according external library.
 *
 * @emulated
 *    gzdecode
 *    ob_get_headers
 *    xmlentities
 *
 * @missing
 *    ...
 *
 * @unimplementable
 *    ... 
 *
 */




/**
 * @since future
 *
 * inflates a string enriched with gzip headers
 *  - this is the logical counterpart to gzencode(), but don't tell anyone!
 */
if (!function_exists("gzdecode")) {
   function gzdecode($data, $maxlen=NULL) {

      #-- decode header
      $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);

      #-- check gzip stream identifier
      if ($ID != 0x1f8b) {
         trigger_error("gzdecode: not in gzip format", E_USER_WARNING);
         return;
      }
      #-- check for deflate algorithm
      if ($CM != 8) {
         trigger_error("gzdecode: cannot decode anything but deflated streams", E_USER_WARNING);
         return;
      }

      #-- start of data, skip bonus fields
      $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;  // cannot check
      }
      
      #-- get data, uncompress
      $data = substr($data, $s, $len-$s);
      if ($maxlen) {
         $data = gzinflate($data, $maxlen);
         return($data);  // no checks(?!)
      }
      else {
         $data = gzinflate($data);
      }
      
      #-- check+fin
      $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);
      }
   }
}



/**
 * get all ob_ soaked 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
 *
 * @param string
 * @return string
 */
if (!function_exists("xmlentities")) {
   function xmlentities($str) {
      return strtr($str, array(
        "&#"=>"&#", "&"=>"&amp;", "'"=>"&apos;",
        "<"=>"&lt;", ">"=>"&gt;", "\""=>"&quot;", 
      ));
   }
}





/**
 *                                   ------------------------------ 5.0 ---
 * @group 5_0







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







995
996
997
998
999
1000
1001







































































































































1002
1003
1004
1005
1006
1007
1008


















































































































































/**
 *                                   ------------------------------ 5.0 ---
 * @group 5_0
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
 *    date_sunset - undoc.
 *    PHP_CONFIG_FILE_SCAN_DIR
 *    clone
 *
 * @unimplementable
 *    set_exception_handler
 *    restore_exception_handler
 *    debug_print_backtrace
 *    debug_backtrace
 *    class_implements
 *    proc_terminate
 *    proc_get_status
 *    range        - new param
 *    microtime    - new param
 *
 */







|
|







1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
 *    date_sunset - undoc.
 *    PHP_CONFIG_FILE_SCAN_DIR
 *    clone
 *
 * @unimplementable
 *    set_exception_handler
 *    restore_exception_handler
 *    debug_print_backtrace - in ext, needs4.3
 *    debug_backtrace       - stub
 *    class_implements
 *    proc_terminate
 *    proc_get_status
 *    range        - new param
 *    microtime    - new param
 *
 */
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155


/**
 * 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
 *
 * @param  mixed  $data           variable data for query string
 * @param  string $int_prefix     (optional)
 * @param  string $subarray_pfix  (optional)
 * @param integer $level  
 * @return mixed
 */
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;







|






|






|







1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320


/**
 * 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
 *
 * @param  mixed  $vars           variable data for query string
 * @param  string $int_prefix     (optional)
 * @param  string $subarray_pfix  (optional)
 * @param integer $level  
 * @return mixed
 */
if (!function_exists("http_build_query")) {
   function http_build_query($vars, $int_prefix="", $subarray_pfix="", $level=0) {
   
      #-- empty starting string
      $s = "";
      ($SEP = ini_get("arg_separator.output")) or ($SEP = "&");
      
      #-- traverse hash/array/list entries 
      foreach ($vars as $index=>$value) {
         
         #-- add sub_prefix for subarrays (happens for recursed innovocation)
         if ($subarray_pfix) {
            if ($level) {
               $index = "[" . $index . "]";
            }
            $index =  $subarray_pfix . $index;
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
 * transform into 3to4 uuencode
 * - this is the bare encoding, not the uu file format
 * 
 * @param  string
 * @return string
 */
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) );
                







|




|
|





|
|
|







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
 * transform into 3to4 uuencode
 * - this is the bare encoding, not the uu file format
 * 
 * @param  string
 * @return string
 */
if (!function_exists("convert_uuencode")) {
   function convert_uuencode($bin) {

      #-- init vars
      $out = "";
      $line = "";
      $len = strlen($bin);
#      $bin .= "\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($bin[$n++]) << 16)
            + (ord($bin[$n++]) <<  8)
            + (ord($bin[$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) );
                
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
   }
}


/**
 * decodes uuencoded() data again
 *
 * @param  string $data  
 * @return string
 */
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;







|



|



|


|







1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
   }
}


/**
 * decodes uuencoded() data again
 *
 * @param  string $from  
 * @return string
 */
if (!function_exists("convert_uudecode")) {
   function convert_uudecode($from) {

      #-- prepare
      $out = "";
      $from = strtr($from, "`", " ");
      
      #-- go through lines
      foreach(explode("\n", ltrim($from)) as $line) {
         if (!strlen($line)) {
            break;  // end reached
         }
         
         #-- current line length prefix
         unset($num);
         $num = ord($line{0}) - 32;
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
}


/**
 * write-at-once file access (counterpart to file_get_contents)
 *
 * @param  integer $filename
 * @param  mixed   $data  
 * @param  integer $flags 
 * @param  mixed   $resource
 * @return integer
 */
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);
//      $resource && trigger_error("EMULATED file_put_contents does not support \$resource parameter.", E_USER_ERROR);
      
      #-- data
      if (is_array($data) || is_object($data)) {
         $data = implode("", (array)$data);
      }

      #-- open for writing
      $f = fopen($filename, $mode, $incl);
      if ($f) {
      
         // locking
         if (($flags & LOCK_EX) && !flock($f, LOCK_EX)) {
            return fclose($f) && false;
         }

         // write
         $written = fwrite($f, $data);
         fclose($f);
         
         #-- only report success, if completely saved
         return($length == $written);
      }
   }
}







|





|




|


|
|
|












|







1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
}


/**
 * write-at-once file access (counterpart to file_get_contents)
 *
 * @param  integer $filename
 * @param  mixed   $content  
 * @param  integer $flags 
 * @param  mixed   $resource
 * @return integer
 */
if (!function_exists("file_put_contents")) {
   function file_put_contents($filename, $content, $flags=0, $resource=NULL) {

      #-- prepare
      $mode = ($flags & FILE_APPEND ? "a" : "w" ) ."b";
      $incl = $flags & FILE_USE_INCLUDE_PATH;
      $length = strlen($content);
//      $resource && trigger_error("EMULATED file_put_contents does not support \$resource parameter.", E_USER_ERROR);
      
      #-- write non-scalar?
      if (is_array($content) || is_object($content)) {
         $content = implode("", (array)$content);
      }

      #-- open for writing
      $f = fopen($filename, $mode, $incl);
      if ($f) {
      
         // locking
         if (($flags & LOCK_EX) && !flock($f, LOCK_EX)) {
            return fclose($f) && false;
         }

         // write
         $written = fwrite($f, $content);
         fclose($f);
         
         #-- only report success, if completely saved
         return($length == $written);
      }
   }
}
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
 * 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;
   }







|
<
<







2493
2494
2495
2496
2497
2498
2499
2500


2501
2502
2503
2504
2505
2506
2507
 * convenience wrapper
 * 
 */
if (!function_exists("md5_file")) {
   function md5_file($filename, $raw_output=false) {

      #-- read file, apply hash function
      $r = md5(file_get_contents($filename, "rb"));


         
      #-- transform? and return
      if ($raw_output) {
         $r = pack("H*", $r);
      }
      return $r;
   }
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
 * @until unknown
 *
 *
 * @emulated
 *    ...
 *
 * @missing
 *    leak
 *
 */












|







2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
 * @until unknown
 *
 *
 * @emulated
 *    ...
 *
 * @missing
 *    leak  - occupy a given amount of memory
 *
 */





Added upgrade.php.shortened.



>
1
<?php if(!function_exists("gzdecode")){function gzdecode($gzdata,$maxlen=NULL){$len=strlen($gzdata);if($len<20){return;}$head=substr($gzdata,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($gzdata,$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($gzdata,"\000",$s)+1;}if($FLG&$FCOMMENT){$s=strpos($gzdata,"\000",$s)+1;}if($FLG&$FHCRC){$s+=2;}$gzdata=substr($gzdata,$s,$len-$s);if($maxlen){$gzdata=gzinflate($gzdata,$maxlen);return($gzdata);}else{$gzdata=gzinflate($gzdata);}$chk=crc32($gzdata);if($CRC32!=$chk){trigger_error("gzdecode: checksum failed(real$chk!=comp$CRC32)",E_USER_WARNING);}elseif($ISIZE!=strlen($gzdata)){trigger_error("gzdecode: stream size mismatch",E_USER_WARNING);}else{return($gzdata);}}}if(!function_exists("preg_filter")){function preg_filter($pattern,$replacement,$subject,$limit=NULL,$count=NULL){$r=preg_replace($pattern,$replacement,$subject,$limit,$count);if(!is_array($subject)){return preg_match($pattern,$subject)?$r : NULL;}else{foreach((array)$subject as$i=>$s){if(!preg_match($pattern,$subject)){unset($r[$i]);}}return($r);}}}if(!function_exists("lcfirst")){function lcfirst($str){return strlen($str)? strtolower($str[0]). substr($str,1):"";}}if(!function_exists("ob_get_headers")){function ob_get_headers(){return(array)NULL;}}if(!function_exists("header_remove")){function header_remove($name){if($name=preg_replace("/[^-_.\w\d]+/","",$name))header("$name: \t");}}if(!function_exists("class_alias")){function class_alias($original,$alias){$abstract="";if(class_exists("ReflectionClass")){$oc=new ReflectionClass($original);$abstract=$oc->isAbstract()?"abstract":"";}eval("$abstract class$alias extends$original{/*identical subclass*/}");return get_parent_class($alias)==$original;}}if(!function_exists("parse_ini_string")){function parse_ini_string($ini,$sectioned=false,$raw=0){$r=array();$map=array("true"=>1,"yes"=>1,"1"=>1,"null"=>"","false"=>"","no"=>"","0"=>0);$section="";foreach(explode("\n",$ini)as$line){if(!strlen($line)){}elseif(($line[0]=="[")and preg_match("/\[([-_\w]+)\]/",$line,$uu)){$section=$uu[1];}elseif(($line[0]!="#")&&($line[0]!=";")&&($i=strpos($line,"="))){$n=trim(substr($line,0,$i));$v=trim(substr($line,$i+1));if(!$raw){$v=trim($v,'"');$v=trim($v,"'");if(isset($map[$v])){$v=$map[$v];}}if($i=strpos($n,"[")){$r[$section][substr($n,0,$i)][]=$v;}else{$r[$section][$n]=$v;}}}return$sectioned ?$r : call_user_func_array("array_merge",$r);}}if(!function_exists("array_replace")){function array_replace($target){$merge=func_get_args();array_shift($merge);for($i=0;$i<count($merge);$i++){foreach((array)$merge[$i]as$i=>$v){if(isset($target[$i])){$target[$i]=$v;}}}return$target;}}if(!defined("E_RECOVERABLE_ERROR")){define("E_RECOVERABLE_ERROR",4096);}if(!function_exists("json_encode")){function json_encode($var,$obj=FALSE){$json="";if(is_array($var)||($obj=is_object($var))){if(!$obj)foreach((array)$var as$i=>$v){if(!is_int($i)){$obj=1;break;}}foreach((array)$var as$i=>$v){$json .=($json ?",":"").($obj ?("\"$i\":"):"").(json_encode($v));}$json=$obj ?"{".$json."}":"[".$json."]";}elseif(is_string($var)){if(!utf8_decode($var)){$var=utf8_encode($var);}$var=str_replace(array("\"","\\","/","\b","\f","\n","\r","\t"),array("\\\"","\\\\","\\/","\\b","\\f","\\n","\\r","\\t"),$var);$json='"' .$var . '"';}elseif(is_bool($var)){$json=$var ?"true":"false";}elseif($var===NULL){$json="null";}elseif(is_int($var)||is_float($var)){$json="$var";}else{trigger_error("json_encode: don't know what a '".gettype($var)."' is.",E_USER_ERROR);}return($json);}}if(!function_exists("json_decode")){function json_decode($json,$assoc=FALSE,$limit=512,$n=0,$state=0,$waitfor=0){$val=NULL;static$lang_eq=array("true"=>TRUE,"false"=>FALSE,"null"=>NULL);static$str_eq=array("n"=>"\012","r"=>"\015","\\"=>"\\",'"'=>'"',"f"=>"\f","b"=>"\b","t"=>"\t","/"=>"/");if($limit<0)return;for(;$n<strlen($json);){$c=$json[$n];if($state==='"'){if($c=='\\'){$c=$json[++$n];if(isset($str_eq[$c])){$val .=$str_eq[$c];}elseif($c=="u"){$hex=hexdec(substr($json,$n+1,4));$n+=4;if($hex<0x80){$val .=chr($hex);}elseif($hex<0x800){$val .=chr(0xC0+$hex>>6). chr(0x80+$hex&63);}elseif($hex<=0xFFFF){$val .=chr(0xE0+$hex>>12). chr(0x80+($hex>>6)&63). chr(0x80+$hex&63);}}else{$val .="\\".$c;}}elseif($c=='"'){$state=0;}else{$val .=$c;}}elseif($waitfor&&(strpos($waitfor,$c)!==false)){return array($val,$n);}elseif($state===']'){list($v,$n)=json_decode($json,$assoc,$limit,$n,0,",]");$val[]=$v;if($json[$n]=="]"){return array($val,$n);}}elseif($state==='}'){list($i,$n)=json_decode($json,$assoc,$limit,$n,0,":");list($v,$n)=json_decode($json,$assoc,$limit,$n+1,0,",}");$val[$i]=$v;if($json[$n]=="}"){return array($val,$n);}}else{if(preg_match("/\s/",$c)){}elseif($c=='"'){$state='"';}elseif($c=="{"){list($val,$n)=json_decode($json,$assoc,$limit-1,$n+1,'}',"}");if($val&&$n){$val=$assoc ?(array)$val :(object)$val;}}elseif($c=="["){list($val,$n)=json_decode($json,$assoc,$limit-1,$n+1,']',"]");}elseif(($c=="/")&&($json[$n+1]=="*")){($n=strpos($json,"*/",$n+1))or($n=strlen($json));}elseif(preg_match("#^(-?\d+(?:\.\d+)?)(?:[eE]([-+]?\d+))?#",substr($json,$n),$uu)){$val=$uu[1];$n+=strlen($uu[0])-1;if(strpos($val,".")){$val=(float)$val;}elseif($val[0]=="0"){$val=octdec($val);}else{$val=(int)$val;}if(isset($uu[2])){$val*=pow(10,(int)$uu[2]);}}elseif(preg_match("#^(true|false|null)\b#",substr($json,$n),$uu)){$val=$lang_eq[$uu[1]];$n+=strlen($uu[1])-1;}else{trigger_error("json_decode: error parsing '$c' at position$n",E_USER_WARNING);return$waitfor ? array(NULL,1<<30): NULL;}}if($n===NULL){return NULL;}$n++;}return($val);}}if(!function_exists("preg_last_error")){if(!defined("PREG_NO_ERROR")){define("PREG_NO_ERROR",0);}if(!defined("PREG_INTERNAL_ERROR")){define("PREG_INTERNAL_ERROR",1);}if(!defined("PREG_BACKTRACK_LIMIT_ERROR")){define("PREG_BACKTRACK_LIMIT_ERROR",2);}if(!defined("PREG_RECURSION_LIMIT_ERROR")){define("PREG_RECURSION_LIMIT_ERROR",3);}if(!defined("PREG_BAD_UTF8_ERROR")){define("PREG_BAD_UTF8_ERROR",4);}function preg_last_error(){return PREG_NO_ERROR;}}if(!function_exists("sys_get_temp_dir")){function sys_get_temp_dir(){($temp=ini_get("temp_dir"))or($temp=$_SERVER["TEMP"])or($temp=$_SERVER["TMP"])or($temp="/tmp");return($temp);}}if(!function_exists("error_get_last")){function error_get_last(){return array("type"=>0,"message"=>$GLOBALS[php_errormsg],"file"=>"unknonw","line"=>0,);}}if(!function_exists("lchown")){function lchown($fn,$user){if(PHP_OS!="Linux"){return false;}$user=escapeshellcmd($user);$fn=escapeshellcmd($fn);exec("chown-h '$user' '$fn'",$uu,$state);return($state);}}if(!function_exists("lchgrp")){function lchgrp($fn,$group){return lchown($fn,":$group");}}if(!defined("PHP_INT_SIZE")){define("PHP_INT_SIZE",4);}if(!defined("PHP_INT_MAX")){define("PHP_INT_MAX",2147483647);}if(!defined("M_SQRTPI")){define("M_SQRTPI",1.7724538509055);}if(!defined("M_LNPI")){define("M_LNPI",1.1447298858494);}if(!defined("M_EULER")){define("M_EULER",0.57721566490153);}if(!defined("M_SQRT3")){define("M_SQRT3",1.7320508075689);}if(!function_exists("htmlspecialchars_decode")){if(!defined("ENT_COMPAT")){define("ENT_COMPAT",2);}if(!defined("ENT_QUOTES")){define("ENT_QUOTES",3);}if(!defined("ENT_NOQUOTES")){define("ENT_NOQUOTES",0);}function htmlspecialchars_decode($string,$quotes=2){$d=$quotes&ENT_COMPAT;$s=$quotes&ENT_QUOTES;return str_replace(array("&lt;","&gt;",($s ?"&quot;":"&.-;"),($d ?"&#039;":"&.-;"),"&amp;"),array("<",">","'","\"","&"),$string);}}if(!function_exists("property_exists")){function property_exists($obj,$propname){if(is_object($obj)){$props=get_object_vars($obj);}elseif(class_exists($obj)){$props=get_class_vars($obj);}if(!@$props){return false;}return @array_walk($props,"strtolower")&&in_array(strtolower($propname),$props);}}if(!function_exists("time_sleep_until")){function time_sleep_until($t){$delay=$t-time();if($delay<0){trigger_error("time_sleep_until: timestamp in the past",E_USER_WARNING);return false;}else{sleep((int)$delay);usleep(($delay-floor($delay))*1000000);return true;}}}if(!function_exists("fputcsv")){function fputcsv($fp,$fields,$delim=",",$encl='"'){$line="";foreach((array)$fields as$str){$line .=($line ?$delim :"").$encl . str_replace(array('\\',$encl),array('\\\\'. '\\'.$encl),$str).$encl;}fwrite($fp,$line."\n");}}if(!function_exists("strptime")){function strptime($str,$format){static$expand=array("%D"=>"%m/%d/%y","%T"=>"%H:%M:%S",);static$map_r=array("%S"=>"tm_sec","%M"=>"tm_min","%H"=>"tm_hour","%d"=>"tm_mday","%m"=>"tm_mon","%Y"=>"tm_year","%y"=>"tm_year","%W"=>"tm_wday","%D"=>"tm_yday","%u"=>"unparsed",);static$names=array("Jan"=>1,"Feb"=>2,"Mar"=>3,"Apr"=>4,"May"=>5,"Jun"=>6,"Jul"=>7,"Aug"=>8,"Sep"=>9,"Oct"=>10,"Nov"=>11,"Dec"=>12,"Sun"=>0,"Mon"=>1,"Tue"=>2,"Wed"=>3,"Thu"=>4,"Fri"=>5,"Sat"=>6,);$format=str_replace(array_keys($expand),array_values($expand),$format);$preg=preg_replace("/(%\w)/","(\w+)",preg_quote($format));preg_match_all("/(%\w)/",$format,$positions);$positions=$positions[1];if(preg_match("#$preg#","$str",$extracted)){foreach($positions as$pos=>$strfc){$v=$extracted[$pos+1];if($n=$map_r[$strfc]){$vals[$n]=($v>0)?(int)$v :$v;}else{$vals["unparsed"].=$v ."";}}$vals["tm_wday"]=$names[substr($vals["tm_wday"],0,3)];if($vals["tm_year"]>=1900){$tm_year-=1900;}elseif($vals["tm_year"]>0){$vals["tm_year"]+=100;}if($vals["tm_mon"]){$vals["tm_mon"]-=1;}else{$vals["tm_mon"]=$names[substr($vals["tm_mon"],0,3)]-1;}}return isset($vals)?$vals : false;}}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){$haystack=strtolower($haystack);$needle=strtolower($needle);$pos=strpos($haystack,$needle,$offset);return($pos);}}if(!function_exists("strripos")){function strripos($haystack,$needle,$offset=NULL){$haystack=strtolower($haystack);$needle=strtolower($needle);if(isset($offset)&&($offset<0)){$haystack=substr($haystack,0,strlen($haystack)-1);}$pos=strrpos($haystack,$needle);if(isset($offset)&&($offset>0)&&($pos>$offset)){$pos=false;}return($pos);}}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{$replace=addcslashes($replace,"$\\");$search="{". preg_quote($search)."}i";$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;}$f=fsockopen($host,$port,$errno,$errstr,$timeout=15);if(!$f){return;}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");$ls=array();while(!feof($f)&&($line=trim(fgets($f,1<<16)))){if($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);}}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($vars,$int_prefix="",$subarray_pfix="",$level=0){$s="";($SEP=ini_get("arg_separator.output"))or($SEP="&");foreach($vars as$index=>$value){if($subarray_pfix){if($level){$index="[".$index ."]";}$index=$subarray_pfix .$index;}elseif(is_int($index)&&strlen($int_prefix)){$index=$int_prefix .$index;}if(is_array($value)){$s .=http_build_query($value,"",$index,$level+1);}else{$s .=$SEP .$index ."=". urlencode($value);}}if(!$subarray_pfix){$s=substr($s,strlen($SEP));}return($s);}}if(!function_exists("convert_uuencode")){function convert_uuencode($bin){$out="";$line="";$len=strlen($bin);for($n=0;$n<$len;){$x=(ord($bin[$n++])<<16)+(ord($bin[$n++])<<8)+(ord($bin[$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($from){$out="";$from=strtr($from,"`","");foreach(explode("\n",ltrim($from))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;}return false;}}if(!function_exists("idate")){function idate($formatchar,$timestamp=NULL){if(strlen($formatchar)!=1){return false;}if(!isset($timestamp)){$timestamp=time();}$str=date($formatchar,$timestamp);return(int)$str;}}if(!function_exists("time_nanosleep")){function time_nanosleep($sec,$nano){sleep($sec);usleep($nano);}}if(!function_exists("strpbrk")){function strpbrk($haystack,$char_list){$len=strlen($char_list);$min=strlen($haystack);for($n=0;$n<$len;$n++){$l=strpos($haystack,$char_list{$n});if(($l!==false)&&($l<$min)){$min=$l;}}if($min){return(substr($haystack,$min));}else{return(false);}}}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("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$key=>$value){if(is_array($value)){array_walk_recursive($input[$key],$callback,$userdata);}else{call_user_func_array($callback,array(&$input[$key],$key,$userdata));}}}}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];}else{$w=false;}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")){function file_put_contents($filename,$content,$flags=0,$resource=NULL){$mode=($flags&FILE_APPEND ?"a":"w")."b";$incl=$flags&FILE_USE_INCLUDE_PATH;$length=strlen($content);if(is_array($content)||is_object($content)){$content=implode("",(array)$content);}$f=fopen($filename,$mode,$incl);if($f){if(($flags&LOCK_EX)&&!flock($f,LOCK_EX)){return fclose($f)&&false;}$written=fwrite($f,$content);fclose($f);return($length==$written);}}}if(!defined("FILE_USE_INCLUDE_PATH")){define("FILE_USE_INCLUDE_PATH",1);}if(!defined("FILE_IGNORE_NEW_LINES")){define("FILE_IGNORE_NEW_LINES",2);}if(!defined("FILE_SKIP_EMPTY_LINES")){define("FILE_SKIP_EMPTY_LINES",4);}if(!defined("FILE_APPEND")){define("FILE_APPEND",8);}if(!defined("FILE_NO_DEFAULT_CONTEXT")){define("FILE_NO_DEFAULT_CONTEXT",16);}if(!defined("E_STRICT")){define("E_STRICT",2048);}if(!defined("COUNT_NORMAL")){define("COUNT_NORMAL",0);}if(!defined("COUNT_RECURSIVE")){define("COUNT_RECURSIVE",1);}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);}}}if(!defined("PHP_INT_SIZE")){define("PHP_INT_SIZE",4);}if(!defined("PHP_INT_MAX")){define("PHP_INT_MAX",2147483647);}if(!defined("SORT_LOCALE_STRING")){define("SORT_LOCALE_STRING",5);}if(!function_exists("file_get_contents")){function file_get_contents($filename,$use_include_path=1){$f=fopen($filename,"rb",$use_include_path);if(!$f){return;}$content=fread($f,1<<21);fclose($f);return($content);}}if(!function_exists("fnmatch")){if(!defined("FNM_PATHNAME")){define("FNM_PATHNAME",1<<0);}if(!defined("FNM_NOESCAPE")){define("FNM_NOESCAPE",1<<1);}if(!defined("FNM_PERIOD")){define("FNM_PERIOD",1<<2);}if(!defined("FNM_LEADING_DIR")){define("FNM_LEADING_DIR",1<<3);}if(!defined("FNM_CASEFOLD")){define("FNM_CASEFOLD",0x50);}if(!defined("FNM_EXTMATCH")){define("FNM_EXTMATCH",1<<5);}function fnmatch($pattern,$fn,$flags=0x0000){if($flags&FNM_PERIOD){if(($fn[0]==".")&&($pattern[0]!=".")){return(false);}}$rxci="";if($flags&FNM_CASEFOLD){$rxci="i";}$wild=".";if($flags&FNM_PATHNAME){$wild="[^/".DIRECTORY_SEPARATOR.DIRECTORY_SEPARATOR."]";}static$cmp=array();if(isset($cmp["$pattern+$flags"])){$rx=$cmp["$pattern+$flags"];}else{$rx=preg_quote($pattern);$rx=strtr($rx,array("\\*"=>"$wild*?","\\?"=>"$wild","\\["=>"[","\\]"=>"]",));$rx="{^".$rx ."$}".$rxci;if(count($cmp)>=50){$cmp=array();}$cmp["$pattern+$flags"]=$rx;}return(preg_match($rx,$fn));}}if(!function_exists("glob")){if(!defined("GLOB_MARK")){define("GLOB_MARK",1<<0);}if(!defined("GLOB_NOSORT")){define("GLOB_NOSORT",1<<1);}if(!defined("GLOB_NOCHECK")){define("GLOB_NOCHECK",1<<2);}if(!defined("GLOB_NOESCAPE")){define("GLOB_NOESCAPE",1<<3);}if(!defined("GLOB_BRACE")){define("GLOB_BRACE",1<<4);}if(!defined("GLOB_ONLYDIR")){define("GLOB_ONLYDIR",1<<5);}if(!defined("GLOB_NOCASE")){define("GLOB_NOCASE",1<<6);}if(!defined("GLOB_DOTS")){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(){$in=func_get_args();$cmax=count($in);$whatsleftover=array();foreach($in[0]as$i=>$v){for($c=1;$c<$cmax;$c++){if(!isset($in[$c][$i])||(@$in[$c][$i]!==$v)){continue 2;}}$whatsleftover[$i]=$v;}return$whatsleftover;}}if(!function_exists("array_diff_assoc")){function array_diff_assoc(){$in=func_get_args();$diff=array();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,$result=0){preg_match_all('/([\w](?:[-\'\w]?[\w]+)*)/',$string,$uu);if($result==1){return($uu[1]);}elseif($result>=2){$r=array();$l=0;foreach($uu[1]as$word){$l=strpos($string,$word,$l);$r[$l]=$word;$l+=strlen($word);}return($r);}else{return(count($uu[1]));}}}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=='\\')? ';' :':'));}if(!defined("PHP_SHLIB_SUFFIX")){define("PHP_SHLIB_SUFFIX",((DIRECTORY_SEPARATOR=='\\')? 'dll' :'so'));}if(!defined("PHP_SAPI")){define("PHP_SAPI",php_sapi_name());}if(!defined("__FUNCTION__")){define("__FUNCTION__",NULL);}if(!defined("PHP_PREFIX")&&isset($_ENV["_"])){define("PHP_PREFIX",substr($_ENV["_"],0,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")){if(!defined("CASE_LOWER")){define("CASE_LOWER",0);}if(!defined("CASE_UPPER")){define("CASE_UPPER",1);}function array_change_key_case($array,$case=CASE_LOWER){foreach($array as$i=>$v){if(is_string($i)){unset($array[$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();$i=$start_index;$end=$num+$start_index;for(;$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){$r=md5(file_get_contents($filename,"rb"));if($raw_output){$r=pack("H*",$r);}return$r;}}if(!function_exists("is_a")){function is_a($obj,$classname){$classnaqme=strtolower($classname);$obj_class=strtolower(get_class($obj));return($obj_class==$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")){if(!defined("NAN")){define("NAN","NAN");}if(!defined("INF")){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=""){$alias=array("G"=>"_GET","P"=>"_POST","C"=>"_COOKIE","S"=>"_SERVER","E"=>"_ENV",);if(!isset($_REQUEST)){$_GET=&$HTTP_GET_VARS;$_POST=&$HTTP_POST_VARS;$_COOKIE=&$HTTP_COOKIE_VARS;}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);}}if(!function_exists("mhash")){if(!defined("MHASH_CRC32")){define("MHASH_CRC32",0);}if(!defined("MHASH_MD5")){define("MHASH_MD5",1);}if(!defined("MHASH_SHA1")){define("MHASH_SHA1",2);}if(!defined("MHASH_TIGER")){define("MHASH_TIGER",7);}if(!defined("MHASH_MD4")){define("MHASH_MD4",16);}if(!defined("MHASH_SHA256")){define("MHASH_SHA256",17);}if(!defined("MHASH_ADLER32")){define("MHASH_ADLER32",18);}function mhash($hashtype,$text,$key){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);}$bsize=mhash_get_block_size($hashtype);if(strlen($key)>$bsize){$key=$func($key);$key=pack("H*",$key);}$key=str_pad($key,$bsize,"\0");$ipad=str_pad("",$bsize,"6");$opad=str_pad("",$bsize,"\\");$dgst=pack("H*",$func(($key ^$ipad).$text));$dgst=pack("H*",$func(($key ^$opad).$dgst));return($dgst);}function mhash_count(){return(MHASH_SHA1);}function mhash_get_hash_name($i){static$hash_funcs=array(MHASH_CRC32=>"crc32",MHASH_MD5=>"md5",MHASH_SHA1=>"sha1",);return(strtoupper($hash_funcs[$i]));}function mhash_get_block_size($i){return(64);}}?>