Project

General

Profile

Download (59.7 KB) Statistics
| Branch: | Tag: | Revision:
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
 * LICENSE: License is granted to use or modify this software
14
 * ("XML-RPC for PHP") for commercial or non-commercial use provided the
15
 * copyright of the author is preserved in any distributed or derivative work.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESSED OR
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 *
28
 * @category   Web Services
29
 * @package    XML_RPC
30
 * @author     Edd Dumbill <edd@usefulinc.com>
31
 * @author     Stig Bakken <stig@php.net>
32
 * @author     Martin Jansen <mj@php.net>
33
 * @author     Daniel Convissor <danielc@php.net>
34
 * @copyright  1999-2001 Edd Dumbill, 2001-2006 The PHP Group
35
 * @version    CVS: $Id$
36
 * @link       http://pear.php.net/package/XML_RPC
37
 */
38

    
39

    
40
if (!function_exists('xml_parser_create')) {
41
    include_once 'PEAR.inc';
42
    PEAR::loadExtension('xml');
43
}
44

    
45
/**#@+
46
 * Error constants
47
 */
48
/**
49
 * Parameter values don't match parameter types
50
 */
51
define('XML_RPC_ERROR_INVALID_TYPE', 101);
52
/**
53
 * Parameter declared to be numeric but the values are not
54
 */
55
define('XML_RPC_ERROR_NON_NUMERIC_FOUND', 102);
56
/**
57
 * Communication error
58
 */
59
define('XML_RPC_ERROR_CONNECTION_FAILED', 103);
60
/**
61
 * The array or struct has already been started
62
 */
63
define('XML_RPC_ERROR_ALREADY_INITIALIZED', 104);
64
/**
65
 * Incorrect parameters submitted
66
 */
67
define('XML_RPC_ERROR_INCORRECT_PARAMS', 105);
68
/**
69
 * Programming error by developer
70
 */
71
define('XML_RPC_ERROR_PROGRAMMING', 106);
72
/**#@-*/
73

    
74

    
75
/**
76
 * Data types
77
 * @global string $GLOBALS['XML_RPC_I4']
78
 */
79
$GLOBALS['XML_RPC_I4'] = 'i4';
80

    
81
/**
82
 * Data types
83
 * @global string $GLOBALS['XML_RPC_Int']
84
 */
85
$GLOBALS['XML_RPC_Int'] = 'int';
86

    
87
/**
88
 * Data types
89
 * @global string $GLOBALS['XML_RPC_Boolean']
90
 */
91
$GLOBALS['XML_RPC_Boolean'] = 'boolean';
92

    
93
/**
94
 * Data types
95
 * @global string $GLOBALS['XML_RPC_Double']
96
 */
97
$GLOBALS['XML_RPC_Double'] = 'double';
98

    
99
/**
100
 * Data types
101
 * @global string $GLOBALS['XML_RPC_String']
102
 */
103
$GLOBALS['XML_RPC_String'] = 'string';
104

    
105
/**
106
 * Data types
107
 * @global string $GLOBALS['XML_RPC_DateTime']
108
 */
109
$GLOBALS['XML_RPC_DateTime'] = 'dateTime.iso8601';
110

    
111
/**
112
 * Data types
113
 * @global string $GLOBALS['XML_RPC_Base64']
114
 */
115
$GLOBALS['XML_RPC_Base64'] = 'base64';
116

    
117
/**
118
 * Data types
119
 * @global string $GLOBALS['XML_RPC_Array']
120
 */
121
$GLOBALS['XML_RPC_Array'] = 'array';
122

    
123
/**
124
 * Data types
125
 * @global string $GLOBALS['XML_RPC_Struct']
126
 */
127
$GLOBALS['XML_RPC_Struct'] = 'struct';
128

    
129

    
130
/**
131
 * Data type meta-types
132
 * @global array $GLOBALS['XML_RPC_Types']
133
 */
134
$GLOBALS['XML_RPC_Types'] = array(
135
    $GLOBALS['XML_RPC_I4']       => 1,
136
    $GLOBALS['XML_RPC_Int']      => 1,
137
    $GLOBALS['XML_RPC_Boolean']  => 1,
138
    $GLOBALS['XML_RPC_String']   => 1,
139
    $GLOBALS['XML_RPC_Double']   => 1,
140
    $GLOBALS['XML_RPC_DateTime'] => 1,
141
    $GLOBALS['XML_RPC_Base64']   => 1,
142
    $GLOBALS['XML_RPC_Array']    => 2,
143
    $GLOBALS['XML_RPC_Struct']   => 3,
144
);
145

    
146

    
147
/**
148
 * Error message numbers
149
 * @global array $GLOBALS['XML_RPC_err']
150
 */
151
$GLOBALS['XML_RPC_err'] = array(
152
    'unknown_method'      => 1,
153
    'invalid_return'      => 2,
154
    'incorrect_params'    => 3,
155
    'introspect_unknown'  => 4,
156
    'http_error'          => 5,
157
    'not_response_object' => 6,
158
    'invalid_request'     => 7,
159
);
160

    
161
/**
162
 * Error message strings
163
 * @global array $GLOBALS['XML_RPC_str']
164
 */
165
$GLOBALS['XML_RPC_str'] = array(
166
    'unknown_method'      => 'Unknown method',
167
    'invalid_return'      => 'Invalid return payload: enable debugging to examine incoming payload',
168
    'incorrect_params'    => 'Incorrect parameters passed to method',
169
    'introspect_unknown'  => 'Can\'t introspect: method unknown',
170
    'http_error'          => 'Didn\'t receive 200 OK from remote server.',
171
    'not_response_object' => 'The requested method didn\'t return an XML_RPC_Response object.',
172
    'invalid_request'     => 'Invalid request payload',
173
);
174

    
175

    
176
/**
177
 * Default XML encoding (ISO-8859-1, UTF-8 or US-ASCII)
178
 * @global string $GLOBALS['XML_RPC_defencoding']
179
 */
180
$GLOBALS['XML_RPC_defencoding'] = 'UTF-8';
181

    
182
/**
183
 * User error codes start at 800
184
 * @global int $GLOBALS['XML_RPC_erruser']
185
 */
186
$GLOBALS['XML_RPC_erruser'] = 800;
187

    
188
/**
189
 * XML parse error codes start at 100
190
 * @global int $GLOBALS['XML_RPC_errxml']
191
 */
192
$GLOBALS['XML_RPC_errxml'] = 100;
193

    
194

    
195
/**
196
 * Compose backslashes for escaping regexp
197
 * @global string $GLOBALS['XML_RPC_backslash']
198
 */
199
$GLOBALS['XML_RPC_backslash'] = chr(92) . chr(92);
200

    
201

    
202
/**#@+
203
 * Which functions to use, depending on whether mbstring is enabled or not.
204
 */
205
if (function_exists('mb_ereg')) {
206
    /** @global string $GLOBALS['XML_RPC_func_ereg'] */
207
    $GLOBALS['XML_RPC_func_ereg'] = 'mb_eregi';
208
    /** @global string $GLOBALS['XML_RPC_func_ereg_replace'] */
209
    $GLOBALS['XML_RPC_func_ereg_replace'] = 'mb_eregi_replace';
210
    /** @global string $GLOBALS['XML_RPC_func_split'] */
211
    $GLOBALS['XML_RPC_func_split'] = 'mb_split';
212
} else {
213
    /** @ignore */
214
    $GLOBALS['XML_RPC_func_ereg'] = 'eregi';
215
    /** @ignore */
216
    $GLOBALS['XML_RPC_func_ereg_replace'] = 'eregi_replace';
217
    /** @ignore */
218
    $GLOBALS['XML_RPC_func_split'] = 'split';
219
}
220
/**#@-*/
221

    
222

    
223
/**
224
 * Should we automatically base64 encode strings that contain characters
225
 * which can cause PHP's SAX-based XML parser to break?
226
 * @global boolean $GLOBALS['XML_RPC_auto_base64']
227
 */
228
$GLOBALS['XML_RPC_auto_base64'] = false;
229

    
230

    
231
/**
232
 * Valid parents of XML elements
233
 * @global array $GLOBALS['XML_RPC_valid_parents']
234
 */
235
$GLOBALS['XML_RPC_valid_parents'] = array(
236
    'BOOLEAN' => array('VALUE'),
237
    'I4' => array('VALUE'),
238
    'INT' => array('VALUE'),
239
    'STRING' => array('VALUE'),
240
    'DOUBLE' => array('VALUE'),
241
    'DATETIME.ISO8601' => array('VALUE'),
242
    'BASE64' => array('VALUE'),
243
    'ARRAY' => array('VALUE'),
244
    'STRUCT' => array('VALUE'),
245
    'PARAM' => array('PARAMS'),
246
    'METHODNAME' => array('METHODCALL'),
247
    'PARAMS' => array('METHODCALL', 'METHODRESPONSE'),
248
    'MEMBER' => array('STRUCT'),
249
    'NAME' => array('MEMBER'),
250
    'DATA' => array('ARRAY'),
251
    'FAULT' => array('METHODRESPONSE'),
252
    'VALUE' => array('MEMBER', 'DATA', 'PARAM', 'FAULT'),
253
);
254

    
255

    
256
/**
257
 * Stores state during parsing
258
 *
259
 * quick explanation of components:
260
 *   + ac     = accumulates values
261
 *   + qt     = decides if quotes are needed for evaluation
262
 *   + cm     = denotes struct or array (comma needed)
263
 *   + isf    = indicates a fault
264
 *   + lv     = indicates "looking for a value": implements the logic
265
 *               to allow values with no types to be strings
266
 *   + params = stores parameters in method calls
267
 *   + method = stores method name
268
 *
269
 * @global array $GLOBALS['XML_RPC_xh']
270
 */
