~jlungo/zhris/trunk

« back to all changes in this revision

Viewing changes to classes/pear/XML/RPC.php

  • Committer: Juma Lungo
  • Date: 2017-11-16 08:54:53 UTC
  • Revision ID: juma.lungo@zalongwa.com-20171116085453-q3jxht0gcab8jbya
codebase commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<?php
 
2
 
 
3
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
 
4
 
 
5
/**
 
6
 * PHP implementation of the XML-RPC protocol
 
7
 *
 
8
 * This is a PEAR-ified version of Useful inc's XML-RPC for PHP.
 
9
 * It has support for HTTP transport, proxies and authentication.
 
10
 *
 
11
 * PHP versions 4 and 5
 
12
 *
 
13
 * @category   Web Services
 
14
 * @package    XML_RPC
 
15
 * @author     Edd Dumbill <edd@usefulinc.com>
 
16
 * @author     Stig Bakken <stig@php.net>
 
17
 * @author     Martin Jansen <mj@php.net>
 
18
 * @author     Daniel Convissor <danielc@php.net>
 
19
 * @copyright  1999-2001 Edd Dumbill, 2001-2010 The PHP Group
 
20
 * @license    http://www.php.net/license/3_01.txt  PHP License
 
21
 * @version    SVN: $Id: RPC.php 293238 2010-01-08 03:21:06Z danielc $
 
22
 * @link       http://pear.php.net/package/XML_RPC
 
23
 */
 
24
 
 
25
 
 
26
if (!function_exists('xml_parser_create')) {
 
27
    include_once 'PEAR.php';
 
28
    PEAR::loadExtension('xml');
 
29
}
 
30
 
 
31
/**#@+
 
32
 * Error constants
 
33
 */
 
34
/**
 
35
 * Parameter values don't match parameter types
 
36
 */
 
37
define('XML_RPC_ERROR_INVALID_TYPE', 101);
 
38
/**
 
39
 * Parameter declared to be numeric but the values are not
 
40
 */
 
41
define('XML_RPC_ERROR_NON_NUMERIC_FOUND', 102);
 
42
/**
 
43
 * Communication error
 
44
 */
 
45
define('XML_RPC_ERROR_CONNECTION_FAILED', 103);
 
46
/**
 
47
 * The array or struct has already been started
 
48
 */
 
49
define('XML_RPC_ERROR_ALREADY_INITIALIZED', 104);
 
50
/**
 
51
 * Incorrect parameters submitted
 
52
 */
 
53
define('XML_RPC_ERROR_INCORRECT_PARAMS', 105);
 
54
/**
 
55
 * Programming error by developer
 
56
 */
 
57
define('XML_RPC_ERROR_PROGRAMMING', 106);
 
58
/**#@-*/
 
59
 
 
60
 
 
61
/**
 
62
 * Data types
 
63
 * @global string $GLOBALS['XML_RPC_I4']
 
64
 */
 
65
$GLOBALS['XML_RPC_I4'] = 'i4';
 
66
 
 
67
/**
 
68
 * Data types
 
69
 * @global string $GLOBALS['XML_RPC_Int']
 
70
 */
 
71
$GLOBALS['XML_RPC_Int'] = 'int';
 
72
 
 
73
/**
 
74
 * Data types
 
75
 * @global string $GLOBALS['XML_RPC_Boolean']
 
76
 */
 
77
$GLOBALS['XML_RPC_Boolean'] = 'boolean';
 
78
 
 
79
/**
 
80
 * Data types
 
81
 * @global string $GLOBALS['XML_RPC_Double']
 
82
 */
 
83
$GLOBALS['XML_RPC_Double'] = 'double';
 
84
 
 
85
/**
 
86
 * Data types
 
87
 * @global string $GLOBALS['XML_RPC_String']
 
88
 */
 
89
$GLOBALS['XML_RPC_String'] = 'string';
 
90
 
 
91
/**
 
92
 * Data types
 
93
 * @global string $GLOBALS['XML_RPC_DateTime']
 
94
 */
 
95
$GLOBALS['XML_RPC_DateTime'] = 'dateTime.iso8601';
 
96
 
 
97
/**
 
98
 * Data types
 
99
 * @global string $GLOBALS['XML_RPC_Base64']
 
100
 */
 
101
$GLOBALS['XML_RPC_Base64'] = 'base64';
 
102
 
 
103
/**
 
104
 * Data types
 
105
 * @global string $GLOBALS['XML_RPC_Array']
 
106
 */
 
107
$GLOBALS['XML_RPC_Array'] = 'array';
 
108
 
 
109
/**
 
110
 * Data types
 
111
 * @global string $GLOBALS['XML_RPC_Struct']
 
112
 */
 
113
$GLOBALS['XML_RPC_Struct'] = 'struct';
 
114
 
 
115
 
 
116
/**
 
117
 * Data type meta-types
 
118
 * @global array $GLOBALS['XML_RPC_Types']
 
119
 */
 
120
$GLOBALS['XML_RPC_Types'] = array(
 
121
    $GLOBALS['XML_RPC_I4']       => 1,
 
122
    $GLOBALS['XML_RPC_Int']      => 1,
 
123
    $GLOBALS['XML_RPC_Boolean']  => 1,
 
124
    $GLOBALS['XML_RPC_String']   => 1,
 
125
    $GLOBALS['XML_RPC_Double']   => 1,
 
126
    $GLOBALS['XML_RPC_DateTime'] => 1,
 
127
    $GLOBALS['XML_RPC_Base64']   => 1,
 
128
    $GLOBALS['XML_RPC_Array']    => 2,
 
129
    $GLOBALS['XML_RPC_Struct']   => 3,
 
130
);
 
131
 
 
132
 
 
133
/**
 
134
 * Error message numbers
 
135
 * @global array $GLOBALS['XML_RPC_err']
 
136
 */
 
137
$GLOBALS['XML_RPC_err'] = array(
 
138
    'unknown_method'      => 1,
 
139
    'invalid_return'      => 2,
 
140
    'incorrect_params'    => 3,
 
141
    'introspect_unknown'  => 4,
 
142
    'http_error'          => 5,
 
143
    'not_response_object' => 6,
 
144
    'invalid_request'     => 7,
 
145
);
 
146
 
 
147
/**
 
148
 * Error message strings
 
149
 * @global array $GLOBALS['XML_RPC_str']
 
150
 */
 
151
$GLOBALS['XML_RPC_str'] = array(
 
152
    'unknown_method'      => 'Unknown method',
 
153
    'invalid_return'      => 'Invalid return payload: enable debugging to examine incoming payload',
 
154
    'incorrect_params'    => 'Incorrect parameters passed to method',
 
155
    'introspect_unknown'  => 'Can\'t introspect: method unknown',
 
156
    'http_error'          => 'Didn\'t receive 200 OK from remote server.',
 
157
    'not_response_object' => 'The requested method didn\'t return an XML_RPC_Response object.',
 
158
    'invalid_request'     => 'Invalid request payload',
 
159
);
 
160
 
 
161
 
 
162
/**
 
163
 * Default XML encoding (ISO-8859-1, UTF-8 or US-ASCII)
 
164
 * @global string $GLOBALS['XML_RPC_defencoding']
 
165
 */
 
166
$GLOBALS['XML_RPC_defencoding'] = 'UTF-8';
 
167
 
 
168
/**
 
169
 * User error codes start at 800
 
170
 * @global int $GLOBALS['XML_RPC_erruser']
 
171
 */
 
172
$GLOBALS['XML_RPC_erruser'] = 800;
 
173
 
 
174
/**
 
175
 * XML parse error codes start at 100
 
176
 * @global int $GLOBALS['XML_RPC_errxml']
 
177
 */
 
178
$GLOBALS['XML_RPC_errxml'] = 100;
 
179
 
 
180
 
 
181
/**
 
182
 * Compose backslashes for escaping regexp
 
183
 * @global string $GLOBALS['XML_RPC_backslash']
 
184
 */
 
185
$GLOBALS['XML_RPC_backslash'] = chr(92) . chr(92);
 
186
 
 
187
 
 
188
/**#@+
 
189
 * Which functions to use, depending on whether mbstring is enabled or not.
 
190
 */
 
191
if (function_exists('mb_ereg')) {
 
192
    /** @global string $GLOBALS['XML_RPC_func_ereg'] */
 
193
    $GLOBALS['XML_RPC_func_ereg'] = 'mb_eregi';
 
194
    /** @global string $GLOBALS['XML_RPC_func_ereg_replace'] */
 
195
    $GLOBALS['XML_RPC_func_ereg_replace'] = 'mb_eregi_replace';
 
196
    /** @global string $GLOBALS['XML_RPC_func_split'] */
 
197
    $GLOBALS['XML_RPC_func_split'] = 'mb_split';
 
198
} else {
 
199
    /** @ignore */
 
200
    $GLOBALS['XML_RPC_func_ereg'] = 'eregi';
 
201
    /** @ignore */
 
202
    $GLOBALS['XML_RPC_func_ereg_replace'] = 'eregi_replace';
 
203
    /** @ignore */
 
204
    $GLOBALS['XML_RPC_func_split'] = 'split';
 
205
}
 
206
/**#@-*/
 
207
 
 
208
 
 
209
/**
 
210
 * Should we automatically base64 encode strings that contain characters
 
211
 * which can cause PHP's SAX-based XML parser to break?
 
212
 * @global boolean $GLOBALS['XML_RPC_auto_base64']
 
213
 */
 
214
$GLOBALS['XML_RPC_auto_base64'] = false;
 
215
 
 
216
 
 
217
/**
 
218
 * Valid parents of XML elements
 
219
 * @global array $GLOBALS['XML_RPC_valid_parents']
 
220
 */
 
221
$GLOBALS['XML_RPC_valid_parents'] = array(
 
222
    'BOOLEAN' => array('VALUE'),
 
223
    'I4' => array('VALUE'),
 
224
    'INT' => array('VALUE'),
 
225
    'STRING' => array('VALUE'),
 
226
    'DOUBLE' => array('VALUE'),
 
227
    'DATETIME.ISO8601' => array('VALUE'),
 
228
    'BASE64' => array('VALUE'),
 
229
    'ARRAY' => array('VALUE'),
 
230
    'STRUCT' => array('VALUE'),
 
231
    'PARAM' => array('PARAMS'),
 
232
    'METHODNAME' => array('METHODCALL'),
 
233
    'PARAMS' => array('METHODCALL', 'METHODRESPONSE'),
 
234
    'MEMBER' => array('STRUCT'),
 
235
    'NAME' => array('MEMBER'),
 
236
    'DATA' => array('ARRAY'),
 
237
    'FAULT' => array('METHODRESPONSE'),
 
238
    'VALUE' => array('MEMBER', 'DATA', 'PARAM', 'FAULT'),
 
239
);
 
