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
	pfSense_MODULE:	utils
41
*/
42

    
43
if (!function_exists('xml_parser_create')) {
44
    include_once 'PEAR.inc';
45
    PEAR::loadExtension('xml');
46
}
47

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

    
77

    
78
/**
79
 * Data types
80
 * @global string $GLOBALS['XML_RPC_I4']
81
 */
82
$GLOBALS['XML_RPC_I4'] = 'i4';
83

    
84
/**
85
 * Data types
86
 * @global string $GLOBALS['XML_RPC_Int']
87
 */
88
$GLOBALS['XML_RPC_Int'] = 'int';
89

    
90
/**
91
 * Data types
92
 * @global string $GLOBALS['XML_RPC_Boolean']
93
 */
94
$GLOBALS['XML_RPC_Boolean'] = 'boolean';
95

    
96
/**
97
 * Data types
98
 * @global string $GLOBALS['XML_RPC_Double']
99
 */
100
$GLOBALS['XML_RPC_Double'] = 'double';
101

    
102
/**
103
 * Data types
104
 * @global string $GLOBALS['XML_RPC_String']
105
 */
106
$GLOBALS['XML_RPC_String'] = 'string';
107

    
108
/**
109
 * Data types
110
 * @global string $GLOBALS['XML_RPC_DateTime']
111
 */
112
$GLOBALS['XML_RPC_DateTime'] = 'dateTime.iso8601';
113

    
114
/**
115
 * Data types
116
 * @global string $GLOBALS['XML_RPC_Base64']
117
 */
118
$GLOBALS['XML_RPC_Base64'] = 'base64';
119

    
120
/**
121
 * Data types
122
 * @global string $GLOBALS['XML_RPC_Array']
123
 */
124
$GLOBALS['XML_RPC_Array'] = 'array';
125

    
126
/**
127
 * Data types
128
 * @global string $GLOBALS['XML_RPC_Struct']
129
 */
130
$GLOBALS['XML_RPC_Struct'] = 'struct';
131

    
132

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

    
149

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

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

    
178

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

    
185
/**
186
 * User error codes start at 800
187
 * @global int $GLOBALS['XML_RPC_erruser']
188
 */
189
$GLOBALS['XML_RPC_erruser'] = 800;
190

    
191
/**
192
 * XML parse error codes start at 100
193
 * @global int $GLOBALS['XML_RPC_errxml']
194
 */
195
$GLOBALS['XML_RPC_errxml'] = 100;
196

    
197

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

    
204

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

    
225

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

    
233

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

    
258

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

    
276

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

    
286
    $parser = (int) $parser_resource;
287

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

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

    
311
    switch ($name) {
312
    case 'STRUCT':
313
        $XML_RPC_xh[$parser]['cm']++;
314

    
315
        // turn quoting off
316
        $XML_RPC_xh[$parser]['qt'] = 0;
317

    
318
        $cur_val = array();
319
        $cur_val['value'] = array();
320
        $cur_val['members'] = 1;
321
        array_unshift($XML_RPC_xh[$parser]['valuestack'], $cur_val);
322
        break;
323

    
324
    case 'ARRAY':
325
        $XML_RPC_xh[$parser]['cm']++;
326

    
327
        // turn quoting off
328
        $XML_RPC_xh[$parser]['qt'] = 0;
329

    
330
        $cur_val = array();
331
        $cur_val['value'] = array();
332
        $cur_val['members'] = 0;
333
        array_unshift($XML_RPC_xh[$parser]['valuestack'], $cur_val);
334
        break;
335

    
336
    case 'NAME':
337
        $XML_RPC_xh[$parser]['ac'] = '';
338
        break;
339

    
340
    case 'FAULT':
341
        $XML_RPC_xh[$parser]['isf'] = 1;
342
        break;
343

    
344
    case 'PARAM':
345
        $XML_RPC_xh[$parser]['valuestack'] = array();
346
        break;
347

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

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

    
367
        if ($name == 'DATETIME.ISO8601' || $name == 'STRING') {
368
            $XML_RPC_xh[$parser]['qt'] = 1;
369

    
370
            if ($name == 'DATETIME.ISO8601') {
371
                $XML_RPC_xh[$parser]['vt'] = $GLOBALS['XML_RPC_DateTime'];
372
            }
373

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

    
384
    case 'MEMBER':
385
        $XML_RPC_xh[$parser]['ac'] = '';
386
        break;
387

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

    
397

    
398
    // Save current element to stack
399
    array_unshift($XML_RPC_xh[$parser]['stack'], $name);
400

    
401
    if ($name != 'VALUE') {
402
        $XML_RPC_xh[$parser]['lv'] = 0;
403
    }
404
}
405

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

    
415
    $parser = (int) $parser_resource;
416

    
417
    if ($XML_RPC_xh[$parser]['isf'] >= 2) {
418
        return;
419
    }
420

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

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

    
436
    case 'NAME':
437
    $XML_RPC_xh[$parser]['valuestack'][0]['name'] = $XML_RPC_xh[$parser]['ac'];
438
        break;
439

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

    
449
        $XML_RPC_xh[$parser]['vt'] = strtolower($name);
450
        // Drop through intentionally.
451

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

    
478
        $XML_RPC_xh[$parser]['ac'] = '';
479
        $XML_RPC_xh[$parser]['qt'] = 0;
480
        $XML_RPC_xh[$parser]['lv'] = 3; // indicate we've found a value
481
        break;
482

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

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

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

    
508
    case 'MEMBER':
509
        $XML_RPC_xh[$parser]['ac'] = '';
510
        $XML_RPC_xh[$parser]['qt'] = 0;
511

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

    
521
    case 'DATA':
522
        $XML_RPC_xh[$parser]['ac'] = '';
523
        $XML_RPC_xh[$parser]['qt'] = 0;
524
        break;
525

    
526
    case 'PARAM':
527
        $XML_RPC_xh[$parser]['params'][] = $XML_RPC_xh[$parser]['value'];
528
        break;
529

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

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

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

    
552
    $parser = (int) $parser_resource;
553

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

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

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

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

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

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

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

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

    
641
    /**
642
     * The name of the remote server to connect to
643
     * @var string
644
     */
645
    var $server = '';
646

    
647
    /**
648
     * The protocol to use in contacting the remote server
649
     * @var string
650
     */
651
    var $protocol = 'http://';
652

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

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

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

    
677
    /**
678
     * The name of the proxy server to use, if any
679
     * @var string
680
     */
681
    var $proxy = '';
682

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

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

    
699
    /**
700
     * A user name for accessing the proxy server
701
     * @var string
702
     */
703
    var $proxy_user = '';
704

    
705
    /**
706
     * A password for accessing the proxy server
707
     * @var string
708
     */
709
    var $proxy_pass = '';
710

    
711
    /**
712
     * The error number, if any
713
     * @var integer
714
     */
715
    var $errno = 0;
716

    
717
    /**
718
     * The error message, if any
719
     * @var string
720
     */
721
    var $errstr = '';
722

    
723
    /**
724
     * The current debug mode (1 = on, 0 = off)
725
     * @var integer
726
     */
727
    var $debug = 0;
728

    
729
    /**
730
     * The HTTP headers for the current request.
731
     * @var string
732
     */
733
    var $headers = '';
734

    
735

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

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

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

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

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

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

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

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

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

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

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

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

    
995
        $op  = $this->headers . "\r\n\r\n";
996
        $op .= $msg->payload;
997

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

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

    
1012
        fclose($fp);
1013
        return $resp;
1014
    }