271
$GLOBALS['XML_RPC_xh'] = array();
272

    
273

    
274
/**
275
 * Start element handler for the XML parser
276
 *
277
 * @return void
278
 */
279
function XML_RPC_se($parser_resource, $name, $attrs)
280
{
281
    global $XML_RPC_xh, $XML_RPC_valid_parents;
282

    
283
    $parser = (int) $parser_resource;
284

    
285
    // if invalid xmlrpc already detected, skip all processing
286
    if ($XML_RPC_xh[$parser]['isf'] >= 2) {
287
        return;
288
    }
289

    
290
    // check for correct element nesting
291
    // top level element can only be of 2 types
292
    if (count($XML_RPC_xh[$parser]['stack']) == 0) {
293
        if ($name != 'METHODRESPONSE' && $name != 'METHODCALL') {
294
            $XML_RPC_xh[$parser]['isf'] = 2;
295
            $XML_RPC_xh[$parser]['isf_reason'] = 'missing top level xmlrpc element';
296
            return;
297
        }
298
    } else {
299
        // not top level element: see if parent is OK
300
        if (!in_array($XML_RPC_xh[$parser]['stack'][0], $XML_RPC_valid_parents[$name])) {
301
            $name = $GLOBALS['XML_RPC_func_ereg_replace']('[^a-zA-Z0-9._-]', '', $name);
302
            $XML_RPC_xh[$parser]['isf'] = 2;
303
            $XML_RPC_xh[$parser]['isf_reason'] = "xmlrpc element $name cannot be child of {$XML_RPC_xh[$parser]['stack'][0]}";
304
            return;
305
        }
306
    }
307

    
308
    switch ($name) {
309
    case 'STRUCT':
310
        $XML_RPC_xh[$parser]['cm']++;
311

    
312
        // turn quoting off
313
        $XML_RPC_xh[$parser]['qt'] = 0;
314

    
315
        $cur_val = array();
316
        $cur_val['value'] = array();
317
        $cur_val['members'] = 1;
318
        array_unshift($XML_RPC_xh[$parser]['valuestack'], $cur_val);
319
        break;
320

    
321
    case 'ARRAY':
322
        $XML_RPC_xh[$parser]['cm']++;
323

    
324
        // turn quoting off
325
        $XML_RPC_xh[$parser]['qt'] = 0;
326

    
327
        $cur_val = array();
328
        $cur_val['value'] = array();
329
        $cur_val['members'] = 0;
330
        array_unshift($XML_RPC_xh[$parser]['valuestack'], $cur_val);
331
        break;
332

    
333
    case 'NAME':
334
        $XML_RPC_xh[$parser]['ac'] = '';
335
        break;
336

    
337
    case 'FAULT':
338
        $XML_RPC_xh[$parser]['isf'] = 1;
339
        break;
340

    
341
    case 'PARAM':
342
        $XML_RPC_xh[$parser]['valuestack'] = array();
343
        break;
344

    
345
    case 'VALUE':
346
        $XML_RPC_xh[$parser]['lv'] = 1;
347
        $XML_RPC_xh[$parser]['vt'] = $GLOBALS['XML_RPC_String'];
348
        $XML_RPC_xh[$parser]['ac'] = '';
349
        $XML_RPC_xh[$parser]['qt'] = 0;
350
        // look for a value: if this is still 1 by the
351
        // time we reach the first data segment then the type is string
352
        // by implication and we need to add in a quote
353
        break;
354

    
355
    case 'I4':
356
    case 'INT':
357
    case 'STRING':
358
    case 'BOOLEAN':
359
    case 'DOUBLE':
360
    case 'DATETIME.ISO8601':
361
    case 'BASE64':
362
        $XML_RPC_xh[$parser]['ac'] = ''; // reset the accumulator
363

    
364
        if ($name == 'DATETIME.ISO8601' || $name == 'STRING') {
365
            $XML_RPC_xh[$parser]['qt'] = 1;
366

    
367
            if ($name == 'DATETIME.ISO8601') {
368
                $XML_RPC_xh[$parser]['vt'] = $GLOBALS['XML_RPC_DateTime'];
369
            }
370

    
371
        } elseif ($name == 'BASE64') {
372
            $XML_RPC_xh[$parser]['qt'] = 2;
373
        } else {
374
            // No quoting is required here -- but
375
            // at the end of the element we must check
376
            // for data format errors.
377
            $XML_RPC_xh[$parser]['qt'] = 0;
378
        }
379
        break;
380

    
381
    case 'MEMBER':
382
        $XML_RPC_xh[$parser]['ac'] = '';
383
        break;
384

    
385
    case 'DATA':
386
    case 'METHODCALL':
387
    case 'METHODNAME':
388
    case 'METHODRESPONSE':
389
    case 'PARAMS':
390
        // valid elements that add little to processing
391
        break;
392
    }
393

    
394

    
395
    // Save current element to stack
396
    array_unshift($XML_RPC_xh[$parser]['stack'], $name);
397

    
398
    if ($name != 'VALUE') {
399
        $XML_RPC_xh[$parser]['lv'] = 0;
400
    }
401
}
402

    
403
/**
404
 * End element handler for the XML parser
405
 *
406
 * @return void
407
 */
408
function XML_RPC_ee($parser_resource, $name)
409
{
410
    global $XML_RPC_xh;
411

    
412
    $parser = (int) $parser_resource;
413

    
414
    if ($XML_RPC_xh[$parser]['isf'] >= 2) {
415
        return;
416
    }
417

    
418
    // push this element from stack
419
    // NB: if XML validates, correct opening/closing is guaranteed and
420
    // we do not have to check for $name == $curr_elem.
421
    // we also checked for proper nesting at start of elements...
422
    $curr_elem = array_shift($XML_RPC_xh[$parser]['stack']);
423

    
424
    switch ($name) {
425
    case 'STRUCT':
426
    case 'ARRAY':
427
    $cur_val = array_shift($XML_RPC_xh[$parser]['valuestack']);
428
    $XML_RPC_xh[$parser]['value'] = $cur_val['value'];
429
        $XML_RPC_xh[$parser]['vt'] = strtolower($name);
430
        $XML_RPC_xh[$parser]['cm']--;
431
        break;
432

    
433
    case 'NAME':
434
    $XML_RPC_xh[$parser]['valuestack'][0]['name'] = $XML_RPC_xh[$parser]['ac'];
435
        break;
436

    
437
    case 'BOOLEAN':
438
        // special case here: we translate boolean 1 or 0 into PHP
439
        // constants true or false
440
        if ($XML_RPC_xh[$parser]['ac'] == '1') {
441
            $XML_RPC_xh[$parser]['ac'] = 'true';
442
        } else {
443
            $XML_RPC_xh[$parser]['ac'] = 'false';
444
        }
445

    
446
        $XML_RPC_xh[$parser]['vt'] = strtolower($name);
447
        // Drop through intentionally.
448

    
449
    case 'I4':
450
    case 'INT':
451
    case 'STRING':
452
    case 'DOUBLE':
453
    case 'DATETIME.ISO8601':
454
    case 'BASE64':
455
        if ($XML_RPC_xh[$parser]['qt'] == 1) {
456
            // we use double quotes rather than single so backslashification works OK
457
            $XML_RPC_xh[$parser]['value'] = $XML_RPC_xh[$parser]['ac'];
458
        } elseif ($XML_RPC_xh[$parser]['qt'] == 2) {
459
            $XML_RPC_xh[$parser]['value'] = base64_decode($XML_RPC_xh[$parser]['ac']);
460
        } elseif ($name == 'BOOLEAN') {
461
            $XML_RPC_xh[$parser]['value'] = $XML_RPC_xh[$parser]['ac'];
462
        } else {
463
            // we have an I4, INT or a DOUBLE
464
            // we must check that only 0123456789-.<space> are characters here
465
            if (!$GLOBALS['XML_RPC_func_ereg']("^[+-]?[0123456789 \t\.]+$", $XML_RPC_xh[$parser]['ac'])) {
466
                XML_RPC_Base::raiseError('Non-numeric value received in INT or DOUBLE',
467
                                         XML_RPC_ERROR_NON_NUMERIC_FOUND);
468
                $XML_RPC_xh[$parser]['value'] = XML_RPC_ERROR_NON_NUMERIC_FOUND;
469
            } else {
470
                // it's ok, add it on
471
                $XML_RPC_xh[$parser]['value'] = $XML_RPC_xh[$parser]['ac'];
472
            }
473
        }
474

    
475
        $XML_RPC_xh[$parser]['ac'] = '';
476
        $XML_RPC_xh[$parser]['qt'] = 0;
477
        $XML_RPC_xh[$parser]['lv'] = 3; // indicate we've found a value
478
        break;
479

    
480
    case 'VALUE':
481
        if ($XML_RPC_xh[$parser]['vt'] == $GLOBALS['XML_RPC_String']) {
482
            if (strlen($XML_RPC_xh[$parser]['ac']) > 0) {
483
                $XML_RPC_xh[$parser]['value'] = $XML_RPC_xh[$parser]['ac'];
484
            } elseif ($XML_RPC_xh[$parser]['lv'] == 1) {
485
                // The <value> element was empty.
486
                $XML_RPC_xh[$parser]['value'] = '';
487
            }
488
        }
489

    
490
        $temp = new XML_RPC_Value($XML_RPC_xh[$parser]['value'], $XML_RPC_xh[$parser]['vt']);
491

    
492
        $cur_val = array_shift($XML_RPC_xh[$parser]['valuestack']);
493
        if (is_array($cur_val)) {
494
            if ($cur_val['members']==0) {
495
                $cur_val['value'][] = $temp;
496
            } else {
497
                $XML_RPC_xh[$parser]['value'] = $temp;
498
            }
499
            array_unshift($XML_RPC_xh[$parser]['valuestack'], $cur_val);
500
        } else {
501
            $XML_RPC_xh[$parser]['value'] = $temp;
502
        }
503
        break;
504

    
505
    case 'MEMBER':
506
        $XML_RPC_xh[$parser]['ac'] = '';
507
        $XML_RPC_xh[$parser]['qt'] = 0;
508

    
509
        $cur_val = array_shift($XML_RPC_xh[$parser]['valuestack']);
510
        if (is_array($cur_val)) {
511
            if ($cur_val['members']==1) {
512
                $cur_val['value'][$cur_val['name']] = $XML_RPC_xh[$parser]['value'];
513
            }
514
            array_unshift($XML_RPC_xh[$parser]['valuestack'], $cur_val);
515
        }
516
        break;
517

    
518
    case 'DATA':
519
        $XML_RPC_xh[$parser]['ac'] = '';
520
        $XML_RPC_xh[$parser]['qt'] = 0;
521
        break;
522

    
523
    case 'PARAM':
524
        $XML_RPC_xh[$parser]['params'][] = $XML_RPC_xh[$parser]['value'];
525
        break;
526

    
527
    case 'METHODNAME':
528
    case 'RPCMETHODNAME':
529
        $XML_RPC_xh[$parser]['method'] = $GLOBALS['XML_RPC_func_ereg_replace']("^[\n\r\t ]+", '',
530
                                                      $XML_RPC_xh[$parser]['ac']);
531
        break;
532
    }
533

    
534
    // if it's a valid type name, set the type
535
    if (isset($GLOBALS['XML_RPC_Types'][strtolower($name)])) {
536
        $XML_RPC_xh[$parser]['vt'] = strtolower($name);
537
    }
538
}
539

    
540
/**
541
 * Character data handler for the XML parser
542
 *
543
 * @return void
544
 */