240
 
 
241
 
 
242
/**
 
243
 * Stores state during parsing
 
244
 *
 
245
 * quick explanation of components:
 
246
 *   + ac     = accumulates values
 
247
 *   + qt     = decides if quotes are needed for evaluation
 
248
 *   + cm     = denotes struct or array (comma needed)
 
249
 *   + isf    = indicates a fault
 
250
 *   + lv     = indicates "looking for a value": implements the logic
 
251
 *               to allow values with no types to be strings
 
252
 *   + params = stores parameters in method calls
 
253
 *   + method = stores method name
 
254
 *
 
255
 * @global array $GLOBALS['XML_RPC_xh']
 
256
 */
 
257
$GLOBALS['XML_RPC_xh'] = array();
 
258
 
 
259
 
 
260
/**
 
261
 * Start element handler for the XML parser
 
262
 *
 
263
 * @return void
 
264
 */
 
265
function XML_RPC_se($parser_resource, $name, $attrs)
 
266
{
 
267
    global $XML_RPC_xh, $XML_RPC_valid_parents;
 
268
 
 
269
    $parser = (int) $parser_resource;
 
270
 
 
271
    // if invalid xmlrpc already detected, skip all processing
 
272
    if ($XML_RPC_xh[$parser]['isf'] >= 2) {
 
273
        return;
 
274
    }
 
275
 
 
276
    // check for correct element nesting
 
277
    // top level element can only be of 2 types
 
278
    if (count($XML_RPC_xh[$parser]['stack']) == 0) {
 
279
        if ($name != 'METHODRESPONSE' && $name != 'METHODCALL') {
 
280
            $XML_RPC_xh[$parser]['isf'] = 2;
 
281
            $XML_RPC_xh[$parser]['isf_reason'] = 'missing top level xmlrpc element';
 
282
            return;
 
283
        }
 
284
    } else {
 
285
        // not top level element: see if parent is OK
 
286
        if (!in_array($XML_RPC_xh[$parser]['stack'][0], $XML_RPC_valid_parents[$name])) {
 
287
            $name = $GLOBALS['XML_RPC_func_ereg_replace']('[^a-zA-Z0-9._-]', '', $name);
 
288
            $XML_RPC_xh[$parser]['isf'] = 2;
 
289
            $XML_RPC_xh[$parser]['isf_reason'] = "xmlrpc element $name cannot be child of {$XML_RPC_xh[$parser]['stack'][0]}";
 
290
            return;
 
291
        }
 
292
    }
 
293
 
 
294
    switch ($name) {
 
295
    case 'STRUCT':
 
296
        $XML_RPC_xh[$parser]['cm']++;
 
297
 
 
298
        // turn quoting off
 
299
        $XML_RPC_xh[$parser]['qt'] = 0;
 
300
 
 
301
        $cur_val = array();
 
302
        $cur_val['value'] = array();
 
303
        $cur_val['members'] = 1;
 
304
        array_unshift($XML_RPC_xh[$parser]['valuestack'], $cur_val);
 
305
        break;
 
306
 
 
307
    case 'ARRAY':
 
308
        $XML_RPC_xh[$parser]['cm']++;
 
309
 
 
310
        // turn quoting off
 
311
        $XML_RPC_xh[$parser]['qt'] = 0;
 
312
 
 
313
        $cur_val = array();
 
314
        $cur_val['value'] = array();
 
315
        $cur_val['members'] = 0;
 
316
        array_unshift($XML_RPC_xh[$parser]['valuestack'], $cur_val);
 
317
        break;
 
318
 
 
319
    case 'NAME':
 
320
        $XML_RPC_xh[$parser]['ac'] = '';
 
321
        break;
 
322
 
 
323
    case 'FAULT':
 
324
        $XML_RPC_xh[$parser]['isf'] = 1;
 
325
        break;
 
326
 
 
327
    case 'PARAM':
 
328
        $XML_RPC_xh[$parser]['valuestack'] = array();
 
329
        break;
 
330
 
 
331
    case 'VALUE':
 
332
        $XML_RPC_xh[$parser]['lv'] = 1;
 
333
        $XML_RPC_xh[$parser]['vt'] = $GLOBALS['XML_RPC_String'];
 
334
        $XML_RPC_xh[$parser]['ac'] = '';
 
335
        $XML_RPC_xh[$parser]['qt'] = 0;
 
336
        // look for a value: if this is still 1 by the
 
337
        // time we reach the first data segment then the type is string
 
338
        // by implication and we need to add in a quote
 
339
        break;
 
340
 
 
341
    case 'I4':
 
342
    case 'INT':
 
343
    case 'STRING':
 
344
    case 'BOOLEAN':
 
345
    case 'DOUBLE':
 
346
    case 'DATETIME.ISO8601':
 
347
    case 'BASE64':
 
348
        $XML_RPC_xh[$parser]['ac'] = ''; // reset the accumulator
 
349
 
 
350
        if ($name == 'DATETIME.ISO8601' || $name == 'STRING') {
 
351
            $XML_RPC_xh[$parser]['qt'] = 1;
 
352
 
 
353
            if ($name == 'DATETIME.ISO8601') {
 
354
                $XML_RPC_xh[$parser]['vt'] = $GLOBALS['XML_RPC_DateTime'];
 
355
            }
 
356
 
 
357
        } elseif ($name == 'BASE64') {
 
358
            $XML_RPC_xh[$parser]['qt'] = 2;
 
359
        } else {
 
360
            // No quoting is required here -- but
 
361
            // at the end of the element we must check
 
362
            // for data format errors.
 
363
            $XML_RPC_xh[$parser]['qt'] = 0;
 
364
        }
 
365
        break;
 
366
 
 
367
    case 'MEMBER':
 
368
        $XML_RPC_xh[$parser]['ac'] = '';
 
369
        break;
 
370
 
 
371
    case 'DATA':
 
372
    case 'METHODCALL':
 
373
    case 'METHODNAME':
 
374
    case 'METHODRESPONSE':
 
375
    case 'PARAMS':
 
376
        // valid elements that add little to processing
 
377
        break;
 
378
    }
 
379
 
 
380
 
 
381
    // Save current element to stack
 
382
    array_unshift($XML_RPC_xh[$parser]['stack'], $name);
 
383
 
 
384
    if ($name != 'VALUE') {
 
385
        $XML_RPC_xh[$parser]['lv'] = 0;
 
386
    }
 
387
}
 
388
 
 
389
/**
 
390
 * End element handler for the XML parser
 
391
 *
 
392
 * @return void
 
393
 */
 
394
function XML_RPC_ee($parser_resource, $name)
 
395
{
 
396
    global $XML_RPC_xh;
 
397
 
 
398
    $parser = (int) $parser_resource;
 
399
 
 
400
    if ($XML_RPC_xh[$parser]['isf'] >= 2) {
 
401
        return;
 
402
    }
 
403
 
 
404
    // push this element from stack
 
405
    // NB: if XML validates, correct opening/closing is guaranteed and
 
406
    // we do not have to check for $name == $curr_elem.
 
407
    // we also checked for proper nesting at start of elements...
 
408
    $curr_elem = array_shift($XML_RPC_xh[$parser]['stack']);
 
409
 
 
410
    switch ($name) {
 
411
    case 'STRUCT':
 
412
    case 'ARRAY':
 
413
    $cur_val = array_shift($XML_RPC_xh[$parser]['valuestack']);
 
414
    $XML_RPC_xh[$parser]['value'] = $cur_val['value'];
 
415
        $XML_RPC_xh[$parser]['vt'] = strtolower($name);
 
416
        $XML_RPC_xh[$parser]['cm']--;
 
417
        break;
 
418
 
 
419
    case 'NAME':
 
420
    $XML_RPC_xh[$parser]['valuestack'][0]['name'] = $XML_RPC_xh[$parser]['ac'];
 
421
        break;
 
422
 
 
423
    case 'BOOLEAN':
 
424
        // special case here: we translate boolean 1 or 0 into PHP
 
425
        // constants true or false
 
426
        if ($XML_RPC_xh[$parser]['ac'] == '1') {
 
427
            $XML_RPC_xh[$parser]['ac'] = 'true';
 
428
        } else {
 
429
            $XML_RPC_xh[$parser]['ac'] = 'false';
 
430
        }
 
431
 
 
432
        $XML_RPC_xh[$parser]['vt'] = strtolower($name);
 
433
        // Drop through intentionally.
 
434
 
 
435
    case 'I4':
 
436
    case 'INT':
 
437
    case 'STRING':
 
438
    case 'DOUBLE':
 
439
    case 'DATETIME.ISO8601':
 
440
    case 'BASE64':
 
441
        if ($XML_RPC_xh[$parser]['qt'] == 1) {
 
442
            // we use double quotes rather than single so backslashification works OK
 
443
            $XML_RPC_xh[$parser]['value'] = $XML_RPC_xh[$parser]['ac'];
 
444
        } elseif ($XML_RPC_xh[$parser]['qt'] == 2) {
 
445
            $XML_RPC_xh[$parser]['value'] = base64_decode($XML_RPC_xh[$parser]['ac']);
 
446
        } elseif ($name == 'BOOLEAN') {
 
447
            $XML_RPC_xh[$parser]['value'] = $XML_RPC_xh[$parser]['ac'];
 
448
        } else {
 
449
            // we have an I4, INT or a DOUBLE
 
450
            // we must check that only 0123456789-.<space> are characters here
 
451
            if (!$GLOBALS['XML_RPC_func_ereg']("^[+-]?[0123456789 \t\.]+$", $XML_RPC_xh[$parser]['ac'])) {
 
452
                XML_RPC_Base::raiseError('Non-numeric value received in INT or DOUBLE',
 
453
                                         XML_RPC_ERROR_NON_NUMERIC_FOUND);
 
454
                $XML_RPC_xh[$parser]['value'] = XML_RPC_ERROR_NON_NUMERIC_FOUND;
 
455
            } else {
 
456
                // it's ok, add it on
 
457
                $XML_RPC_xh[$parser]['value'] = $XML_RPC_xh[$parser]['ac'];
 
458
            }
 
459
        }
 
460
 
 
461
        $XML_RPC_xh[$parser]['ac'] = '';
 
462
        $XML_RPC_xh[$parser]['qt'] = 0;
 
463
        $XML_RPC_xh[$parser]['lv'] = 3; // indicate we've found a value
 
464
        break;
 
465
 
 
466
    case 'VALUE':
 
467
        if ($XML_RPC_xh[$parser]['vt'] == $GLOBALS['XML_RPC_String']) {
 
468
            if (strlen($XML_RPC_xh[$parser]['ac']) > 0) {
 
469
                $XML_RPC_xh[$parser]['value'] = $XML_RPC_xh[$parser]['ac'];
 
470
            } elseif ($XML_RPC_xh[$parser]['lv'] == 1) {
 
471
                // The <value> element was empty.
 
472
                $XML_RPC_xh[$parser]['value'] = '';
 
473
            }
 
474
        }
 
475
 
 
476
        $temp = new XML_RPC_Value($XML_RPC_xh[$parser]['value'], $XML_RPC_xh[$parser]['vt']);
 
477
 
 
478
        $cur_val = array_shift($XML_RPC_xh[$parser]['valuestack']);
 
479
        if (is_array($cur_val)) {
 
480
            if ($cur_val['members']==0) {
 
481
                $cur_val['value'][] = $temp;
 
482
            } else {
 
483
                $XML_RPC_xh[$parser]['value'] = $temp;
 
484
            }
 
485
            array_unshift($XML_RPC_xh[$parser]['valuestack'], $cur_val);
 
486
        } else {
 
487
            $XML_RPC_xh[$parser]['value'] = $temp;
 
488
        }
 
489
        break;
 
490
 
 
491
    case 'MEMBER':
 
492
        $XML_RPC_xh[$parser]['ac'] = '';
 
493
        $XML_RPC_xh[$parser]['qt'] = 0;
 
494
 
 
495
        $cur_val = array_shift($XML_RPC_xh[$parser]['valuestack']);
 
496
        if (is_array($cur_val)) {
 
497
            if ($cur_val['members']==1) {
 
498
                $cur_val['value'][$cur_val['name']] = $XML_RPC_xh[$parser]['value'];
 
499
            }
 
500
            array_unshift($XML_RPC_xh[$parser]['valuestack'], $cur_val);
 
501
        }
 
502
        break;
 
503
 
 
504
    case 'DATA':
 
505
        $XML_RPC_xh[$parser]['ac'] = '';
 
506
        $XML_RPC_xh[$parser]['qt'] = 0;
 
507
        break;
 
508
 
 
509
    case 'PARAM':
 
510
        $XML_RPC_xh[$parser]['params'][] = $XML_RPC_xh[$parser]['value'];
 
511
        break;
 
512
 
 
513
    case 'METHODNAME':
 
514
    case 'RPCMETHODNAME':
 
515
        $XML_RPC_xh[$parser]['method'] = $GLOBALS['XML_RPC_func_ereg_replace']("^[\n\r\t ]+", '',
 
516
                                                      $XML_RPC_xh[$parser]['ac']);
 
517
        break;
 
518
    }
 
519
 
 
520
    // if it's a valid type name, set the type
 
521
    if (isset($GLOBALS['XML_RPC_Types'][strtolower($name)])) {
 
522
        $XML_RPC_xh[$parser]['vt'] = strtolower($name);
 
523
    }
 
524
}
 
