~ubuntu-branches/ubuntu/lucid/ampache/lucid

« back to all changes in this revision

Viewing changes to modules/pearxmlrpc/rpc.php

  • Committer: Bazaar Package Importer
  • Author(s): Charlie Smotherman
  • Date: 2009-07-07 07:23:35 UTC
  • mfrom: (1.1.6 upstream)
  • Revision ID: james.westby@ubuntu.com-20090707072335-soq0jyo59mgopzd2
Tags: 3.5.1-0ubuntu1
 * New upstream release.  Summary of new features:  (LP: #377016)
   - Make the PHP error a little clearer for windows users by indicating
     that their version of PHP is < 5.3 (required for windows)
   - Fix random methods not working for Localplay
   - Fix extra space on prefixed albums (Thx ibizaman)
   - Add missing operator on tag and rating searches so they will
     work with other methods (Thx kiehnet@netscape.net)
   - Fix get_art_url() so it returns something... 
   - Fix problem with creating new playlists where it doesn't work
     but appending to an existing did. 
   - Fixed issue with url_to_song, also cleaned up the code a bit
   - Fixed issue with Random All Catalogs
   - Fixed issues with API and Tag methods not working as advertised
   - Fix endless loop in getid3() with malformed genre tags in mp3s
   - Fixed show test page always returning false on web path
   - Update Man page to adhear to newer Debian rules
   - Fixed issue with Videos being incorrectly registered with stats
     and now playing as songs. 
   - Fixed missing > in HTML for song row
 * Bumped Standards-Version to 3.8.2, no changes needed.
 * Bumped debhelper to dh 7.
   - increased debian/compat to 7.
   - debian/rules removed dh_clean -k in favor of dh_prep
 * Lintian complains of FreeMonoMedium.ttf being an embeded fonts package.
   FreeMonoMedium.ttf is actually part of the ttf-freefont package.
   - added ttf-freefont to the Depends section of debian/control.
   - added -XFreeMono-Medium to dh_install in debian/rules.
   - added FreeMono.ttf symbolic link to debian/links.
 * Lintian complains of the wrong file permissions for 
   -  /locale/base/gather-messages.sh, added -Xgather-messages.sh to 
   debian/rules, gather-messages.sh is not used by ampache proper and 
   can be safely removed.  It is only utilized by developers who are 
   creating or editing the translation files.
   -  /locale/pl_PL/LC_MESSAGES/messages.po added find and chmod rule 
   to debian/rules.
   -  /locale/pl_PL/LC_MESSAGES/messages.mo added find and chmod rule 
   to debian/rules.
   -  /docs/CHANGELOG added find and chmod rule to debian/rules.
 * Lintian complains of wrong-name-for-upstream-changelog
   -  install upstream CHANGELOG to /usr/share/ampache/www/docs
   -  added find and gzip -9 rule to debian/rules
   -  added symlink creation to debian/links to link
      /usr/share/ampache/www/docs/CHANGELOG.gz to 
      /usr/share/doc/ampache/changelog.gz  
 * Lacy Marrow has responded and has stated that he is dropping the GPL-3 
   licensing of his work and is now releasing version 5.9.5 of the 
   XSPF JukeBox under the same BSD license that the original version of XSPF 
   Music Player was released under (XSPF JukeBox is based on XSPF Music 
   Player).  So now XSPF Music Player and XSPF JukeBox are now released under
   the same BSD type license.  This closes RC Bug #526719.  Closes: #526719
   - Updated debian/copyright to refect this.
 * Added dh_installman to debian/rules so the manpage now installs correctly.
   - Added debian/ampache.manpages.
 * debian/ampache.config downgraded db_input to medium
 * debian/copyright removed (C) in favor of the word copyright.
 

Show diffs side-by-side

added added

removed removed

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