545
function XML_RPC_cd($parser_resource, $data)
546
{
547
    global $XML_RPC_xh, $XML_RPC_backslash;
548

    
549
    $parser = (int) $parser_resource;
550

    
551
    if ($XML_RPC_xh[$parser]['lv'] != 3) {
552
        // "lookforvalue==3" means that we've found an entire value
553
        // and should discard any further character data
554

    
555
        if ($XML_RPC_xh[$parser]['lv'] == 1) {
556
            // if we've found text and we're just in a <value> then
557
            // turn quoting on, as this will be a string
558
            $XML_RPC_xh[$parser]['qt'] = 1;
559
            // and say we've found a value
560
            $XML_RPC_xh[$parser]['lv'] = 2;
561
        }
562

    
563
        // replace characters that eval would
564
        // do special things with
565
        if (!isset($XML_RPC_xh[$parser]['ac'])) {
566
            $XML_RPC_xh[$parser]['ac'] = '';
567
        }
568
        $XML_RPC_xh[$parser]['ac'] .= $data;
569
    }
570
}
571

    
572
/**
573
 * The common methods and properties for all of the XML_RPC classes
574
 *
575
 * @category   Web Services
576
 * @package    XML_RPC
577
 * @author     Edd Dumbill <edd@usefulinc.com>
578
 * @author     Stig Bakken <stig@php.net>
579
 * @author     Martin Jansen <mj@php.net>
580
 * @author     Daniel Convissor <danielc@php.net>
581
 * @copyright  1999-2001 Edd Dumbill, 2001-2006 The PHP Group
582
 * @version    Release: 1.5.1
583
 * @link       http://pear.php.net/package/XML_RPC
584
 */
585
class XML_RPC_Base {
586

    
587
    /**
588
     * PEAR Error handling
589
     *
590
     * @return object  PEAR_Error object
591
     */
592
    function raiseError($msg, $code)
593
    {
594
        include_once 'PEAR.inc';
595
        if (is_object(@$this)) {
596
            return PEAR::raiseError(get_class($this) . ': ' . $msg, $code);
597
        } else {
598
            return PEAR::raiseError('XML_RPC: ' . $msg, $code);
599
        }
600
    }
601

    
602
    /**
603
     * Tell whether something is a PEAR_Error object
604
     *
605
     * @param mixed $value  the item to check
606
     *
607
     * @return bool  whether $value is a PEAR_Error object or not
608
     *
609
     * @access public
610
     */
611
    function isError($value)
612
    {
613
        return is_a($value, 'PEAR_Error');
614
    }
615
}
616

    
617
/**
618
 * The methods and properties for submitting XML RPC requests
619
 *
620
 * @category   Web Services
621
 * @package    XML_RPC
622
 * @author     Edd Dumbill <edd@usefulinc.com>
623
 * @author     Stig Bakken <stig@php.net>
624
 * @author     Martin Jansen <mj@php.net>
625
 * @author     Daniel Convissor <danielc@php.net>
626
 * @copyright  1999-2001 Edd Dumbill, 2001-2006 The PHP Group
627
 * @version    Release: 1.5.1
628
 * @link       http://pear.php.net/package/XML_RPC
629
 */