525
 
 
526
/**
 
527
 * Character data handler for the XML parser
 
528
 *
 
529
 * @return void
 
530
 */
 
531
function XML_RPC_cd($parser_resource, $data)
 
532
{
 
533
    global $XML_RPC_xh, $XML_RPC_backslash;
 
534
 
 
535
    $parser = (int) $parser_resource;
 
536
 
 
537
    if ($XML_RPC_xh[$parser]['lv'] != 3) {
 
538
        // "lookforvalue==3" means that we've found an entire value
 
539
        // and should discard any further character data
 
540
 
 
541
        if ($XML_RPC_xh[$parser]['lv'] == 1) {
 
542
            // if we've found text and we're just in a <value> then
 
543
            // turn quoting on, as this will be a string
 
544
            $XML_RPC_xh[$parser]['qt'] = 1;
 
545
            // and say we've found a value
 
546
            $XML_RPC_xh[$parser]['lv'] = 2;
 
547
        }
 
548
 
 
549
        // replace characters that eval would
 
550
        // do special things with
 
551
        if (!isset($XML_RPC_xh[$parser]['ac'])) {
 
552
            $XML_RPC_xh[$parser]['ac'] = '';
 
553
        }
 
554
        $XML_RPC_xh[$parser]['ac'] .= $data;
 
555
    }
 
556
}
 
557
 
 
558
/**
 
559
 * The common methods and properties for all of the XML_RPC classes
 
560
 *
 
561
 * @category   Web Services
 
562
 * @package    XML_RPC
 
563
 * @author     Edd Dumbill <edd@usefulinc.com>
 
564
 * @author     Stig Bakken <stig@php.net>
 
565
 * @author     Martin Jansen <mj@php.net>
 
566
 * @author     Daniel Convissor <danielc@php.net>
 
567
 * @copyright  1999-2001 Edd Dumbill, 2001-2010 The PHP Group
 
568
 * @license    http://www.php.net/license/3_01.txt  PHP License
 
569
 * @version    Release: 1.5.3
 
570
 * @link       http://pear.php.net/package/XML_RPC
 
571
 */
 
572
class XML_RPC_Base {
 
573
 
 
574
    /**
 
575
     * PEAR Error handling
 
576
     *
 
577
     * @return object  PEAR_Error object
 
578
     */
 
579
    function raiseError($msg, $code)
 
580
    {
 
581
        include_once 'PEAR.php';
 
582
        if (is_object(@$this)) {
 
583
            return PEAR::raiseError(get_class($this) . ': ' . $msg, $code);
 
584
        } else {
 
585
            return PEAR::raiseError('XML_RPC: ' . $msg, $code);
 
586
        }
 
587
    }
 
588
 
 
589
    /**
 
590
     * Tell whether something is a PEAR_Error object
 
591
     *
 
592
     * @param mixed $value  the item to check
 
593
     *
 
594
     * @return bool  whether $value is a PEAR_Error object or not
 
595
     *
 
596
     * @access public
 
597
     */
 
598
    function isError($value)
 
599
    {
 
600
        return is_a($value, 'PEAR_Error');
 
601
    }
 
602
}
 
603
 
 
604
/**
 
605
 * The methods and properties for submitting XML RPC requests
 
606
 *
 
607
 * @category   Web Services
 
608
 * @package    XML_RPC
 
609
 * @author     Edd Dumbill <edd@usefulinc.com>
 
610
 * @author     Stig Bakken <stig@php.net>
 
611
 * @author     Martin Jansen <mj@php.net>
 
612
 * @author     Daniel Convissor <danielc@php.net>
 
613
 * @copyright  1999-2001 Edd Dumbill, 2001-2010 The PHP Group
 
614
 * @license    http://www.php.net/license/3_01.txt  PHP License
 
615
 * @version    Release: 1.5.3
 
616
 * @link       http://pear.php.net/package/XML_RPC
 
617
 */
 
