Project

General

Profile

Download (59.9 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'      => gettext("Unknown method"),
170
    'invalid_return'      => gettext("Invalid return payload: enable debugging to examine incoming payload"),
171
    'incorrect_params'    => gettext("Incorrect parameters passed to method"),
172
    'introspect_unknown'  => gettext("Can't introspect: method unknown"),
173
    'http_error'          => gettext("Didn't receive 200 OK from remote server."),
174
    'not_response_object' => gettext("The requested method didn't return an XML_RPC_Response object."),
175
    'invalid_request'     => gettext("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'] = false;
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'] = gettext('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'] = sprintf(gettext("xmlrpc element %s cannot be child of %s"), $name, $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(gettext('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 = sprintf(
893
                gettext(
894
                    "send()'s %s parameter must be an XML_RPC_Message object."
895
                ), $msg);
896
            $this->raiseError($this->errstr, XML_RPC_ERROR_PROGRAMMING);
897
            return 0;
898
        }
899
        $msg->debug = $this->debug;
900
        return $this->sendPayloadHTTP10($msg, $this->server, $this->port,
901
                                        $timeout, $this->username,
902
                                        $this->password);
903
    }
904

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

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

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

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

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

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

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

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

    
1014
        fclose($fp);
1015
        return $resp;
1016
    }
1017

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1202
    /**
1203
     * @var array
1204
     */
1205
    var $params = array();
1206

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

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

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

    
1227

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1437
                default:
1438
                    return $XML_RPC_defencoding;
1439
            }
1440
        } else {
1441
            return $XML_RPC_defencoding;
1442
        }
1443
    }
1444

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

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

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

    
1468
        $XML_RPC_xh = array();
1469
        $XML_RPC_xh[$parser] = array();
1470

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

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

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

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

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

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

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

    
1535
        xml_parser_free($parser_resource);
1536

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

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

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

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

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

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

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

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

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

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

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

    
1709
        case 2:
1710
            return 'array';
1711

    
1712
        case 1:
1713
            return 'scalar';
1714

    
1715
        default:
1716
            return 'undef';
1717
        }
1718
    }
1719

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

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

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

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

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

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

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

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

    
1817
    /**
1818
     * @return mixed  the current value
1819
     */
1820
    function getval()
1821
    {
1822
        // UNSTABLE
1823

    
1824
        reset($this->me);
1825
        $b = current($this->me);
1826

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

    
1832
        if (is_array($b)) {
1833
            foreach ($b as $id => $cont) {
1834
                $b[$id] = $cont->scalarval();
1835
            }
1836
        }
1837

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

    
1849
        // end contrib
1850
        return $b;
1851
    }
1852

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

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

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

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

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

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

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

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

    
1980
    if ($kind == 'scalar') {
1981
        return $XML_RPC_val->scalarval();
1982

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

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

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

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

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

    
2038
    case 'integer':
2039
        $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_Int']);
2040
        break;
2041

    
2042
    case 'double':
2043
        $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_Double']);
2044
        break;
2045

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

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

    
2068
    case 'unknown type':
2069
    default:
2070
        $XML_RPC_val = false;
2071
    }
2072
    return $XML_RPC_val;
2073
}
2074

    
2075
/*
2076
 * Local variables:
2077
 * tab-width: 4
2078
 * c-basic-offset: 4
2079
 * c-hanging-comment-ender-p: nil
2080
 * End:
2081
 */
2082

    
2083
?>
(51-51/53)