630
class XML_RPC_Client extends XML_RPC_Base {
631

    
632
    /**
633
     * The path and name of the RPC server script you want the request to go to
634
     * @var string
635
     */
636
    var $path = '';
637

    
638
    /**
639
     * The name of the remote server to connect to
640
     * @var string
641
     */
642
    var $server = '';
643

    
644
    /**
645
     * The protocol to use in contacting the remote server
646
     * @var string
647
     */
648
    var $protocol = 'http://';
649

    
650
    /**
651
     * The port for connecting to the remote server
652
     *
653
     * The default is 80 for http:// connections
654
     * and 443 for https:// and ssl:// connections.
655
     *
656
     * @var integer
657
     */
658
    var $port = 80;
659

    
660
    /**
661
     * A user name for accessing the RPC server
662
     * @var string
663
     * @see XML_RPC_Client::setCredentials()
664
     */
665
    var $username = '';
666

    
667
    /**
668
     * A password for accessing the RPC server
669
     * @var string
670
     * @see XML_RPC_Client::setCredentials()
671
     */
672
    var $password = '';
673

    
674
    /**
675
     * The name of the proxy server to use, if any
676
     * @var string
677
     */
678
    var $proxy = '';
679

    
680
    /**
681
     * The protocol to use in contacting the proxy server, if any
682
     * @var string
683
     */
684
    var $proxy_protocol = 'http://';
685

    
686
    /**
687
     * The port for connecting to the proxy server
688
     *
689
     * The default is 8080 for http:// connections
690
     * and 443 for https:// and ssl:// connections.
691
     *
692
     * @var integer
693
     */
694
    var $proxy_port = 8080;
695

    
696
    /**
697
     * A user name for accessing the proxy server
698
     * @var string
699
     */
700
    var $proxy_user = '';
701

    
702
    /**
703
     * A password for accessing the proxy server
704
     * @var string
705
     */
706
    var $proxy_pass = '';
707

    
708
    /**
709
     * The error number, if any
710
     * @var integer
711
     */
712
    var $errno = 0;
713

    
714
    /**
715
     * The error message, if any
716
     * @var string
717
     */
718
    var $errstr = '';
719

    
720
    /**
721
     * The current debug mode (1 = on, 0 = off)
722
     * @var integer
723
     */
724
    var $debug = 0;
725

    
726
    /**
727
     * The HTTP headers for the current request.
728
     * @var string
729
     */
730
    var $headers = '';
731

    
732

    
733
    /**
734
     * Sets the object's properties
735
     *
736
     * @param string  $path        the path and name of the RPC server script
737
     *                              you want the request to go to
738
     * @param string  $server      the URL of the remote server to connect to.
739
     *                              If this parameter doesn't specify a
740
     *                              protocol and $port is 443, ssl:// is
741
     *                              assumed.
742
     * @param integer $port        a port for connecting to the remote server.
743
     *                              Defaults to 80 for http:// connections and
744
     *                              443 for https:// and ssl:// connections.
745
     * @param string  $proxy       the URL of the proxy server to use, if any.
746
     *                              If this parameter doesn't specify a
747
     *                              protocol and $port is 443, ssl:// is
748
     *                              assumed.
749
     * @param integer $proxy_port  a port for connecting to the remote server.
750
     *                              Defaults to 8080 for http:// connections and
751
     *                              443 for https:// and ssl:// connections.
752
     * @param string  $proxy_user  a user name for accessing the proxy server
753
     * @param string  $proxy_pass  a password for accessing the proxy server
754
     *
755
     * @return void
756
     */
757
    function XML_RPC_Client($path, $server, $port = 0,
758
                            $proxy = '', $proxy_port = 0,
759
                            $proxy_user = '', $proxy_pass = '')
760
    {
761
        $this->path       = $path;
762
        $this->proxy_user = $proxy_user;
763
        $this->proxy_pass = $proxy_pass;
764

    
765
        $GLOBALS['XML_RPC_func_ereg']('^(http://|https://|ssl://)?(.*)$', $server, $match);
766
        if ($match[1] == '') {
767
            if ($port == 443) {
768
                $this->server   = $match[2];
769
                $this->protocol = 'ssl://';
770
                $this->port     = 443;
771
            } else {
772
                $this->server = $match[2];
773
                if ($port) {
774
                    $this->port = $port;
775
                }
776
            }
777
        } elseif ($match[1] == 'http://') {
778
            $this->server = $match[2];
779
            if ($port) {
780
                $this->port = $port;
781
            }
782
        } else {
783
            $this->server   = $match[2];
784
            $this->protocol = 'ssl://';
785
            if ($port) {
786
                $this->port = $port;
787
            } else {
788
                $this->port = 443;
789
            }
790
        }
791

    
792
        if ($proxy) {
793
            $GLOBALS['XML_RPC_func_ereg']('^(http://|https://|ssl://)?(.*)$', $proxy, $match);
794
            if ($match[1] == '') {
795
                if ($proxy_port == 443) {
796
                    $this->proxy          = $match[2];
797
                    $this->proxy_protocol = 'ssl://';
798
                    $this->proxy_port     = 443;
799
                } else {
800
                    $this->proxy = $match[2];
801
                    if ($proxy_port) {
802
                        $this->proxy_port = $proxy_port;
803
                    }
804
                }
805
            } elseif ($match[1] == 'http://') {
806
                $this->proxy = $match[2];
807
                if ($proxy_port) {
808
                    $this->proxy_port = $proxy_port;
809
                }
810
            } else {
811
                $this->proxy          = $match[2];
812
                $this->proxy_protocol = 'ssl://';
813
                if ($proxy_port) {
814
                    $this->proxy_port = $proxy_port;
815
                } else {
816
                    $this->proxy_port = 443;
817
                }
818
            }
819
        }
820
    }
821

    
822
    /**
823
     * Change the current debug mode
824
     *
825
     * @param int $in  where 1 = on, 0 = off
826
     *
827
     * @return void
828
     */
829
    function setDebug($in)
830
    {
831
        if ($in) {
832
            $this->debug = 1;
833
        } else {
834
            $this->debug = 0;
835
        }
836
    }
837

    
838
    /**
839
     * Sets whether strings that contain characters which may cause PHP's
840
     * SAX-based XML parser to break should be automatically base64 encoded
841
     *
842
     * This is is a workaround for systems that don't have PHP's mbstring
843
     * extension available.
844
     *
845
     * @param int $in  where 1 = on, 0 = off
846
     *
847
     * @return void
848
     */
849
    function setAutoBase64($in)
850
    {
851
        if ($in) {
852
            $GLOBALS['XML_RPC_auto_base64'] = true;
853
        } else {
854
            $GLOBALS['XML_RPC_auto_base64'] = false;
855
        }
856
    }
857

    
858
    /**
859
     * Set username and password properties for connecting to the RPC server
860
     *
861
     * @param string $u  the user name
862
     * @param string $p  the password
863
     *
864
     * @return void
865
     *
866
     * @see XML_RPC_Client::$username, XML_RPC_Client::$password
867
     */
868
    function setCredentials($u, $p)
869
    {
870
        $this->username = $u;
871
        $this->password = $p;
872
    }
873

    
874
    /**
875
     * Transmit the RPC request via HTTP 1.0 protocol
876
     *
877
     * @param object $msg       the XML_RPC_Message object
878
     * @param int    $timeout   how many seconds to wait for the request
879
     *
880
     * @return object  an XML_RPC_Response object.  0 is returned if any
881
     *                  problems happen.
882
     *
883
     * @see XML_RPC_Message, XML_RPC_Client::XML_RPC_Client(),
884
     *      XML_RPC_Client::setCredentials()
885
     */
886
    function send($msg, $timeout = 0)
887
    {
888
        if (!is_a($msg, 'XML_RPC_Message')) {
889
            $this->errstr = 'send()\'s $msg parameter must be an'
890
                          . ' XML_RPC_Message object.';
891
            $this->raiseError($this->errstr, XML_RPC_ERROR_PROGRAMMING);
892
            return 0;
893
        }
894
        $msg->debug = $this->debug;
895
        return $this->sendPayloadHTTP10($msg, $this->server, $this->port,
896
                                        $timeout, $this->username,
897
                                        $this->password);
898
    }
899

    
900
    /**
901
     * Transmit the RPC request via HTTP 1.0 protocol
902
     *
903
     * Requests should be sent using XML_RPC_Client send() rather than
904
     * calling this method directly.
905
     *
906
     * @param object $msg       the XML_RPC_Message object
907
     * @param string $server    the server to send the request to
908
     * @param int    $port      the server port send the request to
909
     * @param int    $timeout   how many seconds to wait for the request
910
     *                           before giving up
911
     * @param string $username  a user name for accessing the RPC server
912
     * @param string $password  a password for accessing the RPC server
913
     *
914
     * @return object  an XML_RPC_Response object.  0 is returned if any
915
     *                  problems happen.
916
     *
917
     * @access protected
918
     * @see XML_RPC_Client::send()
919
     */
920
    function sendPayloadHTTP10($msg, $server, $port, $timeout = 0,
921
                               $username = '', $password = '')
922
    {
923
        /*
924
         * If we're using a proxy open a socket to the proxy server
925
         * instead to the xml-rpc server
926
         */
927
        if ($this->proxy) {
928
            if ($this->proxy_protocol == 'http://') {
929
                $protocol = '';
930
            } else {
931
                $protocol = $this->proxy_protocol;
932
            }
933
            if ($timeout > 0) {
934
                $fp = @fsockopen($protocol . $this->proxy, $this->proxy_port,
935
                                 $this->errno, $this->errstr, $timeout);
936
            } else {
937
                $fp = @fsockopen($protocol . $this->proxy, $this->proxy_port,
938
                                 $this->errno, $this->errstr);
939
            }
940
        } else {
941
            if ($this->protocol == 'http://') {
942
                $protocol = '';
943
            } else {
944
                $protocol = $this->protocol;
945
            }
946
            if ($timeout > 0) {
947
                $fp = @fsockopen($protocol . $server, $port,
948
                                 $this->errno, $this->errstr, $timeout);
949
            } else {
950
                $fp = @fsockopen($protocol . $server, $port,
951
                                 $this->errno, $this->errstr);
952
            }
953
        }
954

    
955
        /*
956
         * Just raising the error without returning it is strange,
957
         * but keep it here for backwards compatibility.
958
         */
959
        if (!$fp && $this->proxy) {
960
            $this->raiseError('Connection to proxy server '
961
                              . $this->proxy . ':' . $this->proxy_port
962
                              . ' failed. ' . $this->errstr,
963
                              XML_RPC_ERROR_CONNECTION_FAILED);
964
            return 0;
965
        } elseif (!$fp) {
966
            $this->raiseError('Connection to RPC server '
967
                              . $server . ':' . $port
968
                              . ' failed. ' . $this->errstr,
969
                              XML_RPC_ERROR_CONNECTION_FAILED);
970
            return 0;
971
        }
972

    
973
        if ($timeout) {
974
            /*
975
             * Using socket_set_timeout() because stream_set_timeout()
976
             * was introduced in 4.3.0, but we need to support 4.2.0.
977
             */
978
            socket_set_timeout($fp, $timeout);
979
        }
980

    
981
        // Pre-emptive BC hacks for fools calling sendPayloadHTTP10() directly
982
        if ($username != $this->username) {
983
            $this->setCredentials($username, $password);
984
        }
985

    
986
        // Only create the payload if it was not created previously
987
        if (empty($msg->payload)) {
988
            $msg->createPayload();
989
        }
990
        $this->createHeaders($msg);
991

    
992
        $op  = $this->headers . "\r\n\r\n";
993
        $op .= $msg->payload;
994

    
995
        if (!fputs($fp, $op, strlen($op))) {
996
            $this->errstr = 'Write error';
997
            return 0;
998
        }
999
        $resp = $msg->parseResponseFile($fp);
1000

    
1001
        $meta = socket_get_status($fp);
1002
        if ($meta['timed_out']) {
1003
            fclose($fp);
1004
            $this->errstr = 'RPC server did not send response before timeout.';
1005
            $this->raiseError($this->errstr, XML_RPC_ERROR_CONNECTION_FAILED);
1006
            return 0;
1007
        }
1008

    
1009
        fclose($fp);
1010
        return $resp;
1011
    }
1012

    
1013
    /**
1014
     * Determines the HTTP headers and puts it in the $headers property
1015
     *
1016
     * @param object $msg       the XML_RPC_Message object
1017
     *
1018
     * @return boolean  TRUE if okay, FALSE if the message payload isn't set.
1019
     *
1020
     * @access protected
1021
     */
1022
    function createHeaders($msg)
1023
    {
1024
        if (empty($msg->payload)) {
1025
            return false;
1026
        }
1027
        if ($this->proxy) {
1028
            $this->headers = 'POST ' . $this->protocol . $this->server;
1029
            if ($this->proxy_port) {
1030
                $this->headers .= ':' . $this->port;
1031
            }
1032
        } else {
1033
           $this->headers = 'POST ';
1034
        }
1035
        $this->headers .= $this->path. " HTTP/1.0\r\n";
1036

    
1037
        $this->headers .= "User-Agent: PEAR XML_RPC\r\n";
1038
        $this->headers .= 'Host: ' . $this->server . "\r\n";
1039

    
1040
        if ($this->proxy && $this->proxy_user) {
1041
            $this->headers .= 'Proxy-Authorization: Basic '
1042
                     . base64_encode("$this->proxy_user:$this->proxy_pass")
1043
                     . "\r\n";
1044
        }
1045

    
1046
        // thanks to Grant Rauscher <grant7@firstworld.net> for this
1047
        if ($this->username) {
1048
            $this->headers .= 'Authorization: Basic '
1049
                     . base64_encode("$this->username:$this->password")
1050
                     . "\r\n";
1051
        }
1052

    
1053
        $this->headers .= "Content-Type: text/xml\r\n";
1054
        $this->headers .= 'Content-Length: ' . strlen($msg->payload);
1055
        return true;
1056
    }
1057
}
1058

    
1059
/**
1060
 * The methods and properties for interpreting responses to XML RPC requests
1061
 *
1062
 * @category   Web Services
1063
 * @package    XML_RPC
1064
 * @author     Edd Dumbill <edd@usefulinc.com>
1065
 * @author     Stig Bakken <stig@php.net>
1066
 * @author     Martin Jansen <mj@php.net>
1067
 * @author     Daniel Convissor <danielc@php.net>
1068
 * @copyright  1999-2001 Edd Dumbill, 2001-2006 The PHP Group
1069
 * @version    Release: 1.5.1
1070
 * @link       http://pear.php.net/package/XML_RPC
1071
 */