618
class XML_RPC_Client extends XML_RPC_Base {
 
619
 
 
620
    /**
 
621
     * The path and name of the RPC server script you want the request to go to
 
622
     * @var string
 
623
     */
 
624
    var $path = '';
 
625
 
 
626
    /**
 
627
     * The name of the remote server to connect to
 
628
     * @var string
 
629
     */
 
630
    var $server = '';
 
631
 
 
632
    /**
 
633
     * The protocol to use in contacting the remote server
 
634
     * @var string
 
635
     */
 
636
    var $protocol = 'http://';
 
637
 
 
638
    /**
 
639
     * The port for connecting to the remote server
 
640
     *
 
641
     * The default is 80 for http:// connections
 
642
     * and 443 for https:// and ssl:// connections.
 
643
     *
 
644
     * @var integer
 
645
     */
 
646
    var $port = 80;
 
647
 
 
648
    /**
 
649
     * A user name for accessing the RPC server
 
650
     * @var string
 
651
     * @see XML_RPC_Client::setCredentials()
 
652
     */
 
653
    var $username = '';
 
654
 
 
655
    /**
 
656
     * A password for accessing the RPC server
 
657
     * @var string
 
658
     * @see XML_RPC_Client::setCredentials()
 
659
     */
 
660
    var $password = '';
 
661
 
 
662
    /**
 
663
     * The name of the proxy server to use, if any
 
664
     * @var string
 
665
     */
 
666
    var $proxy = '';
 
667
 
 
668
    /**
 
669
     * The protocol to use in contacting the proxy server, if any
 
670
     * @var string
 
671
     */
 
672
    var $proxy_protocol = 'http://';
 
673
 
 
674
    /**
 
675
     * The port for connecting to the proxy server
 
676
     *
 
677
     * The default is 8080 for http:// connections
 
678
     * and 443 for https:// and ssl:// connections.
 
679
     *
 
680
     * @var integer
 
681
     */
 
682
    var $proxy_port = 8080;
 
683
 
 
684
    /**
 
685
     * A user name for accessing the proxy server
 
686
     * @var string
 
687
     */
 
688
    var $proxy_user = '';
 
689
 
 
690
    /**
 
691
     * A password for accessing the proxy server
 
692
     * @var string
 
693
     */
 
694
    var $proxy_pass = '';
 
695
 
 
696
    /**
 
697
     * The error number, if any
 
698
     * @var integer
 
699
     */
 
700
    var $errno = 0;
 
701
 
 
702
    /**
 
703
     * The error message, if any
 
704
     * @var string
 
705
     */
 
706
    var $errstr = '';
 
707
 
 
708
    /**
 
709
     * The current debug mode (1 = on, 0 = off)
 
710
     * @var integer
 
711
     */
 
712
    var $debug = 0;
 
713
 
 
714
    /**
 
715
     * The HTTP headers for the current request.
 
716
     * @var string
 
717
     */
 
718
    var $headers = '';
 
719
 
 
720
 
 
721
    /**
 
722
     * Sets the object's properties
 
723
     *
 
724
     * @param string  $path        the path and name of the RPC server script
 
725
     *                              you want the request to go to
 
726
     * @param string  $server      the URL of the remote server to connect to.
 
727
     *                              If this parameter doesn't specify a
 
728
     *                              protocol and $port is 443, ssl:// is
 
729
     *                              assumed.
 
730
     * @param integer $port        a port for connecting to the remote server.
 
731
     *                              Defaults to 80 for http:// connections and
 
732
     *                              443 for https:// and ssl:// connections.
 
733
     * @param string  $proxy       the URL of the proxy server to use, if any.
 
734
     *                              If this parameter doesn't specify a
 
735
     *                              protocol and $port is 443, ssl:// is
 
736
     *                              assumed.
 
737
     * @param integer $proxy_port  a port for connecting to the remote server.
 
738
     *                              Defaults to 8080 for http:// connections and
 
739
     *                              443 for https:// and ssl:// connections.
 
740
     * @param string  $proxy_user  a user name for accessing the proxy server
 
741
     * @param string  $proxy_pass  a password for accessing the proxy server
 
742
     *
 
743
     * @return void
 
744
     */
 
745
    function __construct($path, $server, $port = 0,
 
746
                            $proxy = '', $proxy_port = 0,
 
747
                            $proxy_user = '', $proxy_pass = '')
 
748
    {
 
749
        $this->path       = $path;
 
750
        $this->proxy_user = $proxy_user;
 
751
        $this->proxy_pass = $proxy_pass;
 
752
 
 
753
        $GLOBALS['XML_RPC_func_ereg']('^(http://|https://|ssl://)?(.*)$', $server, $match);
 
754
        if ($match[1] == '') {
 
755
            if ($port == 443) {
 
756
                $this->server   = $match[2];
 
757
                $this->protocol = 'ssl://';
 
758
                $this->port     = 443;
 
759
            } else {
 
760
                $this->server = $match[2];
 
761
                if ($port) {
 
762
                    $this->port = $port;
 
763
                }
 
764
            }
 
765
        } elseif ($match[1] == 'http://') {
 
766
            $this->server = $match[2];
 
767
            if ($port) {
 
768
                $this->port = $port;
 
769
            }
 
770
        } else {
 
771
            $this->server   = $match[2];
 
772
            $this->protocol = 'ssl://';
 
773
            if ($port) {
 
774
                $this->port = $port;
 
775
            } else {
 
776
                $this->port = 443;
 
777
            }
 
778
        }
 
779
 
 
780
        if ($proxy) {
 
781
            $GLOBALS['XML_RPC_func_ereg']('^(http://|https://|ssl://)?(.*)$', $proxy, $match);
 
782
            if ($match[1] == '') {
 
783
                if ($proxy_port == 443) {
 
784
                    $this->proxy          = $match[2];
 
785
                    $this->proxy_protocol = 'ssl://';
 
786
                    $this->proxy_port     = 443;
 
787
                } else {
 
788
                    $this->proxy = $match[2];
 
789
                    if ($proxy_port) {
 
790
                        $this->proxy_port = $proxy_port;
 
791
                    }
 
792
                }
 
793
            } elseif ($match[1] == 'http://') {
 
794
                $this->proxy = $match[2];
 
795
                if ($proxy_port) {
 
796
                    $this->proxy_port = $proxy_port;
 
797
                }
 
798
            } else {
 
799
                $this->proxy          = $match[2];
 
800
                $this->proxy_protocol = 'ssl://';
 
801
                if ($proxy_port) {
 
802
                    $this->proxy_port = $proxy_port;
 
803
                } else {
 
804
                    $this->proxy_port = 443;
 
805
                }
 
806
            }
 
807
        }
 
808
    }
 
809
 
 
810
    /**
 
811
     * Change the current debug mode
 
812
     *
 
813
     * @param int $in  where 1 = on, 0 = off
 
814
     *
 
815
     * @return void
 
816
     */
 
817
    function setDebug($in)
 
818
    {
 
819
        if ($in) {
 
820
            $this->debug = 1;
 
821
        } else {
 
822
            $this->debug = 0;
 
823
        }
 
824
    }
 
825
 
 
826
    /**
 
827
     * Sets whether strings that contain characters which may cause PHP's
 
828
     * SAX-based XML parser to break should be automatically base64 encoded
 
829
     *
 
830
     * This is is a workaround for systems that don't have PHP's mbstring
 
831
     * extension available.
 
832
     *
 
833
     * @param int $in  where 1 = on, 0 = off
 
834
     *
 
835
     * @return void
 
836
     */
 
837
    function setAutoBase64($in)
 
838
    {
 
839
        if ($in) {
 
840
            $GLOBALS['XML_RPC_auto_base64'] = true;
 
841
        } else {
 
842
            $GLOBALS['XML_RPC_auto_base64'] = false;
 
843
        }
 
844
    }
 
845
 
 
846
    /**
 
847
     * Set username and password properties for connecting to the RPC server
 
848
     *
 
849
     * @param string $u  the user name
 
850
     * @param string $p  the password
 
851
     *
 
852
     * @return void
 
853
     *
 
854
     * @see XML_RPC_Client::$username, XML_RPC_Client::$password
 
855
     */
 
856
    function setCredentials($u, $p)
 
857
    {
 
858
        $this->username = $u;
 
859
        $this->password = $p;
 
860
    }
 
861
 
 
862
    /**
 
863
     * Transmit the RPC request via HTTP 1.0 protocol
 
864
     *
 
865
     * @param object $msg       the XML_RPC_Message object
 
866
     * @param int    $timeout   how many seconds to wait for the request
 
867
     *
 
868
     * @return object  an XML_RPC_Response object.  0 is returned if any
 
869
     *                  problems happen.
 
870
     *
 
871
     * @see XML_RPC_Message, XML_RPC_Client::XML_RPC_Client(),
 
872
     *      XML_RPC_Client::setCredentials()
 
873
     */
 
874
    function send($msg, $timeout = 0)
 
875
    {
 
876
        if (!is_a($msg, 'XML_RPC_Message')) {
 
877
            $this->errstr = 'send()\'s $msg parameter must be an'
 
878
                          . ' XML_RPC_Message object.';
 
879
            $this->raiseError($this->errstr, XML_RPC_ERROR_PROGRAMMING);
 
880
            return 0;
 
881
        }
 
882
        $msg->debug = $this->debug;
 
883
        return $this->sendPayloadHTTP10($msg, $this->server, $this->port,
 
884
                                        $timeout, $this->username,
 
885
                                        $this->password);
 
886
    }
 
887
 
 
888
    /**
 
889
     * Transmit the RPC request via HTTP 1.0 protocol
 
890
     *
 
891
     * Requests should be sent using XML_RPC_Client send() rather than
 
892
     * calling this method directly.
 
893
     *
 
894
     * @param object $msg       the XML_RPC_Message object
 
895
     * @param string $server    the server to send the request to
 
896
     * @param int    $port      the server port send the request to
 
897
     * @param int    $timeout   how many seconds to wait for the request
 
898
     *                           before giving up
 
899
     * @param string $username  a user name for accessing the RPC server
 
900
     * @param string $password  a password for accessing the RPC server
 
901
     *
 
902
     * @return object  an XML_RPC_Response object.  0 is returned if any
 
903
     *                  problems happen.
 
904
     *
 
905
     * @access protected
 
906
     * @see XML_RPC_Client::send()
 
907
     */
 
908
    function sendPayloadHTTP10($msg, $server, $port, $timeout = 0,
 
909
                               $username = '', $password = '')
 
910
    {
 
911
        // Pre-emptive BC hacks for fools calling sendPayloadHTTP10() directly
 
912
        if ($username != $this->username) {
 
913
            $this->setCredentials($username, $password);
 
914
        }
 
915
 
 
916
        // Only create the payload if it was not created previously
 
917
        if (empty($msg->payload)) {
 
918
            $msg->createPayload();
 
919
        }
 
920
        $this->createHeaders($msg);
 
921
 
 
922
        $op  = $this->headers . "\r\n\r\n";
 
923
        $op .= $msg->payload;
 
924
 
 
925
        if ($this->debug) {
 
926
            print "\n<pre>---SENT---\n";
 
927
            print $op;
 
928
            print "\n---END---</pre>\n";
 
929
        }
 
930
 
 
931
        /*
 
932
         * If we're using a proxy open a socket to the proxy server
 
933
         * instead to the xml-rpc server
 
934
         */
 
935
        if ($this->proxy) {
 
936
            if ($this->proxy_protocol == 'http://') {
 
937
                $protocol = '';
 
938
            } else {
 
939
                $protocol = $this->proxy_protocol;
 
940
            }
 
941
            if ($timeout > 0) {
 
942
                $fp = @fsockopen($protocol . $this->proxy, $this->proxy_port,
 
943
                                 $this->errno, $this->errstr, $timeout);
 
944
            } else {
 
945
                $fp = @fsockopen($protocol . $this->proxy, $this->proxy_port,
 
946
                                 $this->errno, $this->errstr);
 
947
            }
 
948
        } else {
 
949
            if ($this->protocol == 'http://') {
 
950
                $protocol = '';
 
951
            } else {
 
952
                $protocol = $this->protocol;
 
953
            }
 
954
            if ($timeout > 0) {
 
955
                $fp = @fsockopen($protocol . $server, $port,
 
956
                                 $this->errno, $this->errstr, $timeout);
 
957
            } else {
 
958
                $fp = @fsockopen($protocol . $server, $port,
 
959
                                 $this->errno, $this->errstr);
 
960
            }
 
961
        }
 
962
 
 
963
        /*
 
964
         * Just raising the error without returning it is strange,
 
965
         * but keep it here for backwards compatibility.
 
966
         */
 
967
        if (!$fp && $this->proxy) {
 
968
            $this->raiseError('Connection to proxy server '
 
969
                              . $this->proxy . ':' . $this->proxy_port
 
970
                              . ' failed. ' . $this->errstr,
 
971
                              XML_RPC_ERROR_CONNECTION_FAILED);
 
972
            return 0;
 
973
        } elseif (!$fp) {
 
974
            $this->raiseError('Connection to RPC server '
 
975
                              . $server . ':' . $port
 
976
                              . ' failed. ' . $this->errstr,
 
977
                              XML_RPC_ERROR_CONNECTION_FAILED);
 
978
            return 0;
 
979
        }
 
980
 
 
981
        if ($timeout) {
 
982
            /*
 
983
             * Using socket_set_timeout() because stream_set_timeout()
 
984
             * was introduced in 4.3.0, but we need to support 4.2.0.
 
985
             */
 
986
            socket_set_timeout($fp, $timeout);
 
987
        }
 
988
 
 
989
        if (!fputs($fp, $op, strlen($op))) {
 
990
            $this->errstr = 'Write error';
 
991
            return 0;
 
992
        }
 
993
        $resp = $msg->parseResponseFile($fp);
 
994
 
 
995
        $meta = socket_get_status($fp);
 
996
        if ($meta['timed_out']) {
 
997
            fclose($fp);
 
998
            $this->errstr = 'RPC server did not send response before timeout.';
 
999
            $this->raiseError($this->errstr, XML_RPC_ERROR_CONNECTION_FAILED);
 
1000
            return 0;
 
1001
        }
 
1002
 
 
1003
        fclose($fp);
 
1004
        return $resp;
 
1005
    }
 
1006
 
 
1007
    /**
 
1008
     * Determines the HTTP headers and puts it in the $headers property
 
1009
     *
 
1010
     * @param object $msg       the XML_RPC_Message object
 
1011
     *
 
1012
     * @return boolean  TRUE if okay, FALSE if the message payload isn't set.
 
1013
     *
 
1014
     * @access protected
 
1015
     */
 
1016
    function createHeaders($msg)
 
1017
    {
 
1018
        if (empty($msg->payload)) {
 
1019
            return false;
 
1020
        }
 
1021
        if ($this->proxy) {
 
1022
            $this->headers = 'POST ' . $this->protocol . $this->server;
 
1023
            if ($this->proxy_port) {
 
1024
                $this->headers .= ':' . $this->port;
 
1025
            }
 
1026
        } else {
 
1027
           $this->headers = 'POST ';
 
1028
        }
 
1029
        $this->headers .= $this->path. " HTTP/1.0\r\n";
 
1030
 
 
1031
        $this->headers .= "User-Agent: PEAR XML_RPC\r\n";
 
1032
        $this->headers .= 'Host: ' . $this->server . "\r\n";
 
1033
 
 
1034
        if ($this->proxy && $this->proxy_user) {
 
1035
            $this->headers .= 'Proxy-Authorization: Basic '
 
1036
                     . base64_encode("$this->proxy_user:$this->proxy_pass")
 
1037
                     . "\r\n";
 
1038
        }
 
1039
 
 
1040
        // thanks to Grant Rauscher <grant7@firstworld.net> for this
 
1041
        if ($this->username) {
 
1042
            $this->headers .= 'Authorization: Basic '
 
1043
                     . base64_encode("$this->username:$this->password")
 
1044
                     . "\r\n";
 
1045
        }
 
1046
 
 
1047
        $this->headers .= "Content-Type: text/xml\r\n";
 
1048
        $this->headers .= 'Content-Length: ' . strlen($msg->payload);
 
1049
        return true;
 
1050
    }
 
1051
}
 