1015

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

    
1040
        $this->headers .= "User-Agent: PEAR XML_RPC\r\n";
1041
        $this->headers .= 'Host: ' . $this->server . "\r\n";
1042

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

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

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

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

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

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

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

    
1115
    /**
1116
     * @return mixed  the value
1117
     */
1118
    function value()
1119
    {
1120
        return $this->xv;
1121
    }
1122

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

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

    
1177
    /**
1178
     * The current debug mode (1 = on, 0 = off)
1179
     * @var integer
1180
     */
1181
    var $debug = 0;
1182

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

    
1194
    /**
1195
     * The method presently being evaluated
1196
     * @var string
1197
     */
1198
    var $methodname = '';
1199

    
1200
    /**
1201
     * @var array
1202
     */
1203
    var $params = array();
1204

    
1205
    /**
1206
     * The XML message being generated
1207
     * @var string
1208
     */
1209
    var $payload = '';
1210

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

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

    
1225

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1435
                default:
1436
                    return $XML_RPC_defencoding;
1437
            }
1438
        } else {
1439
            return $XML_RPC_defencoding;
1440
        }
1441
    }
1442

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

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

    
1462
        $encoding = $this->getEncoding($data);
1463
        $parser_resource = xml_parser_create($encoding);
1464
        $parser = (int) $parser_resource;
1465

    
1466
        $XML_RPC_xh = array();
1467
        $XML_RPC_xh[$parser] = array();
1468

    
1469
        $XML_RPC_xh[$parser]['cm'] = 0;
1470
        $XML_RPC_xh[$parser]['isf'] = 0;
1471
        $XML_RPC_xh[$parser]['ac'] = '';
1472
        $XML_RPC_xh[$parser]['qt'] = '';
1473
        $XML_RPC_xh[$parser]['stack'] = array();
1474
        $XML_RPC_xh[$parser]['valuestack'] = array();
1475

    
1476
        xml_parser_set_option($parser_resource, XML_OPTION_CASE_FOLDING, true);
1477
        xml_set_element_handler($parser_resource, 'XML_RPC_se', 'XML_RPC_ee');
1478
        xml_set_character_data_handler($parser_resource, 'XML_RPC_cd');
1479

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

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

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

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

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

    
1533
        xml_parser_free($parser_resource);
1534

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

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

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

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

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

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

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

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

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

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

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

    
1706
        case 2:
1707
            return 'array';
1708

    
1709
        case 1:
1710
            return 'scalar';
1711

    
1712
        default:
1713
            return 'undef';
1714
        }
1715
    }
1716

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

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

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

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

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

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

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

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

    
1814
    /**
1815
     * @return mixed  the current value
1816
     */
1817
    function getval()
1818
    {
1819
        // UNSTABLE
1820

    
1821
        reset($this->me);
1822
        $b = current($this->me);
1823

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

    
1829
        if (is_array($b)) {
1830
            foreach ($b as $id => $cont) {
1831
                $b[$id] = $cont->scalarval();
1832
            }
1833
        }
1834

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

    
1846
        // end contrib
1847
        return $b;
1848
    }
1849

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

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

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

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

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

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

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

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

    
1977
    if ($kind == 'scalar') {
1978
        return $XML_RPC_val->scalarval();
1979

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

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

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

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

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

    
2035
    case 'integer':
2036
        $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_Int']);
2037
        break;
2038

    
2039
    case 'double':
2040
        $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_Double']);
2041
        break;
2042

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

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

    
2065
    case 'unknown type':
2066
    default:
2067
        $XML_RPC_val = false;
2068
    }
2069
    return $XML_RPC_val;
2070
}
2071

    
2072
/*
2073
 * Local variables:
2074
 * tab-width: 4
2075
 * c-basic-offset: 4
2076
 * c-hanging-comment-ender-p: nil
2077
 * End:
2078
 */
2079

    
2080
?>
(59-59/61)