1072
class XML_RPC_Response extends XML_RPC_Base
1073
{
1074
    var $xv;
1075
    var $fn;
1076
    var $fs;
1077
    var $hdrs;
1078

    
1079
    /**
1080
     * @return void
1081
     */
1082
    function XML_RPC_Response($val, $fcode = 0, $fstr = '')
1083
    {
1084
        if ($fcode != 0) {
1085
            $this->fn = $fcode;
1086
            $this->fs = htmlspecialchars($fstr);
1087
        } else {
1088
            $this->xv = $val;
1089
        }
1090
    }
1091

    
1092
    /**
1093
     * @return int  the error code
1094
     */
1095
    function faultCode()
1096
    {
1097
        if (isset($this->fn)) {
1098
            return $this->fn;
1099
        } else {
1100
            return 0;
1101
        }
1102
    }
1103

    
1104
    /**
1105
     * @return string  the error string
1106
     */
1107
    function faultString()
1108
    {
1109
        return $this->fs;
1110
    }
1111

    
1112
    /**
1113
     * @return mixed  the value
1114
     */
1115
    function value()
1116
    {
1117
        return $this->xv;
1118
    }
1119

    
1120
    /**
1121
     * @return string  the error message in XML format
1122
     */
1123
    function serialize()
1124
    {
1125
        $rs = "<methodResponse>\n";
1126
        if ($this->fn) {
1127
            $rs .= "<fault>
1128
  <value>
1129
    <struct>
1130
      <member>
1131
        <name>faultCode</name>
1132
        <value><int>" . $this->fn . "</int></value>
1133
      </member>
1134
      <member>
1135
        <name>faultString</name>
1136
        <value><string>" . $this->fs . "</string></value>
1137
      </member>
1138
    </struct>
1139
  </value>
1140
</fault>";
1141
        } else {
1142
            $rs .= "<params>\n<param>\n" . $this->xv->serialize() .
1143
        "</param>\n</params>";
1144
        }
1145
        $rs .= "\n</methodResponse>";
1146
        return $rs;
1147
    }
1148
}
1149

    
1150
/**
1151
 * The methods and properties for composing XML RPC messages
1152
 *
1153
 * @category   Web Services
1154
 * @package    XML_RPC
1155
 * @author     Edd Dumbill <edd@usefulinc.com>
1156
 * @author     Stig Bakken <stig@php.net>
1157
 * @author     Martin Jansen <mj@php.net>
1158
 * @author     Daniel Convissor <danielc@php.net>
1159
 * @copyright  1999-2001 Edd Dumbill, 2001-2006 The PHP Group
1160
 * @version    Release: 1.5.1
1161
 * @link       http://pear.php.net/package/XML_RPC
1162
 */