1052
 
 
1053
/**
 
1054
 * The methods and properties for interpreting responses to XML RPC requests
 
1055
 *
 
1056
 * @category   Web Services
 
1057
 * @package    XML_RPC
 
1058
 * @author     Edd Dumbill <edd@usefulinc.com>
 
1059
 * @author     Stig Bakken <stig@php.net>
 
1060
 * @author     Martin Jansen <mj@php.net>
 
1061
 * @author     Daniel Convissor <danielc@php.net>
 
1062
 * @copyright  1999-2001 Edd Dumbill, 2001-2010 The PHP Group
 
1063
 * @license    http://www.php.net/license/3_01.txt  PHP License
 
1064
 * @version    Release: 1.5.3
 
1065
 * @link       http://pear.php.net/package/XML_RPC
 
1066
 */
 
1067
class XML_RPC_Response extends XML_RPC_Base
 
1068
{
 
1069
    var $xv;
 
1070
    var $fn;
 
1071
    var $fs;
 
1072
    var $hdrs;
 
1073
 
 
1074
    /**
 
1075
     * @return void
 
1076
     */
 
1077
    function __construct($val, $fcode = 0, $fstr = '')
 
1078
    {
 
1079
        if ($fcode != 0) {
 
1080
            $this->fn = $fcode;
 
1081
            $this->fs = htmlspecialchars($fstr);
 
1082
        } else {
 
1083
            $this->xv = $val;
 
1084
        }
 
1085
    }
 
1086
 
 
1087
    /**
 
1088
     * @return int  the error code
 
1089
     */
 
1090
    function faultCode()
 
1091
    {
 
1092
        if (isset($this->fn)) {
 
1093
            return $this->fn;
 
1094
        } else {
 
1095
            return 0;
 
1096
        }
 
1097
    }
 
1098
 
 
1099
    /**
 
1100
     * @return string  the error string
 
1101
     */
 
1102
    function faultString()
 
1103
    {
 
1104
        return $this->fs;
 
1105
    }
 
1106
 
 
1107
    /**
 
1108
     * @return mixed  the value
 
1109
     */
 
1110
    function value()
 
1111
    {
 
1112
        return $this->xv;
 
1113
    }
 
1114
 
 
1115
    /**
 
1116
     * @return string  the error message in XML format
 
1117
     */
 
1118
    function serialize()
 
1119
    {
 
1120
        $rs = "<methodResponse>\n";
 
1121
        if ($this->fn) {
 
1122
            $rs .= "<fault>
 
1123
  <value>
 
1124
    <struct>
 
1125
      <member>
 
1126
        <name>faultCode</name>
 
1127
        <value><int>" . $this->fn . "</int></value>
 
1128
      </member>
 
1129
      <member>
 
1130
        <name>faultString</name>
 
1131
        <value><string>" . $this->fs . "</string></value>
 
1132
      </member>
 
1133
    </struct>
 
1134
  </value>
 
1135
</fault>";
 
1136
        } else {
 
1137
            $rs .= "<params>\n<param>\n" . $this->xv->serialize() .
 
1138
        "</param>\n</params>";
 
1139
        }
 
1140
        $rs .= "\n</methodResponse>";
 
1141
        return $rs;
 
1142
    }
 
1143
}
 
1144
 
 
1145
/**
 
1146
 * The methods and properties for composing XML RPC messages
 
1147
 *
 
1148
 * @category   Web Services
 
1149
 * @package    XML_RPC
 
1150
 * @author     Edd Dumbill <edd@usefulinc.com>
 
1151
 * @author     Stig Bakken <stig@php.net>
 
1152
 * @author     Martin Jansen <mj@php.net>
 
1153
 * @author     Daniel Convissor <danielc@php.net>
 
1154
 * @copyright  1999-2001 Edd Dumbill, 2001-2010 The PHP Group
 
1155
 * @license    http://www.php.net/license/3_01.txt  PHP License
 
1156
 * @version    Release: 1.5.3
 
1157
 * @link       http://pear.php.net/package/XML_RPC
 
1158
 */
 
1159
class XML_RPC_Message extends XML_RPC_Base
 
1160
{
 
1161
    /**
 
1162
     * Should the payload's content be passed through mb_convert_encoding()?
 
1163
     *
 
1164
     * @see XML_RPC_Message::setConvertPayloadEncoding()
 
1165
     * @since Property available since Release 1.5.1
 
1166
     * @var boolean
 
1167
     */
 
1168
    var $convert_payload_encoding = false;
 
1169
 
 
1170
    /**
 
1171
     * The current debug mode (1 = on, 0 = off)
 
1172
     * @var integer
 
1173
     */
 
1174
    var $debug = 0;
 
1175
 
 
1176
    /**
 
1177
     * The encoding to be used for outgoing messages
 
1178
     *
 
1179
     * Defaults to the value of <var>$GLOBALS['XML_RPC_defencoding']</var>
 
1180
     *
 
1181
     * @var string
 
1182
     * @see XML_RPC_Message::setSendEncoding(),
 
1183
     *      $GLOBALS['XML_RPC_defencoding'], XML_RPC_Message::xml_header()
 
1184
     */
 
1185
    var $send_encoding = '';
 
1186
 
 
1187
    /**
 
1188
     * The method presently being evaluated
 
1189
     * @var string
 
1190
     */
 
1191
    var $methodname = '';
 
1192
 
 
1193
    /**
 
1194
     * @var array
 
1195
     */
 
1196
    var $params = array();
 
1197
 
 
1198
    /**
 
1199
     * The XML message being generated
 
1200
     * @var string
 
1201
     */
 
1202
    var $payload = '';
 
1203
 
 
1204
    /**
 
1205
     * Should extra line breaks be removed from the payload?
 
1206
     * @since Property available since Release 1.4.6
 
1207
     * @var boolean
 
1208
     */
 
1209
    var $remove_extra_lines = true;
 
1210
 
 
1211
    /**
 
1212
     * The XML response from the remote server
 
1213
     * @since Property available since Release 1.4.6
 
1214
     * @var string
 
1215
     */
 
1216
    var $response_payload = '';
 
1217
 
 
1218
 
 
1219
    /**
 
1220
     * @return void
 
1221
     */
 
1222
    function __construct($meth, $pars = 0)
 
1223
    {
 
1224
        $this->methodname = $meth;
 
1225
        if (is_array($pars) && sizeof($pars) > 0) {
 
1226
            for ($i = 0; $i < sizeof($pars); $i++) {
 
1227
                $this->addParam($pars[$i]);
 
1228
            }
 
1229
        }
 
1230
    }
 
1231
 
 
1232
    /**
 
1233
     * Produces the XML declaration including the encoding attribute
 
1234
     *
 
1235
     * The encoding is determined by this class' <var>$send_encoding</var>
 
1236
     * property.  If the <var>$send_encoding</var> property is not set, use
 
1237
     * <var>$GLOBALS['XML_RPC_defencoding']</var>.
 
1238
     *
 
1239
     * @return string  the XML declaration and <methodCall> element
 
1240
     *
 
1241
     * @see XML_RPC_Message::setSendEncoding(),
 
1242
     *      XML_RPC_Message::$send_encoding, $GLOBALS['XML_RPC_defencoding']
 
1243
     */
 
1244
    function xml_header()
 
1245
    {
 
1246
        global $XML_RPC_defencoding;
 
1247
 
 
1248
        if (!$this->send_encoding) {
 
1249
            $this->send_encoding = $XML_RPC_defencoding;
 
1250
        }
 
1251
        return '<?xml version="1.0" encoding="' . $this->send_encoding . '"?>'
 
1252
               . "\n<methodCall>\n";
 
1253
    }
 
1254
 
 
1255
    /**
 
1256
     * @return string  the closing </methodCall> tag
 
1257
     */
 
1258
    function xml_footer()
 
1259
    {
 
1260
        return "</methodCall>\n";
 
1261
    }
 
1262
 
 
1263
    /**
 
1264
     * Fills the XML_RPC_Message::$payload property
 
1265
     *
 
1266
     * Part of the process makes sure all line endings are in DOS format
 
1267
     * (CRLF), which is probably required by specifications.
 
1268
     *
 
1269
     * If XML_RPC_Message::setConvertPayloadEncoding() was set to true,
 
1270
     * the payload gets passed through mb_convert_encoding()
 
1271
     * to ensure the payload matches the encoding set in the
 
1272
     * XML declaration.  The encoding type can be manually set via
 
1273
     * XML_RPC_Message::setSendEncoding().
 
1274
     *
 
1275
     * @return void
 
1276
     *
 
1277
     * @uses XML_RPC_Message::xml_header(), XML_RPC_Message::xml_footer()
 
1278
     * @see XML_RPC_Message::setSendEncoding(), $GLOBALS['XML_RPC_defencoding'],
 
1279
     *      XML_RPC_Message::setConvertPayloadEncoding()
 
1280
     */
 
1281
    function createPayload()
 
1282
    {
 
1283
        $this->payload = $this->xml_header();
 
1284
        $this->payload .= '<methodName>' . $this->methodname . "</methodName>\n";
 
1285
        $this->payload .= "<params>\n";
 
1286
        for ($i = 0; $i < sizeof($this->params); $i++) {
 
1287
            $p = $this->params[$i];
 
1288
            $this->payload .= "<param>\n" . $p->serialize() . "</param>\n";
 
1289
        }
 
1290
        $this->payload .= "</params>\n";
 
1291
        $this->payload .= $this->xml_footer();
 
1292
        if ($this->remove_extra_lines) {
 
1293
            $this->payload = $GLOBALS['XML_RPC_func_ereg_replace']("[\r\n]+", "\r\n", $this->payload);
 
1294
        } else {
 
1295
            $this->payload = $GLOBALS['XML_RPC_func_ereg_replace']("\r\n|\n|\r|\n\r", "\r\n", $this->payload);
 
1296
        }
 
1297
        if ($this->convert_payload_encoding) {
 
1298
            $this->payload = mb_convert_encoding($this->payload, $this->send_encoding);
 
1299
        }
 
1300
    }
 
1301
 
 
1302
    /**
 
1303
     * @return string  the name of the method
 
1304
     */
 
1305
    function method($meth = '')
 
1306
    {
 
1307
        if ($meth != '') {
 
1308
            $this->methodname = $meth;
 
1309
        }
 
1310
        return $this->methodname;
 
1311
    }
 
1312
 
 
1313
    /**
 
1314
     * @return string  the payload
 
1315
     */
 
1316
    function serialize()
 
1317
    {
 
1318
        $this->createPayload();
 
1319
        return $this->payload;
 
1320
    }
 
1321
 
 
1322
    /**
 
1323
     * @return void
 
1324
     */
 
1325
    function addParam($par)
 
1326
    {
 
1327
        $this->params[] = $par;
 
1328
    }
 
1329
 
 
1330
    /**
 
1331
     * Obtains an XML_RPC_Value object for the given parameter
 
1332
     *
 
1333
     * @param int $i  the index number of the parameter to obtain
 
1334
     *
 
1335
     * @return object  the XML_RPC_Value object.
 
1336
     *                  If the parameter doesn't exist, an XML_RPC_Response object.
 
1337
     *
 
1338
     * @since Returns XML_RPC_Response object on error since Release 1.3.0
 
1339
     */
 
1340
    function getParam($i)
 
1341
    {
 
1342
        global $XML_RPC_err, $XML_RPC_str;
 
1343
 
 
1344
        if (isset($this->params[$i])) {
 
1345
            return $this->params[$i];
 
1346
        } else {
 
1347
            $this->raiseError('The submitted request did not contain this parameter',
 
1348
                              XML_RPC_ERROR_INCORRECT_PARAMS);
 
1349
            return new XML_RPC_Response(0, $XML_RPC_err['incorrect_params'],
 
1350
                                        $XML_RPC_str['incorrect_params']);
 
1351
        }
 
1352
    }
 
1353
 
 
1354
    /**
 
1355
     * @return int  the number of parameters
 
1356
     */
 
1357
    function getNumParams()
 
1358
    {
 
1359
        return sizeof($this->params);
 
1360
    }
 
1361
 
 
1362
    /**
 
1363
     * Sets whether the payload's content gets passed through
 
1364
     * mb_convert_encoding()
 
1365
     *
 
1366
     * Returns PEAR_ERROR object if mb_convert_encoding() isn't available.
 
1367
     *
 
1368
     * @param int $in  where 1 = on, 0 = off
 
1369
     *
 
1370
     * @return void
 
1371
     *
 
1372
     * @see XML_RPC_Message::setSendEncoding()
 
1373
     * @since Method available since Release 1.5.1
 
1374
     */
 
1375
    function setConvertPayloadEncoding($in)
 
1376
    {
 
1377
        if ($in && !function_exists('mb_convert_encoding')) {
 
1378
            return $this->raiseError('mb_convert_encoding() is not available',
 
1379
                              XML_RPC_ERROR_PROGRAMMING);
 
1380
        }
 
1381
        $this->convert_payload_encoding = $in;
 
1382
    }
 
1383
 
 
1384
    /**
 
1385
     * Sets the XML declaration's encoding attribute
 
1386
     *
 
1387
     * @param string $type  the encoding type (ISO-8859-1, UTF-8 or US-ASCII)
 
1388
     *
 
1389
     * @return void
 
1390
     *
 
1391
     * @see XML_RPC_Message::setConvertPayloadEncoding(), XML_RPC_Message::xml_header()
 
1392
     * @since Method available since Release 1.2.0
 
1393
     */
 
1394
    function setSendEncoding($type)
 
1395
    {
 
1396
        $this->send_encoding = $type;
 
1397
    }
 
1398
 
 
1399
    /**
 
1400
     * Determine the XML's encoding via the encoding attribute
 
1401
     * in the XML declaration
 
1402
     *
 
1403
     * If the encoding parameter is not set or is not ISO-8859-1, UTF-8
 
1404
     * or US-ASCII, $XML_RPC_defencoding will be returned.
 
1405
     *
 
1406
     * @param string $data  the XML that will be parsed
 
1407
     *
 
1408
     * @return string  the encoding to be used
 
1409
     *
 
1410
     * @link   http://php.net/xml_parser_create
 
1411
     * @since  Method available since Release 1.2.0
 
1412
     */
 
1413
    function getEncoding($data)
 
1414
    {
 
1415
        global $XML_RPC_defencoding;
 
1416
 
 
1417
        if ($GLOBALS['XML_RPC_func_ereg']('<\?xml[^>]*[:space:]*encoding[:space:]*=[:space:]*[\'"]([^"\']*)[\'"]',
 
1418
                       $data, $match))
 
1419
        {
 
1420
            $match[1] = trim(strtoupper($match[1]));
 
1421
            switch ($match[1]) {
 
1422
                case 'ISO-8859-1':
 
1423
                case 'UTF-8':
 
1424
                case 'US-ASCII':
 
1425
                    return $match[1];
 
1426
                    break;
 
1427
 
 
1428
                default:
 
1429
                    return $XML_RPC_defencoding;
 
1430
            }
 
1431
        } else {
 
1432
            return $XML_RPC_defencoding;
 
1433
        }
 
1434
    }
 
1435
 
 
1436
    /**
 
1437
     * @return object  a new XML_RPC_Response object
 
1438
     */
 
1439
    function parseResponseFile($fp)
 
1440
    {
 
1441
        $ipd = '';
 
1442
        while ($data = @fread($fp, 8192)) {
 
1443
            $ipd .= $data;
 
1444
        }
 
1445
        return $this->parseResponse($ipd);
 
1446
    }
 
1447
 
 
1448
    /**
 
1449
     * @return object  a new XML_RPC_Response object
 
1450
     */
 
1451
    function parseResponse($data = '')
 
1452
    {
 
1453
        global $XML_RPC_xh, $XML_RPC_err, $XML_RPC_str, $XML_RPC_defencoding;
 
1454
 
 
1455
        $encoding = $this->getEncoding($data);
 
1456
        $parser_resource = xml_parser_create($encoding);
 
1457
        $parser = (int) $parser_resource;
 
1458
 
 
1459
        $XML_RPC_xh = array();
 
1460
        $XML_RPC_xh[$parser] = array();
 
1461
 
 
1462
        $XML_RPC_xh[$parser]['cm'] = 0;
 
1463
        $XML_RPC_xh[$parser]['isf'] = 0;
 
1464
        $XML_RPC_xh[$parser]['ac'] = '';
 
1465
        $XML_RPC_xh[$parser]['qt'] = '';
 
1466
        $XML_RPC_xh[$parser]['stack'] = array();
 
1467
        $XML_RPC_xh[$parser]['valuestack'] = array();
 
1468
 
 
1469
        xml_parser_set_option($parser_resource, XML_OPTION_CASE_FOLDING, true);
 
1470
        xml_set_element_handler($parser_resource, 'XML_RPC_se', 'XML_RPC_ee');
 
1471
        xml_set_character_data_handler($parser_resource, 'XML_RPC_cd');
 
1472
 
 
1473
        $hdrfnd = 0;
 
1474
        if ($this->debug) {
 
1475
            print "\n<pre>---GOT---\n";
 
1476
            print isset($_SERVER['SERVER_PROTOCOL']) ? htmlspecialchars($data) : $data;
 
1477
            print "\n---END---</pre>\n";
 
1478
        }
 
1479
 
 
1480
        // See if response is a 200 or a 100 then a 200, else raise error.
 
1481
        // But only do this if we're using the HTTP protocol.
 
1482
        if ($GLOBALS['XML_RPC_func_ereg']('^HTTP', $data) &&
 
1483
            !$GLOBALS['XML_RPC_func_ereg']('^HTTP/[0-9\.]+ 200 ', $data) &&
 
1484
            !$GLOBALS['XML_RPC_func_ereg']('^HTTP/[0-9\.]+ 10[0-9]([A-Z ]+)?[\r\n]+HTTP/[0-9\.]+ 200', $data))
 
1485
        {
 
1486
                $errstr = substr($data, 0, strpos($data, "\n") - 1);
 
1487
                error_log('HTTP error, got response: ' . $errstr);
 
1488
                $r = new XML_RPC_Response(0, $XML_RPC_err['http_error'],
 
1489
                                          $XML_RPC_str['http_error'] . ' (' .
 
1490
                                          $errstr . ')');
 
1491
                xml_parser_free($parser_resource);
 
1492
                return $r;
 
1493
        }
 
1494
 
 
1495
        // gotta get rid of headers here
 
1496
        if (!$hdrfnd && ($brpos = strpos($data,"\r\n\r\n"))) {
 
1497
            $XML_RPC_xh[$parser]['ha'] = substr($data, 0, $brpos);
 
1498
            $data = substr($data, $brpos + 4);
 
1499
            $hdrfnd = 1;
 
1500
        }
 
1501
 
 
1502
        /*
 
1503
         * be tolerant of junk after methodResponse
 
1504
         * (e.g. javascript automatically inserted by free hosts)
 
1505
         * thanks to Luca Mariano <luca.mariano@email.it>
 
1506
         */
 
1507
        $data = substr($data, 0, strpos($data, "</methodResponse>") + 17);
 
1508
        $this->response_payload = $data;
 
1509
 
 
1510
        if (!xml_parse($parser_resource, $data, sizeof($data))) {
 
1511
            // thanks to Peter Kocks <peter.kocks@baygate.com>
 
1512
            if (xml_get_current_line_number($parser_resource) == 1) {
 
1513
                $errstr = 'XML error at line 1, check URL';
 
1514
            } else {
 
1515
                $errstr = sprintf('XML error: %s at line %d',
 
1516
                                  xml_error_string(xml_get_error_code($parser_resource)),
 
1517
                                  xml_get_current_line_number($parser_resource));
 
1518
            }
 
1519
            error_log($errstr);
 
1520
            $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'],
 
1521
                                      $XML_RPC_str['invalid_return']);
 
1522
            xml_parser_free($parser_resource);
 
1523
            return $r;
 
1524
        }
 
1525
 
 
1526
        xml_parser_free($parser_resource);
 
1527
 
 
1528
        if ($this->debug) {
 
1529
            print "\n<pre>---PARSED---\n";
 
1530
            var_dump($XML_RPC_xh[$parser]['value']);
 
1531
            print "---END---</pre>\n";
 
1532
        }
 
1533
 
 
1534
        if ($XML_RPC_xh[$parser]['isf'] > 1) {
 
1535
            $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'],
 
1536
                                      $XML_RPC_str['invalid_return'].' '.$XML_RPC_xh[$parser]['isf_reason']);
 
1537
        } elseif (!is_object($XML_RPC_xh[$parser]['value'])) {
 
1538
            // then something odd has happened
 
1539
            // and it's time to generate a client side error
 
1540
            // indicating something odd went on
 
1541
            $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'],
 
1542
                                      $XML_RPC_str['invalid_return']);
 