1163
class XML_RPC_Message extends XML_RPC_Base
1164
{
1165
    /**
1166
     * Should the payload's content be passed through mb_convert_encoding()?
1167
     *
1168
     * @see XML_RPC_Message::setConvertPayloadEncoding()
1169
     * @since Property available since Release 1.5.1
1170
     * @var boolean
1171
     */
1172
    var $convert_payload_encoding = false;
1173

    
1174
    /**
1175
     * The current debug mode (1 = on, 0 = off)
1176
     * @var integer
1177
     */
1178
    var $debug = 0;
1179

    
1180
    /**
1181
     * The encoding to be used for outgoing messages
1182
     *
1183
     * Defaults to the value of <var>$GLOBALS['XML_RPC_defencoding']</var>
1184
     *
1185
     * @var string
1186
     * @see XML_RPC_Message::setSendEncoding(),
1187
     *      $GLOBALS['XML_RPC_defencoding'], XML_RPC_Message::xml_header()
1188
     */
1189
    var $send_encoding = '';
1190

    
1191
    /**
1192
     * The method presently being evaluated
1193
     * @var string
1194
     */
1195
    var $methodname = '';
1196

    
1197
    /**
1198
     * @var array
1199
     */
1200
    var $params = array();
1201

    
1202
    /**
1203
     * The XML message being generated
1204
     * @var string
1205
     */
1206
    var $payload = '';
1207

    
1208
    /**
1209
     * Should extra line breaks be removed from the payload?
1210
     * @since Property available since Release 1.4.6
1211
     * @var boolean
1212
     */
1213
    var $remove_extra_lines = true;
1214

    
1215
    /**
1216
     * The XML response from the remote server
1217
     * @since Property available since Release 1.4.6
1218
     * @var string
1219
     */
1220
    var $response_payload = '';
1221

    
1222

    
1223
    /**
1224
     * @return void
1225
     */
1226
    function XML_RPC_Message($meth, $pars = 0)
1227
    {
1228
        $this->methodname = $meth;
1229
        if (is_array($pars) && sizeof($pars) > 0) {
1230
            for ($i = 0; $i < sizeof($pars); $i++) {
1231
                $this->addParam($pars[$i]);
1232
            }
1233
        }
1234
    }
1235

    
1236
    /**
1237
     * Produces the XML declaration including the encoding attribute
1238
     *
1239
     * The encoding is determined by this class' <var>$send_encoding</var>
1240
     * property.  If the <var>$send_encoding</var> property is not set, use
1241
     * <var>$GLOBALS['XML_RPC_defencoding']</var>.
1242
     *
1243
     * @return string  the XML declaration and <methodCall> element
1244
     *
1245
     * @see XML_RPC_Message::setSendEncoding(),
1246
     *      XML_RPC_Message::$send_encoding, $GLOBALS['XML_RPC_defencoding']
1247
     */
1248
    function xml_header()
1249
    {
1250
        global $XML_RPC_defencoding;
1251

    
1252
        if (!$this->send_encoding) {
1253
            $this->send_encoding = $XML_RPC_defencoding;
1254
        }
1255
        return '<?xml version="1.0" encoding="' . $this->send_encoding . '"?>'
1256
               . "\n<methodCall>\n";
1257
    }
1258

    
1259
    /**
1260
     * @return string  the closing </methodCall> tag
1261
     */
1262
    function xml_footer()
1263
    {
1264
        return "</methodCall>\n";
1265
    }
1266

    
1267
    /**
1268
     * Fills the XML_RPC_Message::$payload property
1269
     *
1270
     * Part of the process makes sure all line endings are in DOS format
1271
     * (CRLF), which is probably required by specifications.
1272
     *
1273
     * If XML_RPC_Message::setConvertPayloadEncoding() was set to true,
1274
     * the payload gets passed through mb_convert_encoding()
1275
     * to ensure the payload matches the encoding set in the
1276
     * XML declaration.  The encoding type can be manually set via
1277
     * XML_RPC_Message::setSendEncoding().
1278
     *
1279
     * @return void
1280
     *
1281
     * @uses XML_RPC_Message::xml_header(), XML_RPC_Message::xml_footer()
1282
     * @see XML_RPC_Message::setSendEncoding(), $GLOBALS['XML_RPC_defencoding'],
1283
     *      XML_RPC_Message::setConvertPayloadEncoding()
1284
     */
1285
    function createPayload()
1286
    {
1287
        $this->payload = $this->xml_header();
1288
        $this->payload .= '<methodName>' . $this->methodname . "</methodName>\n";
1289
        $this->payload .= "<params>\n";
1290
        for ($i = 0; $i < sizeof($this->params); $i++) {
1291
            $p = $this->params[$i];
1292
            $this->payload .= "<param>\n" . $p->serialize() . "</param>\n";
1293
        }
1294
        $this->payload .= "</params>\n";
1295
        $this->payload .= $this->xml_footer();
1296
        if ($this->remove_extra_lines) {
1297
            $this->payload = $GLOBALS['XML_RPC_func_ereg_replace']("[\r\n]+", "\r\n", $this->payload);
1298
        } else {
1299
            $this->payload = $GLOBALS['XML_RPC_func_ereg_replace']("\r\n|\n|\r|\n\r", "\r\n", $this->payload);
1300
        }
1301
        if ($this->convert_payload_encoding) {
1302
            $this->payload = mb_convert_encoding($this->payload, $this->send_encoding);
1303
        }
1304
    }
1305

    
1306
    /**
1307
     * @return string  the name of the method
1308
     */
1309
    function method($meth = '')
1310
    {
1311
        if ($meth != '') {
1312
            $this->methodname = $meth;
1313
        }
1314
        return $this->methodname;
1315
    }
1316

    
1317
    /**
1318
     * @return string  the payload
1319
     */
1320
    function serialize()
1321
    {
1322
        $this->createPayload();
1323
        return $this->payload;
1324
    }
1325

    
1326
    /**
1327
     * @return void
1328
     */
1329
    function addParam($par)
1330
    {
1331
        $this->params[] = $par;
1332
    }
1333

    
1334
    /**
1335
     * Obtains an XML_RPC_Value object for the given parameter
1336
     *
1337
     * @param int $i  the index number of the parameter to obtain
1338
     *
1339
     * @return object  the XML_RPC_Value object.
1340
     *                  If the parameter doesn't exist, an XML_RPC_Response object.
1341
     *
1342
     * @since Returns XML_RPC_Response object on error since Release 1.3.0
1343
     */
1344
    function getParam($i)
1345
    {
1346
        global $XML_RPC_err, $XML_RPC_str;
1347

    
1348
        if (isset($this->params[$i])) {
1349
            return $this->params[$i];
1350
        } else {
1351
            $this->raiseError('The submitted request did not contain this parameter',
1352
                              XML_RPC_ERROR_INCORRECT_PARAMS);
1353
            return new XML_RPC_Response(0, $XML_RPC_err['incorrect_params'],
1354
                                        $XML_RPC_str['incorrect_params']);
1355
        }
1356
    }
1357

    
1358
    /**
1359
     * @return int  the number of parameters
1360
     */
1361
    function getNumParams()
1362
    {
1363
        return sizeof($this->params);
1364
    }
1365

    
1366
    /**
1367
     * Sets whether the payload's content gets passed through
1368
     * mb_convert_encoding()
1369
     *
1370
     * Returns PEAR_ERROR object if mb_convert_encoding() isn't available.
1371
     *
1372
     * @param int $in  where 1 = on, 0 = off
1373
     *
1374
     * @return void
1375
     *
1376
     * @see XML_RPC_Message::setSendEncoding()
1377
     * @since Method available since Release 1.5.1
1378
     */
1379
    function setConvertPayloadEncoding($in)
1380
    {
1381
        if ($in && !function_exists('mb_convert_encoding')) {
1382
            return $this->raiseError('mb_convert_encoding() is not available',
1383
                              XML_RPC_ERROR_PROGRAMMING);
1384
        }
1385
        $this->convert_payload_encoding = $in;
1386
    }
1387

    
1388
    /**
1389
     * Sets the XML declaration's encoding attribute
1390
     *
1391
     * @param string $type  the encoding type (ISO-8859-1, UTF-8 or US-ASCII)
1392
     *
1393
     * @return void
1394
     *
1395
     * @see XML_RPC_Message::setConvertPayloadEncoding(), XML_RPC_Message::xml_header()
1396
     * @since Method available since Release 1.2.0
1397
     */
1398
    function setSendEncoding($type)
1399
    {
1400
        $this->send_encoding = $type;
1401
    }
1402

    
1403
    /**
1404
     * Determine the XML's encoding via the encoding attribute
1405
     * in the XML declaration
1406
     *
1407
     * If the encoding parameter is not set or is not ISO-8859-1, UTF-8
1408
     * or US-ASCII, $XML_RPC_defencoding will be returned.
1409
     *
1410
     * @param string $data  the XML that will be parsed
1411
     *
1412
     * @return string  the encoding to be used
1413
     *
1414
     * @link   http://php.net/xml_parser_create
1415
     * @since  Method available since Release 1.2.0
1416
     */
1417
    function getEncoding($data)
1418
    {
1419
        global $XML_RPC_defencoding;
1420

    
1421
        if ($GLOBALS['XML_RPC_func_ereg']('<\?xml[^>]*[:space:]*encoding[:space:]*=[:space:]*[\'"]([^"\']*)[\'"]',
1422
                       $data, $match))
1423
        {
1424
            $match[1] = trim(strtoupper($match[1]));
1425
            switch ($match[1]) {
1426
                case 'ISO-8859-1':
1427
                case 'UTF-8':
1428
                case 'US-ASCII':
1429
                    return $match[1];
1430
                    break;
1431

    
1432
                default:
1433
                    return $XML_RPC_defencoding;
1434
            }
1435
        } else {
1436
            return $XML_RPC_defencoding;
1437
        }
1438
    }
1439

    
1440
    /**
1441
     * @return object  a new XML_RPC_Response object
1442
     */
1443
    function parseResponseFile($fp)
1444
    {
1445
        $ipd = '';
1446
        while ($data = @fread($fp, 8192)) {
1447
            $ipd .= $data;
1448
        }
1449
        return $this->parseResponse($ipd);
1450
    }
1451

    
1452
    /**
1453
     * @return object  a new XML_RPC_Response object
1454
     */
1455
    function parseResponse($data = '')
1456
    {
1457
        global $XML_RPC_xh, $XML_RPC_err, $XML_RPC_str, $XML_RPC_defencoding;
1458

    
1459
        $encoding = $this->getEncoding($data);
1460
        $parser_resource = xml_parser_create($encoding);
1461
        $parser = (int) $parser_resource;
1462

    
1463
        $XML_RPC_xh = array();
1464
        $XML_RPC_xh[$parser] = array();
1465

    
1466
        $XML_RPC_xh[$parser]['cm'] = 0;
1467
        $XML_RPC_xh[$parser]['isf'] = 0;
1468
        $XML_RPC_xh[$parser]['ac'] = '';
1469
        $XML_RPC_xh[$parser]['qt'] = '';
1470
        $XML_RPC_xh[$parser]['stack'] = array();
1471
        $XML_RPC_xh[$parser]['valuestack'] = array();
1472

    
1473
        xml_parser_set_option($parser_resource, XML_OPTION_CASE_FOLDING, true);
1474
        xml_set_element_handler($parser_resource, 'XML_RPC_se', 'XML_RPC_ee');
1475
        xml_set_character_data_handler($parser_resource, 'XML_RPC_cd');
1476

    
1477
        $hdrfnd = 0;
1478
        if ($this->debug) {
1479
            print "\n<pre>---GOT---\n";
1480
            print isset($_SERVER['SERVER_PROTOCOL']) ? htmlspecialchars($data) : $data;
1481
            print "\n---END---</pre>\n";
1482
        }
1483

    
1484
        // See if response is a 200 or a 100 then a 200, else raise error.
1485
        // But only do this if we're using the HTTP protocol.
1486
        if ($GLOBALS['XML_RPC_func_ereg']('^HTTP', $data) &&
1487
            !$GLOBALS['XML_RPC_func_ereg']('^HTTP/[0-9\.]+ 200 ', $data) &&
1488
            !$GLOBALS['XML_RPC_func_ereg']('^HTTP/[0-9\.]+ 10[0-9]([A-Z ]+)?[\r\n]+HTTP/[0-9\.]+ 200', $data))
1489
        {
1490
                $errstr = substr($data, 0, strpos($data, "\n") - 1);
1491
                error_log('HTTP error, got response: ' . $errstr);
1492
                $r = new XML_RPC_Response(0, $XML_RPC_err['http_error'],
1493
                                          $XML_RPC_str['http_error'] . ' (' .
1494
                                          $errstr . ')');
1495
                xml_parser_free($parser_resource);
1496
                return $r;
1497
        }
1498

    
1499
        // gotta get rid of headers here
1500
        if (!$hdrfnd && ($brpos = strpos($data,"\r\n\r\n"))) {
1501
            $XML_RPC_xh[$parser]['ha'] = substr($data, 0, $brpos);
1502
            $data = substr($data, $brpos + 4);
1503
            $hdrfnd = 1;
1504
        }
1505

    
1506
        /*
1507
         * be tolerant of junk after methodResponse
1508
         * (e.g. javascript automatically inserted by free hosts)
1509
         * thanks to Luca Mariano <luca.mariano@email.it>
1510
         */
1511
        $data = substr($data, 0, strpos($data, "</methodResponse>") + 17);
1512
        $this->response_payload = $data;
1513

    
1514
        if (!xml_parse($parser_resource, $data, sizeof($data))) {
1515
            // thanks to Peter Kocks <peter.kocks@baygate.com>
1516
            if (xml_get_current_line_number($parser_resource) == 1) {
1517
                $errstr = 'XML error at line 1, check URL';
1518
            } else {
1519
                $errstr = sprintf('XML error: %s at line %d',
1520
                                  xml_error_string(xml_get_error_code($parser_resource)),
1521
                                  xml_get_current_line_number($parser_resource));
1522
            }
1523
            error_log($errstr);
1524
            $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'],
1525
                                      $XML_RPC_str['invalid_return']);
1526
            xml_parser_free($parser_resource);
1527
            return $r;
1528
        }
1529

    
1530
        xml_parser_free($parser_resource);
1531

    
1532
        if ($this->debug) {
1533
            print "\n<pre>---PARSED---\n";
1534
            var_dump($XML_RPC_xh[$parser]['value']);
1535
            print "---END---</pre>\n";
1536
        }
1537

    
1538
        if ($XML_RPC_xh[$parser]['isf'] > 1) {
1539
            $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'],
1540
                                      $XML_RPC_str['invalid_return'].' '.$XML_RPC_xh[$parser]['isf_reason']);
1541
        } elseif (!is_object($XML_RPC_xh[$parser]['value'])) {
1542
            // then something odd has happened
1543
            // and it's time to generate a client side error
1544
            // indicating something odd went on
1545
            $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'],
1546
                                      $XML_RPC_str['invalid_return']);