1543
        } else {
 
1544
            $v = $XML_RPC_xh[$parser]['value'];
 
1545
            if ($XML_RPC_xh[$parser]['isf']) {
 
1546
                $f = $v->structmem('faultCode');
 
1547
                $fs = $v->structmem('faultString');
 
1548
                $r = new XML_RPC_Response($v, $f->scalarval(),
 
1549
                                          $fs->scalarval());
 
1550
            } else {
 
1551
                $r = new XML_RPC_Response($v);
 
1552
            }
 
1553
        }
 
1554
        $r->hdrs = split("\r?\n", $XML_RPC_xh[$parser]['ha'][1]);
 
1555
        return $r;
 
1556
    }
 
1557
}
 
1558
 
 
1559
/**
 
1560
 * The methods and properties that represent data in XML RPC format
 
1561
 *
 
1562
 * @category   Web Services
 
1563
 * @package    XML_RPC
 
1564
 * @author     Edd Dumbill <edd@usefulinc.com>
 
1565
 * @author     Stig Bakken <stig@php.net>
 
1566
 * @author     Martin Jansen <mj@php.net>
 
1567
 * @author     Daniel Convissor <danielc@php.net>
 
1568
 * @copyright  1999-2001 Edd Dumbill, 2001-2010 The PHP Group
 
1569
 * @license    http://www.php.net/license/3_01.txt  PHP License
 
1570
 * @version    Release: 1.5.3
 
1571
 * @link       http://pear.php.net/package/XML_RPC
 
1572
 */
 
1573
class XML_RPC_Value extends XML_RPC_Base
 
1574
{
 
1575
    var $me = array();
 
1576
    var $mytype = 0;
 
1577
 
 
1578
    /**
 
1579
     * @return void
 
1580
     */
 
1581
    function __construct($val = -1, $type = '')
 
1582
    {
 
1583
        $this->me = array();
 
1584
        $this->mytype = 0;
 
1585
        if ($val != -1 || $type != '') {
 
1586
            if ($type == '') {
 
1587
                $type = 'string';
 
1588
            }
 
1589
            if (!array_key_exists($type, $GLOBALS['XML_RPC_Types'])) {
 
1590
                // XXX
 
1591
                // need some way to report this error
 
1592
            } elseif ($GLOBALS['XML_RPC_Types'][$type] == 1) {
 
1593
                $this->addScalar($val, $type);
 
1594
            } elseif ($GLOBALS['XML_RPC_Types'][$type] == 2) {
 
1595
                $this->addArray($val);
 
1596
            } elseif ($GLOBALS['XML_RPC_Types'][$type] == 3) {
 
1597
                $this->addStruct($val);
 
1598
            }
 
1599
        }
 
1600
    }
 
1601
 
 
1602
    /**
 
1603
     * @return int  returns 1 if successful or 0 if there are problems
 
1604
     */
 
1605
    function addScalar($val, $type = 'string')
 
1606
    {
 
1607
        if ($this->mytype == 1) {
 
1608
            $this->raiseError('Scalar can have only one value',
 
1609
                              XML_RPC_ERROR_INVALID_TYPE);
 
1610
            return 0;
 
1611
        }
 
1612
        $typeof = $GLOBALS['XML_RPC_Types'][$type];
 
1613
        if ($typeof != 1) {
 
1614
            $this->raiseError("Not a scalar type (${typeof})",
 
1615
                              XML_RPC_ERROR_INVALID_TYPE);
 
1616
            return 0;
 
1617
        }
 
1618
 
 
1619
        if ($type == $GLOBALS['XML_RPC_Boolean']) {
 
1620
            if (strcasecmp($val, 'true') == 0
 
1621
                || $val == 1
 
1622
                || ($val == true && strcasecmp($val, 'false')))
 
1623
            {
 
1624
                $val = 1;
 
1625
            } else {
 
1626
                $val = 0;
 
1627
            }
 
1628
        }
 
1629
 
 
1630
        if ($this->mytype == 2) {
 
1631
            // we're adding to an array here
 
1632
            $ar = $this->me['array'];
 
1633
            $ar[] = new XML_RPC_Value($val, $type);
 
1634
            $this->me['array'] = $ar;
 
1635
        } else {
 
1636
            // a scalar, so set the value and remember we're scalar
 
1637
            $this->me[$type] = $val;
 
1638
            $this->mytype = $typeof;
 
1639
        }
 
1640
        return 1;
 
1641
    }
 
1642
 
 
1643
    /**
 
1644
     * @return int  returns 1 if successful or 0 if there are problems
 
1645
     */
 
1646
    function addArray($vals)
 
1647
    {
 
1648
        if ($this->mytype != 0) {
 
1649
            $this->raiseError(
 
1650
                    'Already initialized as a [' . $this->kindOf() . ']',
 
1651
                    XML_RPC_ERROR_ALREADY_INITIALIZED);
 
1652
            return 0;
 
1653
        }
 
1654
        $this->mytype = $GLOBALS['XML_RPC_Types']['array'];
 
1655
        $this->me['array'] = $vals;
 
1656
        return 1;
 
1657
    }
 
1658
 
 
1659
    /**
 
1660
     * @return int  returns 1 if successful or 0 if there are problems
 
1661
     */
 
1662
    function addStruct($vals)
 
1663
    {
 
1664
        if ($this->mytype != 0) {
 
1665
            $this->raiseError(
 
1666
                    'Already initialized as a [' . $this->kindOf() . ']',
 
1667
                    XML_RPC_ERROR_ALREADY_INITIALIZED);
 
1668
            return 0;
 
1669
        }
 
1670
        $this->mytype = $GLOBALS['XML_RPC_Types']['struct'];
 
1671
        $this->me['struct'] = $vals;
 
1672
        return 1;
 
1673
    }
 
1674
 
 
1675
    /**
 
1676
     * @return void
 
1677
     */
 
1678
    function dump($ar)
 
1679
    {
 
1680
        reset($ar);
 
1681
        foreach ($ar as $key => $val) {
 
1682
            echo "$key => $val<br />";
 
1683
            if ($key == 'array') {
 
1684
                foreach ($val as $key2 => $val2) {
 
1685
                    echo "-- $key2 => $val2<br />";
 
1686
                }
 
1687
            }
 
1688
        }
 
1689
    }
 
1690
 
 
1691
    /**
 
1692
     * @return string  the data type of the current value
 
1693
     */
 
1694
    function kindOf()
 
1695
    {
 
1696
        switch ($this->mytype) {
 
1697
        case 3:
 
1698
            return 'struct';
 
1699
 
 
1700
        case 2:
 
1701
            return 'array';
 
1702
 
 
1703
        case 1:
 
1704
            return 'scalar';
 
1705
 
 
1706
        default:
 
1707
            return 'undef';
 
1708
        }
 
1709
    }
 
1710
 
 
1711
    /**
 
1712
     * @return string  the data in XML format
 
1713
     */
 
1714
    function serializedata($typ, $val)
 
1715
    {
 
1716
        $rs = '';
 
1717
        if (!array_key_exists($typ, $GLOBALS['XML_RPC_Types'])) {
 
1718
            // XXX
 
1719
            // need some way to report this error
 
1720
            return;
 
1721
        }
 
1722
        switch ($GLOBALS['XML_RPC_Types'][$typ]) {
 
1723
        case 3:
 
1724
            // struct
 
1725
            $rs .= "<struct>\n";
 
1726
            reset($val);
 
1727
            foreach ($val as $key2 => $val2) {
 
1728
                $rs .= "<member><name>${key2}</name>\n";
 
1729
                $rs .= $this->serializeval($val2);
 
1730
                $rs .= "</member>\n";
 
1731
            }
 
1732
            $rs .= '</struct>';
 
1733
            break;
 
1734
 
 
1735
        case 2:
 
1736
            // array
 
1737
            $rs .= "<array>\n<data>\n";
 
1738
            foreach ($val as $value) {
 
1739
                $rs .= $this->serializeval($value);
 
1740
            }
 
1741
            $rs .= "</data>\n</array>";
 
1742
            break;
 
1743
 
 
1744
        case 1:
 
1745
            switch ($typ) {
 
1746
            case $GLOBALS['XML_RPC_Base64']:
 
1747
                $rs .= "<${typ}>" . base64_encode($val) . "</${typ}>";
 
1748
                break;
 
1749
            case $GLOBALS['XML_RPC_Boolean']:
 
1750
                $rs .= "<${typ}>" . ($val ? '1' : '0') . "</${typ}>";
 
1751
                break;
 
1752
            case $GLOBALS['XML_RPC_String']:
 
1753
                $rs .= "<${typ}>" . htmlspecialchars($val). "</${typ}>";
 
1754
                break;
 
1755
            default:
 
1756
                $rs .= "<${typ}>${val}</${typ}>";
 
1757
            }
 
1758
        }
 
1759
        return $rs;
 
1760
    }
 
1761
 
 
1762
    /**
 
1763
     * @return string  the data in XML format
 
1764
     */
 
1765
    function serialize()
 
1766
    {
 
1767
        return $this->serializeval($this);
 
1768
    }
 
1769
 
 
1770
    /**
 
1771
     * @return string  the data in XML format
 
1772
     */
 
1773
    function serializeval($o)
 
1774
    {
 
1775
        if (!is_object($o) || empty($o->me) || !is_array($o->me)) {
 
1776
            return '';
 
1777
        }
 
1778
        $ar = $o->me;
 
1779
        reset($ar);
 
1780
        list($typ, $val) = each($ar);
 
1781
        return '<value>' .  $this->serializedata($typ, $val) .  "</value>\n";
 
1782
    }
 
1783
 
 
1784
    /**
 
1785
     * @return mixed  the contents of the element requested
 
1786
     */
 
1787
    function structmem($m)
 
1788
    {
 
1789
        return $this->me['struct'][$m];
 
1790
    }
 
1791
 
 
1792
    /**
 
1793
     * @return void
 
1794
     */
 
1795
    function structreset()
 
1796
    {
 
1797
        reset($this->me['struct']);
 
1798
    }
 
1799
 
 
1800
    /**
 
1801
     * @return  the key/value pair of the struct's current element
 
1802
     */
 
1803
    function structeach()
 
1804
    {
 
1805
        return each($this->me['struct']);
 
1806
    }
 
1807
 
 
1808
    /**
 
1809
     * @return mixed  the current value
 
1810
     */
 
1811
    function getval()
 
1812
    {
 
1813
        // UNSTABLE
 
1814
 
 
1815
        reset($this->me);
 
1816
        $b = current($this->me);
 
1817
 
 
1818
        // contributed by I Sofer, 2001-03-24
 
1819
        // add support for nested arrays to scalarval
 
1820
        // i've created a new method here, so as to
 
1821
        // preserve back compatibility
 
1822
 
 
1823
        if (is_array($b)) {
 
1824
            foreach ($b as $id => $cont) {
 
1825
                $b[$id] = $cont->scalarval();
 
1826
            }
 
1827
        }
 
1828
 
 
1829
        // add support for structures directly encoding php objects
 
1830
        if (is_object($b)) {
 
1831
            $t = get_object_vars($b);
 
1832
            foreach ($t as $id => $cont) {
 
1833
                $t[$id] = $cont->scalarval();
 
1834
            }
 
1835
            foreach ($t as $id => $cont) {
 
1836
                $b->$id = $cont;
 
1837
            }
 
1838
        }
 
1839
 
 
1840
        // end contrib
 
1841
        return $b;
 
1842
    }
 
1843
 
 
1844
    /**
 
1845
     * @return mixed  the current element's scalar value.  If the value is
 
1846
     *                 not scalar, FALSE is returned.
 
1847
     */
 
1848
    function scalarval()
 
1849
    {
 
1850
        reset($this->me);
 
1851
        $v = current($this->me);
 
1852
        if (!is_scalar($v)) {
 
1853
            $v = false;
 
1854
        }
 
1855
        return $v;
 
1856
    }
 
1857
 
 
1858
    /**
 
1859
     * @return string
 
1860
     */
 
1861
    function scalartyp()
 
1862
    {
 
1863
        reset($this->me);
 
1864
        $a = key($this->me);
 
1865
        if ($a == $GLOBALS['XML_RPC_I4']) {
 
1866
            $a = $GLOBALS['XML_RPC_Int'];
 
1867
        }
 
1868
        return $a;
 
1869
    }
 
1870
 
 
1871
    /**
 
1872
     * @return mixed  the struct's current element
 
1873
     */
 
1874
    function arraymem($m)
 
1875
    {
 
1876
        return $this->me['array'][$m];
 
1877
    }
 
1878
 
 
1879
    /**
 
1880
     * @return int  the number of elements in the array
 
1881
     */
 
1882
    function arraysize()
 
1883
    {
 
1884
        reset($this->me);
 
1885
        list($a, $b) = each($this->me);
 
1886
        return sizeof($b);
 
1887
    }
 
1888
 
 
1889
    /**
 
1890
     * Determines if the item submitted is an XML_RPC_Value object
 
1891
     *
 
1892
     * @param mixed $val  the variable to be evaluated
 
1893
     *
 
1894
     * @return bool  TRUE if the item is an XML_RPC_Value object
 
1895
     *
 
1896
     * @static
 
1897
     * @since Method available since Release 1.3.0
 
1898
     */
 
1899
    function isValue($val)
 
1900
    {
 
1901
        return (strtolower(get_class($val)) == 'xml_rpc_value');
 
1902
    }
 
1903
}
 