1547
        } else {
1548
            $v = $XML_RPC_xh[$parser]['value'];
1549
            if ($XML_RPC_xh[$parser]['isf']) {
1550
                $f = $v->structmem('faultCode');
1551
                $fs = $v->structmem('faultString');
1552
                $r = new XML_RPC_Response($v, $f->scalarval(),
1553
                                          $fs->scalarval());
1554
            } else {
1555
                $r = new XML_RPC_Response($v);
1556
            }
1557
        }
1558
        $r->hdrs = split("\r?\n", $XML_RPC_xh[$parser]['ha'][1]);
1559
        return $r;
1560
    }
1561
}
1562

    
1563
/**
1564
 * The methods and properties that represent data in XML RPC format
1565
 *
1566
 * @category   Web Services
1567
 * @package    XML_RPC
1568
 * @author     Edd Dumbill <edd@usefulinc.com>
1569
 * @author     Stig Bakken <stig@php.net>
1570
 * @author     Martin Jansen <mj@php.net>
1571
 * @author     Daniel Convissor <danielc@php.net>
1572
 * @copyright  1999-2001 Edd Dumbill, 2001-2006 The PHP Group
1573
 * @version    Release: 1.5.1
1574
 * @link       http://pear.php.net/package/XML_RPC
1575
 */
1576
class XML_RPC_Value extends XML_RPC_Base
1577
{
1578
    var $me = array();
1579
    var $mytype = 0;
1580

    
1581
    /**
1582
     * @return void
1583
     */
1584
    function XML_RPC_Value($val = -1, $type = '')
1585
    {
1586
        $this->me = array();
1587
        $this->mytype = 0;
1588
        if ($val != -1 || $type != '') {
1589
            if ($type == '') {
1590
                $type = 'string';
1591
            }
1592
            if (!array_key_exists($type, $GLOBALS['XML_RPC_Types'])) {
1593
                // XXX
1594
                // need some way to report this error
1595
            } elseif ($GLOBALS['XML_RPC_Types'][$type] == 1) {
1596
                $this->addScalar($val, $type);
1597
            } elseif ($GLOBALS['XML_RPC_Types'][$type] == 2) {
1598
                $this->addArray($val);
1599
            } elseif ($GLOBALS['XML_RPC_Types'][$type] == 3) {
1600
                $this->addStruct($val);
1601
            }
1602
        }
1603
    }
1604

    
1605
    /**
1606
     * @return int  returns 1 if successful or 0 if there are problems
1607
     */
1608
    function addScalar($val, $type = 'string')
1609
    {
1610
        if ($this->mytype == 1) {
1611
            $this->raiseError('Scalar can have only one value',
1612
                              XML_RPC_ERROR_INVALID_TYPE);
1613
            return 0;
1614
        }
1615
        $typeof = $GLOBALS['XML_RPC_Types'][$type];
1616
        if ($typeof != 1) {
1617
            $this->raiseError("Not a scalar type (${typeof})",
1618
                              XML_RPC_ERROR_INVALID_TYPE);
1619
            return 0;
1620
        }
1621

    
1622
        if ($type == $GLOBALS['XML_RPC_Boolean']) {
1623
            if (strcasecmp($val, 'true') == 0
1624
                || $val == 1
1625
                || ($val == true && strcasecmp($val, 'false')))
1626
            {
1627
                $val = 1;
1628
            } else {
1629
                $val = 0;
1630
            }
1631
        }
1632

    
1633
        if ($this->mytype == 2) {
1634
            // we're adding to an array here
1635
            $ar = $this->me['array'];
1636
            $ar[] = new XML_RPC_Value($val, $type);
1637
            $this->me['array'] = $ar;
1638
        } else {
1639
            // a scalar, so set the value and remember we're scalar
1640
            $this->me[$type] = $val;
1641
            $this->mytype = $typeof;
1642
        }
1643
        return 1;
1644
    }
1645

    
1646
    /**
1647
     * @return int  returns 1 if successful or 0 if there are problems
1648
     */
1649
    function addArray($vals)
1650
    {
1651
        if ($this->mytype != 0) {
1652
            $this->raiseError(
1653
                    'Already initialized as a [' . $this->kindOf() . ']',
1654
                    XML_RPC_ERROR_ALREADY_INITIALIZED);
1655
            return 0;
1656
        }
1657
        $this->mytype = $GLOBALS['XML_RPC_Types']['array'];
1658
        $this->me['array'] = $vals;
1659
        return 1;
1660
    }
1661

    
1662
    /**
1663
     * @return int  returns 1 if successful or 0 if there are problems
1664
     */
1665
    function addStruct($vals)
1666
    {
1667
        if ($this->mytype != 0) {
1668
            $this->raiseError(
1669
                    'Already initialized as a [' . $this->kindOf() . ']',
1670
                    XML_RPC_ERROR_ALREADY_INITIALIZED);
1671
            return 0;
1672
        }
1673
        $this->mytype = $GLOBALS['XML_RPC_Types']['struct'];
1674
        $this->me['struct'] = $vals;
1675
        return 1;
1676
    }
1677

    
1678
    /**
1679
     * @return void
1680
     */
1681
    function dump($ar)
1682
    {
1683
        reset($ar);
1684
        foreach ($ar as $key => $val) {
1685
            echo "$key => $val<br />";
1686
            if ($key == 'array') {
1687
                foreach ($val as $key2 => $val2) {
1688
                    echo "-- $key2 => $val2<br />";
1689
                }
1690
            }
1691
        }
1692
    }
1693

    
1694
    /**
1695
     * @return string  the data type of the current value
1696
     */
1697
    function kindOf()
1698
    {
1699
        switch ($this->mytype) {
1700
        case 3:
1701
            return 'struct';
1702

    
1703
        case 2:
1704
            return 'array';
1705

    
1706
        case 1:
1707
            return 'scalar';
1708

    
1709
        default:
1710
            return 'undef';
1711
        }
1712
    }
1713

    
1714
    /**
1715
     * @return string  the data in XML format
1716
     */
1717
    function serializedata($typ, $val)
1718
    {
1719
        $rs = '';
1720
        if (!array_key_exists($typ, $GLOBALS['XML_RPC_Types'])) {
1721
            // XXX
1722
            // need some way to report this error
1723
            return;
1724
        }
1725
        switch ($GLOBALS['XML_RPC_Types'][$typ]) {
1726
        case 3:
1727
            // struct
1728
            $rs .= "<struct>\n";
1729
            reset($val);
1730
            foreach ($val as $key2 => $val2) {
1731
                $rs .= "<member><name>${key2}</name>\n";
1732
                $rs .= $this->serializeval($val2);
1733
                $rs .= "</member>\n";
1734
            }
1735
            $rs .= '</struct>';
1736
            break;
1737

    
1738
        case 2:
1739
            // array
1740
            $rs .= "<array>\n<data>\n";
1741
            for ($i = 0; $i < sizeof($val); $i++) {
1742
                $rs .= $this->serializeval($val[$i]);
1743
            }
1744
            $rs .= "</data>\n</array>";
1745
            break;
1746

    
1747
        case 1:
1748
            switch ($typ) {
1749
            case $GLOBALS['XML_RPC_Base64']:
1750
                $rs .= "<${typ}>" . base64_encode($val) . "</${typ}>";
1751
                break;
1752
            case $GLOBALS['XML_RPC_Boolean']:
1753
                $rs .= "<${typ}>" . ($val ? '1' : '0') . "</${typ}>";
1754
                break;
1755
            case $GLOBALS['XML_RPC_String']:
1756
                $rs .= "<${typ}>" . htmlspecialchars($val). "</${typ}>";
1757
                break;
1758
            default:
1759
                $rs .= "<${typ}>${val}</${typ}>";
1760
            }
1761
        }
1762
        return $rs;
1763
    }
1764

    
1765
    /**
1766
     * @return string  the data in XML format
1767
     */
1768
    function serialize()
1769
    {
1770
        return $this->serializeval($this);
1771
    }
1772

    
1773
    /**
1774
     * @return string  the data in XML format
1775
     */
1776
    function serializeval($o)
1777
    {
1778
        if (!is_object($o) || empty($o->me) || !is_array($o->me)) {
1779
            return '';
1780
        }
1781
        $ar = $o->me;
1782
        reset($ar);
1783
        list($typ, $val) = each($ar);
1784
        return '<value>' .  $this->serializedata($typ, $val) .  "</value>\n";
1785
    }
1786

    
1787
    /**
1788
     * @return mixed  the contents of the element requested
1789
     */
1790
    function structmem($m)
1791
    {
1792
        return $this->me['struct'][$m];
1793
    }
1794

    
1795
    /**
1796
     * @return void
1797
     */
1798
    function structreset()
1799
    {
1800
        reset($this->me['struct']);
1801
    }
1802

    
1803
    /**
1804
     * @return  the key/value pair of the struct's current element
1805
     */
1806
    function structeach()
1807
    {
1808
        return each($this->me['struct']);
1809
    }
1810

    
1811
    /**
1812
     * @return mixed  the current value
1813
     */
1814
    function getval()
1815
    {
1816
        // UNSTABLE
1817

    
1818
        reset($this->me);
1819
        $b = current($this->me);
1820

    
1821
        // contributed by I Sofer, 2001-03-24
1822
        // add support for nested arrays to scalarval
1823
        // i've created a new method here, so as to
1824
        // preserve back compatibility
1825

    
1826
        if (is_array($b)) {
1827
            foreach ($b as $id => $cont) {
1828
                $b[$id] = $cont->scalarval();
1829
            }
1830
        }
1831

    
1832
        // add support for structures directly encoding php objects
1833
        if (is_object($b)) {
1834
            $t = get_object_vars($b);
1835
            foreach ($t as $id => $cont) {
1836
                $t[$id] = $cont->scalarval();
1837
            }
1838
            foreach ($t as $id => $cont) {
1839
                $b->$id = $cont;
1840
            }
1841
        }
1842

    
1843
        // end contrib
1844
        return $b;
1845
    }
1846

    
1847
    /**
1848
     * @return mixed  the current element's scalar value.  If the value is
1849
     *                 not scalar, FALSE is returned.
1850
     */
1851
    function scalarval()
1852
    {
1853
        reset($this->me);
1854
        $v = current($this->me);
1855
        if (!is_scalar($v)) {
1856
            $v = false;
1857
        }
1858
        return $v;
1859
    }
1860

    
1861
    /**
1862
     * @return string
1863
     */
1864
    function scalartyp()
1865
    {
1866
        reset($this->me);
1867
        $a = key($this->me);
1868
        if ($a == $GLOBALS['XML_RPC_I4']) {
1869
            $a = $GLOBALS['XML_RPC_Int'];
1870
        }
1871
        return $a;
1872
    }
1873

    
1874
    /**
1875
     * @return mixed  the struct's current element
1876
     */
1877
    function arraymem($m)
1878
    {
1879
        return $this->me['array'][$m];
1880
    }
1881

    
1882
    /**
1883
     * @return int  the number of elements in the array
1884
     */
1885
    function arraysize()
1886
    {
1887
        reset($this->me);
1888
        list($a, $b) = each($this->me);
1889
        return sizeof($b);
1890
    }
1891

    
1892
    /**
1893
     * Determines if the item submitted is an XML_RPC_Value object
1894
     *
1895
     * @param mixed $val  the variable to be evaluated
1896
     *
1897
     * @return bool  TRUE if the item is an XML_RPC_Value object
1898
     *
1899
     * @static
1900
     * @since Method available since Release 1.3.0
1901
     */
1902
    function isValue($val)
1903
    {
1904
        return (strtolower(get_class($val)) == 'xml_rpc_value');
1905
    }
1906
}
1907

    
1908
/**
1909
 * Return an ISO8601 encoded string
1910
 *
1911
 * While timezones ought to be supported, the XML-RPC spec says:
1912
 *
1913
 * "Don't assume a timezone. It should be specified by the server in its
1914
 * documentation what assumptions it makes about timezones."
1915
 *
1916
 * This routine always assumes localtime unless $utc is set to 1, in which
1917
 * case UTC is assumed and an adjustment for locale is made when encoding.
1918
 *
1919
 * @return string  the formatted date
1920
 */
1921
function XML_RPC_iso8601_encode($timet, $utc = 0)
1922
{
1923
    if (!$utc) {
1924
        $t = strftime('%Y%m%dT%H:%M:%S', $timet);
1925
    } else {
1926
        if (function_exists('gmstrftime')) {
1927
            // gmstrftime doesn't exist in some versions
1928
            // of PHP
1929
            $t = gmstrftime('%Y%m%dT%H:%M:%S', $timet);
1930
        } else {
1931
            $t = strftime('%Y%m%dT%H:%M:%S', $timet - date('Z'));
1932
        }
1933
    }
1934
    return $t;
1935
}
1936

    
1937
/**
1938
 * Convert a datetime string into a Unix timestamp
1939
 *
1940
 * While timezones ought to be supported, the XML-RPC spec says:
1941
 *
1942
 * "Don't assume a timezone. It should be specified by the server in its
1943
 * documentation what assumptions it makes about timezones."
1944
 *
1945
 * This routine always assumes localtime unless $utc is set to 1, in which
1946
 * case UTC is assumed and an adjustment for locale is made when encoding.
1947
 *
1948
 * @return int  the unix timestamp of the date submitted
1949
 */
1950
function XML_RPC_iso8601_decode($idate, $utc = 0)
1951
{
1952
    $t = 0;
1953
    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)) {
1954
        if ($utc) {
1955
            $t = gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
1956
        } else {
1957
            $t = mktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
1958
        }
1959
    }
1960
    return $t;
1961
}
1962

    
1963
/**
1964
 * Converts an XML_RPC_Value object into native PHP types
1965
 *
1966
 * @param object $XML_RPC_val  the XML_RPC_Value object to decode
1967
 *
1968
 * @return mixed  the PHP values
1969
 */
1970
function XML_RPC_decode($XML_RPC_val)
1971
{
1972
    $kind = $XML_RPC_val->kindOf();
1973

    
1974
    if ($kind == 'scalar') {
1975
        return $XML_RPC_val->scalarval();
1976

    
1977
    } elseif ($kind == 'array') {
1978
        $size = $XML_RPC_val->arraysize();
1979
        $arr = array();
1980
        for ($i = 0; $i < $size; $i++) {
1981
            $arr[] = XML_RPC_decode($XML_RPC_val->arraymem($i));
1982
        }
1983
        return $arr;
1984

    
1985
    } elseif ($kind == 'struct') {
1986
        $XML_RPC_val->structreset();
1987
        $arr = array();
1988
        while (list($key, $value) = $XML_RPC_val->structeach()) {
1989
            $arr[$key] = XML_RPC_decode($value);
1990
        }
1991
        return $arr;
1992
    }
1993
}
1994

    
1995
/**
1996
 * Converts native PHP types into an XML_RPC_Value object
1997
 *
1998
 * @param mixed $php_val  the PHP value or variable you want encoded
1999
 *
2000
 * @return object  the XML_RPC_Value object
2001
 */
2002
function XML_RPC_encode($php_val)
2003
{
2004
    $type = gettype($php_val);
2005
    $XML_RPC_val = new XML_RPC_Value;
2006

    
2007
    switch ($type) {
2008
    case 'array':
2009
        if (empty($php_val)) {
2010
            $XML_RPC_val->addArray($php_val);
2011
            break;
2012
        }
2013
        $tmp = array_diff(array_keys($php_val), range(0, count($php_val)-1));
2014
        if (empty($tmp)) {
2015
           $arr = array();
2016
           foreach ($php_val as $k => $v) {
2017
               $arr[$k] = XML_RPC_encode($v);
2018
           }
2019
           $XML_RPC_val->addArray($arr);
2020
           break;
2021
        }
2022
        // fall though if it's not an enumerated array
2023

    
2024
    case 'object':
2025
        $arr = array();
2026
        foreach ($php_val as $k => $v) {
2027
            $arr[$k] = XML_RPC_encode($v);
2028
        }
2029
        $XML_RPC_val->addStruct($arr);
2030
        break;
2031

    
2032
    case 'integer':
2033
        $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_Int']);
2034
        break;
2035

    
2036
    case 'double':
2037
        $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_Double']);
2038
        break;
2039

    
2040
    case 'string':
2041
    case 'NULL':
2042
        if ($GLOBALS['XML_RPC_func_ereg']('^[0-9]{8}\T{1}[0-9]{2}\:[0-9]{2}\:[0-9]{2}$', $php_val)) {
2043
            $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_DateTime']);
2044
        } elseif ($GLOBALS['XML_RPC_auto_base64']
2045
                  && $GLOBALS['XML_RPC_func_ereg']("[^ -~\t\r\n]", $php_val))
2046
        {
2047
            // Characters other than alpha-numeric, punctuation, SP, TAB,
2048
            // LF and CR break the XML parser, encode value via Base 64.
2049
            $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_Base64']);
2050
        } else {
2051
            $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_String']);
2052
        }
2053
        break;
2054

    
2055
    case 'boolean':
2056
        // Add support for encoding/decoding of booleans, since they
2057
        // are supported in PHP
2058
        // by <G_Giunta_2001-02-29>
2059
        $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_Boolean']);
2060
        break;
2061

    
2062
    case 'unknown type':
2063
    default:
2064
        $XML_RPC_val = false;
2065
    }
2066
    return $XML_RPC_val;
2067
}
2068

    
2069
/*
2070
 * Local variables:
2071
 * tab-width: 4
2072
 * c-basic-offset: 4
2073
 * c-hanging-comment-ender-p: nil
2074
 * End:
2075
 */
2076

    
2077
?>
(39-39/40)