1904
 
 
1905
/**
 
1906
 * Return an ISO8601 encoded string
 
1907
 *
 
1908
 * While timezones ought to be supported, the XML-RPC spec says:
 
1909
 *
 
1910
 * "Don't assume a timezone. It should be specified by the server in its
 
1911
 * documentation what assumptions it makes about timezones."
 
1912
 *
 
1913
 * This routine always assumes localtime unless $utc is set to 1, in which
 
1914
 * case UTC is assumed and an adjustment for locale is made when encoding.
 
1915
 *
 
1916
 * @return string  the formatted date
 
1917
 */
 
1918
function XML_RPC_iso8601_encode($timet, $utc = 0)
 
1919
{
 
1920
    if (!$utc) {
 
1921
        $t = strftime('%Y%m%dT%H:%M:%S', $timet);
 
1922
    } else {
 
1923
        if (function_exists('gmstrftime')) {
 
1924
            // gmstrftime doesn't exist in some versions
 
1925
            // of PHP
 
1926
            $t = gmstrftime('%Y%m%dT%H:%M:%S', $timet);
 
1927
        } else {
 
1928
            $t = strftime('%Y%m%dT%H:%M:%S', $timet - date('Z'));
 
1929
        }
 
1930
    }
 
1931
    return $t;
 
1932
}
 
1933
 
 
1934
/**
 
1935
 * Convert a datetime string into a Unix timestamp
 
1936
 *
 
1937
 * While timezones ought to be supported, the XML-RPC spec says:
 
1938
 *
 
1939
 * "Don't assume a timezone. It should be specified by the server in its
 
1940
 * documentation what assumptions it makes about timezones."
 
1941
 *
 
1942
 * This routine always assumes localtime unless $utc is set to 1, in which
 
1943
 * case UTC is assumed and an adjustment for locale is made when encoding.
 
1944
 *
 
1945
 * @return int  the unix timestamp of the date submitted
 
1946
 */
 
1947
function XML_RPC_iso8601_decode($idate, $utc = 0)
 
1948
{
 
1949
    $t = 0;
 
1950
    if ($GLOBALS['XML_RPC_func_ereg']('([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})', $idate, $regs)) {
 
1951
        if ($utc) {
 
1952
            $t = gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
 
1953
        } else {
 
1954
            $t = mktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
 
1955
        }
 
1956
    }
 
1957
    return $t;
 
1958
}
 
1959
 
 
1960
/**
 
1961
 * Converts an XML_RPC_Value object into native PHP types
 
1962
 *
 
1963
 * @param object $XML_RPC_val  the XML_RPC_Value object to decode
 
1964
 *
 
1965
 * @return mixed  the PHP values
 
1966
 */
 
1967
function XML_RPC_decode($XML_RPC_val)
 
1968
{
 
1969
    $kind = $XML_RPC_val->kindOf();
 
1970
 
 
1971
    if ($kind == 'scalar') {
 
1972
        return $XML_RPC_val->scalarval();
 
1973
 
 
1974
    } elseif ($kind == 'array') {
 
1975
        $size = $XML_RPC_val->arraysize();
 
1976
        $arr = array();
 
1977
        for ($i = 0; $i < $size; $i++) {
 
1978
            $arr[] = XML_RPC_decode($XML_RPC_val->arraymem($i));
 
1979
        }
 
1980
        return $arr;
 
1981
 
 
1982
    } elseif ($kind == 'struct') {
 
1983
        $XML_RPC_val->structreset();
 
1984
        $arr = array();
 
1985
        while (list($key, $value) = $XML_RPC_val->structeach()) {
 
1986
            $arr[$key] = XML_RPC_decode($value);
 
1987
        }
 
1988
        return $arr;
 
1989
    }
 
1990
}
 
1991
 
 
1992
/**
 
1993
 * Converts native PHP types into an XML_RPC_Value object
 
1994
 *
 
1995
 * @param mixed $php_val  the PHP value or variable you want encoded
 
1996
 *
 
1997
 * @return object  the XML_RPC_Value object
 
1998
 */
 
1999
function XML_RPC_encode($php_val)
 
2000
{
 
2001
    $type = gettype($php_val);
 
2002
    $XML_RPC_val = new XML_RPC_Value;
 
2003
 
 
2004
    switch ($type) {
 
2005
    case 'array':
 
2006
        if (empty($php_val)) {
 
2007
            $XML_RPC_val->addArray($php_val);
 
2008
            break;
 
2009
        }
 
2010
        $tmp = array_diff(array_keys($php_val), range(0, count($php_val)-1));
 
2011
        if (empty($tmp)) {
 
2012
           $arr = array();
 
2013
           foreach ($php_val as $k => $v) {
 
2014
               $arr[$k] = XML_RPC_encode($v);
 
2015
           }
 
2016
           $XML_RPC_val->addArray($arr);
 
2017
           break;
 
2018
        }
 
2019
        // fall though if it's not an enumerated array
 
2020
 
 
2021
    case 'object':
 
2022
        $arr = array();
 
2023
        foreach ($php_val as $k => $v) {
 
2024
            $arr[$k] = XML_RPC_encode($v);
 
2025
        }
 
2026
        $XML_RPC_val->addStruct($arr);
 
2027
        break;
 
2028
 
 
2029
    case 'integer':
 
2030
        $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_Int']);
 
2031
        break;
 
2032
 
 
2033
    case 'double':
 
2034
        $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_Double']);
 
2035
        break;
 
2036
 
 
2037
    case 'string':
 
2038
    case 'NULL':
 
2039
        if ($GLOBALS['XML_RPC_func_ereg']('^[0-9]{8}\T{1}[0-9]{2}\:[0-9]{2}\:[0-9]{2}$', $php_val)) {
 
2040
            $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_DateTime']);
 
2041
        } elseif ($GLOBALS['XML_RPC_auto_base64']
 
2042
                  && $GLOBALS['XML_RPC_func_ereg']("[^ -~\t\r\n]", $php_val))
 
2043
        {
 
2044
            // Characters other than alpha-numeric, punctuation, SP, TAB,
 
2045
            // LF and CR break the XML parser, encode value via Base 64.
 
2046
            $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_Base64']);
 
2047
        } else {
 
2048
            $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_String']);
 
2049
        }
 
2050
        break;
 
2051
 
 
2052
    case 'boolean':
 
2053
        // Add support for encoding/decoding of booleans, since they
 
2054
        // are supported in PHP
 
2055
        // by <G_Giunta_2001-02-29>
 
2056
        $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_Boolean']);
 
2057
        break;
 
2058
 
 
2059
    case 'unknown type':
 
2060
    default:
 
2061
        $XML_RPC_val = false;
 
2062
    }
 
2063
    return $XML_RPC_val;
 
2064
}
 
2065
 
 
2066
/*
 
2067
 * Local variables:
 
2068
 * tab-width: 4
 
2069
 * c-basic-offset: 4
 
2070
 * c-hanging-comment-ender-p: nil
 
2071
 * End:
 
2072
 */
 
2073
 
 
2074
?>