blob: 80648c9bd6c54672e1579b6493b88fb3ef19ad87 [file] [log] [blame]
Andrey Andreeva30faf92011-12-25 18:15:34 +02001<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
Derek Allard2067d1a2008-11-13 22:59:24 +00002/**
3 * CodeIgniter
4 *
Phil Sturgeon07c1ac82012-03-09 17:03:37 +00005 * An open source application development framework for PHP 5.2.4 or newer
Derek Allard2067d1a2008-11-13 22:59:24 +00006 *
Derek Jonesf4a4bd82011-10-20 12:18:42 -05007 * NOTICE OF LICENSE
Andrey Andreeva30faf92011-12-25 18:15:34 +02008 *
Derek Jonesf4a4bd82011-10-20 12:18:42 -05009 * Licensed under the Open Software License version 3.0
Andrey Andreeva30faf92011-12-25 18:15:34 +020010 *
Derek Jonesf4a4bd82011-10-20 12:18:42 -050011 * This source file is subject to the Open Software License (OSL 3.0) that is
12 * bundled with this package in the files license.txt / license.rst. It is
13 * also available through the world wide web at this URL:
14 * http://opensource.org/licenses/OSL-3.0
15 * If you did not receive a copy of the license and are unable to obtain it
16 * through the world wide web, please send an email to
17 * licensing@ellislab.com so we can send you a copy immediately.
18 *
Derek Allard2067d1a2008-11-13 22:59:24 +000019 * @package CodeIgniter
Derek Jonesf4a4bd82011-10-20 12:18:42 -050020 * @author EllisLab Dev Team
Greg Aker0defe5d2012-01-01 18:46:41 -060021 * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
Derek Jonesf4a4bd82011-10-20 12:18:42 -050022 * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
Derek Allard2067d1a2008-11-13 22:59:24 +000023 * @link http://codeigniter.com
24 * @since Version 1.0
25 * @filesource
26 */
27
Derek Allard2067d1a2008-11-13 22:59:24 +000028/**
29 * XML-RPC request handler class
30 *
31 * @package CodeIgniter
32 * @subpackage Libraries
33 * @category XML-RPC
Derek Jonesf4a4bd82011-10-20 12:18:42 -050034 * @author EllisLab Dev Team
Derek Allard2067d1a2008-11-13 22:59:24 +000035 * @link http://codeigniter.com/user_guide/libraries/xmlrpc.html
36 */
Andrey Andreevc8709832012-04-04 13:43:53 +030037
38if ( ! function_exists('xml_parser_create'))
39{
40 show_error('Your PHP installation does not support XML');
41}
42
43// ------------------------------------------------------------------------
44
Derek Allard2067d1a2008-11-13 22:59:24 +000045class CI_Xmlrpc {
46
Andrey Andreeva30faf92011-12-25 18:15:34 +020047 public $debug = FALSE; // Debugging on or off
48 public $xmlrpcI4 = 'i4';
49 public $xmlrpcInt = 'int';
50 public $xmlrpcBoolean = 'boolean';
51 public $xmlrpcDouble = 'double';
52 public $xmlrpcString = 'string';
53 public $xmlrpcDateTime = 'dateTime.iso8601';
54 public $xmlrpcBase64 = 'base64';
55 public $xmlrpcArray = 'array';
56 public $xmlrpcStruct = 'struct';
Barry Mienydd671972010-10-04 16:33:58 +020057
Andrey Andreeva30faf92011-12-25 18:15:34 +020058 public $xmlrpcTypes = array();
59 public $valid_parents = array();
60 public $xmlrpcerr = array(); // Response numbers
61 public $xmlrpcstr = array(); // Response strings
Barry Mienydd671972010-10-04 16:33:58 +020062
Andrey Andreeva30faf92011-12-25 18:15:34 +020063 public $xmlrpc_defencoding = 'UTF-8';
64 public $xmlrpcName = 'XML-RPC for CodeIgniter';
65 public $xmlrpcVersion = '1.1';
66 public $xmlrpcerruser = 800; // Start of user errors
67 public $xmlrpcerrxml = 100; // Start of XML Parse errors
68 public $xmlrpc_backslash = ''; // formulate backslashes for escaping regexp
Barry Mienydd671972010-10-04 16:33:58 +020069
Andrey Andreeva30faf92011-12-25 18:15:34 +020070 public $client;
71 public $method;
72 public $data;
73 public $message = '';
74 public $error = ''; // Error string for request
75 public $result;
76 public $response = array(); // Response from remote server
Derek Allard2067d1a2008-11-13 22:59:24 +000077
Andrey Andreeva30faf92011-12-25 18:15:34 +020078 public $xss_clean = TRUE;
Derek Allard2067d1a2008-11-13 22:59:24 +000079
Derek Allard2067d1a2008-11-13 22:59:24 +000080
Andrey Andreevc8709832012-04-04 13:43:53 +030081 /**
82 * Constructor
83 *
84 * Initializes property default values
85 *
86 * @param array
87 * @return void
88 */
Greg Akera9263282010-11-10 15:26:43 -060089 public function __construct($config = array())
Derek Allard2067d1a2008-11-13 22:59:24 +000090 {
Derek Allard2067d1a2008-11-13 22:59:24 +000091 $this->xmlrpc_backslash = chr(92).chr(92);
Barry Mienydd671972010-10-04 16:33:58 +020092
Derek Allard2067d1a2008-11-13 22:59:24 +000093 // Types for info sent back and forth
94 $this->xmlrpcTypes = array(
Barry Mienydd671972010-10-04 16:33:58 +020095 $this->xmlrpcI4 => '1',
96 $this->xmlrpcInt => '1',
97 $this->xmlrpcBoolean => '1',
98 $this->xmlrpcString => '1',
99 $this->xmlrpcDouble => '1',
100 $this->xmlrpcDateTime => '1',
101 $this->xmlrpcBase64 => '1',
102 $this->xmlrpcArray => '2',
103 $this->xmlrpcStruct => '3'
Derek Allard2067d1a2008-11-13 22:59:24 +0000104 );
Barry Mienydd671972010-10-04 16:33:58 +0200105
Derek Allard2067d1a2008-11-13 22:59:24 +0000106 // Array of Valid Parents for Various XML-RPC elements
Timothy Warren0688ac92012-04-20 10:25:04 -0400107 $this->valid_parents = array('BOOLEAN' => array('VALUE'),
108 'I4' => array('VALUE'),
109 'INT' => array('VALUE'),
110 'STRING' => array('VALUE'),
111 'DOUBLE' => array('VALUE'),
112 'DATETIME.ISO8601' => array('VALUE'),
113 'BASE64' => array('VALUE'),
114 'ARRAY' => array('VALUE'),
115 'STRUCT' => array('VALUE'),
116 'PARAM' => array('PARAMS'),
117 'METHODNAME' => array('METHODCALL'),
118 'PARAMS' => array('METHODCALL', 'METHODRESPONSE'),
119 'MEMBER' => array('STRUCT'),
120 'NAME' => array('MEMBER'),
121 'DATA' => array('ARRAY'),
122 'FAULT' => array('METHODRESPONSE'),
123 'VALUE' => array('MEMBER', 'DATA', 'PARAM', 'FAULT')
124 );
Barry Mienydd671972010-10-04 16:33:58 +0200125
126
Derek Allard2067d1a2008-11-13 22:59:24 +0000127 // XML-RPC Responses
128 $this->xmlrpcerr['unknown_method'] = '1';
129 $this->xmlrpcstr['unknown_method'] = 'This is not a known method for this XML-RPC Server';
130 $this->xmlrpcerr['invalid_return'] = '2';
Derek Jones37f4b9c2011-07-01 17:56:50 -0500131 $this->xmlrpcstr['invalid_return'] = 'The XML data received was either invalid or not in the correct form for XML-RPC. Turn on debugging to examine the XML data further.';
Derek Allard2067d1a2008-11-13 22:59:24 +0000132 $this->xmlrpcerr['incorrect_params'] = '3';
133 $this->xmlrpcstr['incorrect_params'] = 'Incorrect parameters were passed to method';
134 $this->xmlrpcerr['introspect_unknown'] = '4';
Andrey Andreeva30faf92011-12-25 18:15:34 +0200135 $this->xmlrpcstr['introspect_unknown'] = 'Cannot inspect signature for request: method unknown';
Derek Allard2067d1a2008-11-13 22:59:24 +0000136 $this->xmlrpcerr['http_error'] = '5';
137 $this->xmlrpcstr['http_error'] = "Did not receive a '200 OK' response from remote server.";
138 $this->xmlrpcerr['no_data'] = '6';
139 $this->xmlrpcstr['no_data'] ='No data received from server.';
Barry Mienydd671972010-10-04 16:33:58 +0200140
Derek Allard2067d1a2008-11-13 22:59:24 +0000141 $this->initialize($config);
Barry Mienydd671972010-10-04 16:33:58 +0200142
Andrey Andreev8f50b6b2012-03-28 14:12:09 +0300143 log_message('debug', 'XML-RPC Class Initialized');
Derek Allard2067d1a2008-11-13 22:59:24 +0000144 }
Barry Mienydd671972010-10-04 16:33:58 +0200145
Andrey Andreevc8709832012-04-04 13:43:53 +0300146 // --------------------------------------------------------------------
Derek Allard2067d1a2008-11-13 22:59:24 +0000147
Andrey Andreevc8709832012-04-04 13:43:53 +0300148 /**
149 * Initialize
150 *
151 * @param array
152 * @return void
153 */
Andrey Andreeva30faf92011-12-25 18:15:34 +0200154 public function initialize($config = array())
Derek Allard2067d1a2008-11-13 22:59:24 +0000155 {
Derek Jones33559102009-02-02 18:50:38 +0000156 if (count($config) > 0)
Derek Allard2067d1a2008-11-13 22:59:24 +0000157 {
158 foreach ($config as $key => $val)
159 {
160 if (isset($this->$key))
161 {
Barry Mienydd671972010-10-04 16:33:58 +0200162 $this->$key = $val;
Derek Allard2067d1a2008-11-13 22:59:24 +0000163 }
164 }
165 }
166 }
Barry Mienydd671972010-10-04 16:33:58 +0200167
Andrey Andreevc8709832012-04-04 13:43:53 +0300168 // --------------------------------------------------------------------
Derek Allard2067d1a2008-11-13 22:59:24 +0000169
Andrey Andreevc8709832012-04-04 13:43:53 +0300170 /**
171 * Parse server URL
172 *
173 * @param string url
174 * @param int port
175 * @return void
176 */
Valio9dee5352012-07-02 10:42:28 +0300177 public function server($url, $port = 80, $proxy=FALSE, $proxy_port = 8080)
Derek Allard2067d1a2008-11-13 22:59:24 +0000178 {
Andrey Andreeva30faf92011-12-25 18:15:34 +0200179 if (strpos($url, 'http') !== 0)
Derek Allard2067d1a2008-11-13 22:59:24 +0000180 {
Andrey Andreevc8709832012-04-04 13:43:53 +0300181 $url = 'http://'.$url;
Derek Allard2067d1a2008-11-13 22:59:24 +0000182 }
Barry Mienydd671972010-10-04 16:33:58 +0200183
Derek Allard2067d1a2008-11-13 22:59:24 +0000184 $parts = parse_url($url);
Barry Mienydd671972010-10-04 16:33:58 +0200185
Andrey Andreev8f50b6b2012-03-28 14:12:09 +0300186 $path = isset($parts['path']) ? $parts['path'] : '/';
Barry Mienydd671972010-10-04 16:33:58 +0200187
Andrey Andreev8f50b6b2012-03-28 14:12:09 +0300188 if ( ! empty($parts['query']))
Derek Allard2067d1a2008-11-13 22:59:24 +0000189 {
190 $path .= '?'.$parts['query'];
Barry Mienydd671972010-10-04 16:33:58 +0200191 }
192
Valio9dee5352012-07-02 10:42:28 +0300193 $this->client = new XML_RPC_Client($path, $parts['host'], $port, $proxy, $proxy_port);
Derek Allard2067d1a2008-11-13 22:59:24 +0000194 }
Barry Mienydd671972010-10-04 16:33:58 +0200195
Andrey Andreevc8709832012-04-04 13:43:53 +0300196 // --------------------------------------------------------------------
Derek Allard2067d1a2008-11-13 22:59:24 +0000197
Andrey Andreevc8709832012-04-04 13:43:53 +0300198 /**
199 * Set Timeout
200 *
201 * @param int seconds
202 * @return void
203 */
Andrey Andreeva30faf92011-12-25 18:15:34 +0200204 public function timeout($seconds = 5)
Derek Allard2067d1a2008-11-13 22:59:24 +0000205 {
206 if ( ! is_null($this->client) && is_int($seconds))
207 {
208 $this->client->timeout = $seconds;
209 }
210 }
Barry Mienydd671972010-10-04 16:33:58 +0200211
Andrey Andreevc8709832012-04-04 13:43:53 +0300212 // --------------------------------------------------------------------
Derek Allard2067d1a2008-11-13 22:59:24 +0000213
Andrey Andreevc8709832012-04-04 13:43:53 +0300214 /**
215 * Set Methods
216 *
217 * @param string method name
218 * @return void
219 */
Andrey Andreeva30faf92011-12-25 18:15:34 +0200220 public function method($function)
Derek Allard2067d1a2008-11-13 22:59:24 +0000221 {
222 $this->method = $function;
223 }
Barry Mienydd671972010-10-04 16:33:58 +0200224
Andrey Andreevc8709832012-04-04 13:43:53 +0300225 // --------------------------------------------------------------------
Derek Allard2067d1a2008-11-13 22:59:24 +0000226
Andrey Andreevc8709832012-04-04 13:43:53 +0300227 /**
228 * Take Array of Data and Create Objects
229 *
230 * @param array
231 * @return void
232 */
Andrey Andreeva30faf92011-12-25 18:15:34 +0200233 public function request($incoming)
Derek Allard2067d1a2008-11-13 22:59:24 +0000234 {
235 if ( ! is_array($incoming))
236 {
237 // Send Error
Andrey Andreevc8709832012-04-04 13:43:53 +0300238 return;
Derek Allard2067d1a2008-11-13 22:59:24 +0000239 }
Barry Mienydd671972010-10-04 16:33:58 +0200240
Derek Allard2067d1a2008-11-13 22:59:24 +0000241 $this->data = array();
Barry Mienydd671972010-10-04 16:33:58 +0200242
Pascal Kriete14287f32011-02-14 13:39:34 -0500243 foreach ($incoming as $key => $value)
Derek Allard2067d1a2008-11-13 22:59:24 +0000244 {
245 $this->data[$key] = $this->values_parsing($value);
246 }
247 }
Barry Mienydd671972010-10-04 16:33:58 +0200248
Andrey Andreevc8709832012-04-04 13:43:53 +0300249 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200250
Andrey Andreevc8709832012-04-04 13:43:53 +0300251 /**
252 * Set Debug
253 *
254 * @param bool
255 * @return void
256 */
Andrey Andreeva30faf92011-12-25 18:15:34 +0200257 public function set_debug($flag = TRUE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000258 {
Alex Bilbied261b1e2012-06-02 11:12:16 +0100259 $this->debug = ($flag === TRUE);
Derek Allard2067d1a2008-11-13 22:59:24 +0000260 }
Barry Mienydd671972010-10-04 16:33:58 +0200261
Andrey Andreevc8709832012-04-04 13:43:53 +0300262 // --------------------------------------------------------------------
Derek Allard2067d1a2008-11-13 22:59:24 +0000263
Andrey Andreevc8709832012-04-04 13:43:53 +0300264 /**
265 * Values Parsing
266 *
267 * @param mixed
268 * @return object
269 */
270 public function values_parsing($value)
Derek Allard2067d1a2008-11-13 22:59:24 +0000271 {
Derek Jones8c4b5e72010-01-06 22:21:41 +0000272 if (is_array($value) && array_key_exists(0, $value))
Derek Allard2067d1a2008-11-13 22:59:24 +0000273 {
Andrey Andreev8f50b6b2012-03-28 14:12:09 +0300274 if ( ! isset($value[1], $this->xmlrpcTypes[$value[1]]))
Derek Allard2067d1a2008-11-13 22:59:24 +0000275 {
Andrey Andreeva30faf92011-12-25 18:15:34 +0200276 $temp = new XML_RPC_Values($value[0], (is_array($value[0]) ? 'array' : 'string'));
Derek Allard2067d1a2008-11-13 22:59:24 +0000277 }
278 else
279 {
Alex Bilbied261b1e2012-06-02 11:12:16 +0100280 if (is_array($value[0]) && ($value[1] === 'struct' OR $value[1] === 'array'))
Andrey Andreeva30faf92011-12-25 18:15:34 +0200281 {
282 while (list($k) = each($value[0]))
283 {
284 $value[0][$k] = $this->values_parsing($value[0][$k], TRUE);
285 }
286 }
287
288 $temp = new XML_RPC_Values($value[0], $value[1]);
Derek Allard2067d1a2008-11-13 22:59:24 +0000289 }
290 }
291 else
292 {
293 $temp = new XML_RPC_Values($value, 'string');
294 }
295
296 return $temp;
297 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000298
Andrey Andreevc8709832012-04-04 13:43:53 +0300299 // --------------------------------------------------------------------
Derek Allard2067d1a2008-11-13 22:59:24 +0000300
Andrey Andreevc8709832012-04-04 13:43:53 +0300301 /**
302 * Sends XML-RPC Request
303 *
304 * @return bool
305 */
Andrey Andreeva30faf92011-12-25 18:15:34 +0200306 public function send_request()
Derek Allard2067d1a2008-11-13 22:59:24 +0000307 {
Andrey Andreevc8709832012-04-04 13:43:53 +0300308 $this->message = new XML_RPC_Message($this->method, $this->data);
Derek Allard2067d1a2008-11-13 22:59:24 +0000309 $this->message->debug = $this->debug;
Barry Mienydd671972010-10-04 16:33:58 +0200310
Andrey Andreeva30faf92011-12-25 18:15:34 +0200311 if ( ! $this->result = $this->client->send($this->message) OR ! is_object($this->result->val))
Derek Allard2067d1a2008-11-13 22:59:24 +0000312 {
313 $this->error = $this->result->errstr;
314 return FALSE;
315 }
Barry Mienydd671972010-10-04 16:33:58 +0200316
Derek Allard2067d1a2008-11-13 22:59:24 +0000317 $this->response = $this->result->decode();
Derek Allard2067d1a2008-11-13 22:59:24 +0000318 return TRUE;
319 }
Barry Mienydd671972010-10-04 16:33:58 +0200320
Andrey Andreevc8709832012-04-04 13:43:53 +0300321 // --------------------------------------------------------------------
Derek Allard2067d1a2008-11-13 22:59:24 +0000322
Andrey Andreevc8709832012-04-04 13:43:53 +0300323 /**
324 * Returns Error
325 *
326 * @return string
327 */
Andrey Andreeva30faf92011-12-25 18:15:34 +0200328 public function display_error()
Derek Allard2067d1a2008-11-13 22:59:24 +0000329 {
330 return $this->error;
331 }
Barry Mienydd671972010-10-04 16:33:58 +0200332
Andrey Andreevc8709832012-04-04 13:43:53 +0300333 // --------------------------------------------------------------------
Derek Allard2067d1a2008-11-13 22:59:24 +0000334
Andrey Andreevc8709832012-04-04 13:43:53 +0300335 /**
336 * Returns Remote Server Response
337 *
338 * @return string
339 */
Andrey Andreeva30faf92011-12-25 18:15:34 +0200340 public function display_response()
Derek Allard2067d1a2008-11-13 22:59:24 +0000341 {
342 return $this->response;
343 }
Barry Mienydd671972010-10-04 16:33:58 +0200344
Andrey Andreevc8709832012-04-04 13:43:53 +0300345 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200346
Andrey Andreevc8709832012-04-04 13:43:53 +0300347 /**
348 * Sends an Error Message for Server Request
349 *
350 * @param int
351 * @param string
352 * @return object
353 */
Andrey Andreeva30faf92011-12-25 18:15:34 +0200354 public function send_error_message($number, $message)
Derek Allard2067d1a2008-11-13 22:59:24 +0000355 {
Andrey Andreeva30faf92011-12-25 18:15:34 +0200356 return new XML_RPC_Response(0, $number, $message);
Derek Allard2067d1a2008-11-13 22:59:24 +0000357 }
Barry Mienydd671972010-10-04 16:33:58 +0200358
Andrey Andreevc8709832012-04-04 13:43:53 +0300359 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200360
Andrey Andreevc8709832012-04-04 13:43:53 +0300361 /**
362 * Send Response for Server Request
363 *
364 * @param array
365 * @return object
366 */
Andrey Andreeva30faf92011-12-25 18:15:34 +0200367 public function send_response($response)
Derek Allard2067d1a2008-11-13 22:59:24 +0000368 {
369 // $response should be array of values, which will be parsed
370 // based on their data and type into a valid group of XML-RPC values
Andrey Andreeva30faf92011-12-25 18:15:34 +0200371 return new XML_RPC_Response($this->values_parsing($response));
Derek Allard2067d1a2008-11-13 22:59:24 +0000372 }
Barry Mienydd671972010-10-04 16:33:58 +0200373
Derek Allard2067d1a2008-11-13 22:59:24 +0000374} // END XML_RPC Class
375
Derek Allard2067d1a2008-11-13 22:59:24 +0000376/**
377 * XML-RPC Client class
378 *
379 * @category XML-RPC
Derek Jonesf4a4bd82011-10-20 12:18:42 -0500380 * @author EllisLab Dev Team
Derek Allard2067d1a2008-11-13 22:59:24 +0000381 * @link http://codeigniter.com/user_guide/libraries/xmlrpc.html
382 */
383class XML_RPC_Client extends CI_Xmlrpc
384{
Andrey Andreeva30faf92011-12-25 18:15:34 +0200385 public $path = '';
386 public $server = '';
387 public $port = 80;
Valio9dee5352012-07-02 10:42:28 +0300388 public $proxy = FALSE;
389 public $proxy_port = 8080;
Andrey Andreeva30faf92011-12-25 18:15:34 +0200390 public $errno = '';
391 public $errstring = '';
392 public $timeout = 5;
393 public $no_multicall = FALSE;
Derek Allard2067d1a2008-11-13 22:59:24 +0000394
Andrey Andreevc8709832012-04-04 13:43:53 +0300395 /**
396 * Constructor
397 *
398 * @param string
399 * @param object
400 * @param int
401 * @return void
402 */
Valio9dee5352012-07-02 10:42:28 +0300403 public function __construct($path, $server, $port = 80, $proxy = FALSE, $proxy_port = 8080)
Derek Allard2067d1a2008-11-13 22:59:24 +0000404 {
Greg Akera9263282010-11-10 15:26:43 -0600405 parent::__construct();
Barry Mienydd671972010-10-04 16:33:58 +0200406
Derek Allard2067d1a2008-11-13 22:59:24 +0000407 $this->port = $port;
408 $this->server = $server;
409 $this->path = $path;
Valio9dee5352012-07-02 10:42:28 +0300410 $this->proxy = $proxy;
411 $this->proxy_port = $proxy_port;
Derek Allard2067d1a2008-11-13 22:59:24 +0000412 }
Barry Mienydd671972010-10-04 16:33:58 +0200413
Andrey Andreevc8709832012-04-04 13:43:53 +0300414 // --------------------------------------------------------------------
415
416 /**
417 * Send message
418 *
419 * @param mixed
420 * @return object
421 */
Andrey Andreeva30faf92011-12-25 18:15:34 +0200422 public function send($msg)
Derek Allard2067d1a2008-11-13 22:59:24 +0000423 {
424 if (is_array($msg))
425 {
426 // Multi-call disabled
Andrey Andreevc8709832012-04-04 13:43:53 +0300427 return new XML_RPC_Response(0, $this->xmlrpcerr['multicall_recursion'], $this->xmlrpcstr['multicall_recursion']);
Derek Allard2067d1a2008-11-13 22:59:24 +0000428 }
429
430 return $this->sendPayload($msg);
431 }
432
Andrey Andreevc8709832012-04-04 13:43:53 +0300433 // --------------------------------------------------------------------
434
435 /**
436 * Send payload
437 *
438 * @param object
439 * @return object
440 */
Andrey Andreeva30faf92011-12-25 18:15:34 +0200441 public function sendPayload($msg)
Barry Mienydd671972010-10-04 16:33:58 +0200442 {
Valio9dee5352012-07-02 10:42:28 +0300443 $server = $this->server;
444 $port = $this->port;
445 if ($this->proxy !== FALSE) {
446 $server = $this->proxy;
447 $port = $this->proxy_port;
448 }
449 $fp = @fsockopen($server, $port, $this->errno, $this->errstring, $this->timeout);
Barry Mienydd671972010-10-04 16:33:58 +0200450
Derek Allard2067d1a2008-11-13 22:59:24 +0000451 if ( ! is_resource($fp))
452 {
453 error_log($this->xmlrpcstr['http_error']);
Andrey Andreevc8709832012-04-04 13:43:53 +0300454 return new XML_RPC_Response(0, $this->xmlrpcerr['http_error'], $this->xmlrpcstr['http_error']);
Derek Allard2067d1a2008-11-13 22:59:24 +0000455 }
Barry Mienydd671972010-10-04 16:33:58 +0200456
Pascal Kriete14287f32011-02-14 13:39:34 -0500457 if (empty($msg->payload))
Derek Allard2067d1a2008-11-13 22:59:24 +0000458 {
459 // $msg = XML_RPC_Messages
460 $msg->createPayload();
461 }
Barry Mienydd671972010-10-04 16:33:58 +0200462
Derek Allard2067d1a2008-11-13 22:59:24 +0000463 $r = "\r\n";
Andrey Andreev8f50b6b2012-03-28 14:12:09 +0300464 $op = 'POST '.$this->path.' HTTP/1.0'.$r
465 .'Host: '.$this->server.$r
466 .'Content-Type: text/xml'.$r
467 .'User-Agent: '.$this->xmlrpcName.$r
468 .'Content-Length: '.strlen($msg->payload).$r.$r
469 .$msg->payload;
Barry Mienydd671972010-10-04 16:33:58 +0200470
George Petsagourakis306b3782012-05-02 20:31:08 +0300471 if ( ! fwrite($fp, $op, strlen($op)))
Derek Allard2067d1a2008-11-13 22:59:24 +0000472 {
473 error_log($this->xmlrpcstr['http_error']);
Andrey Andreevc8709832012-04-04 13:43:53 +0300474 return new XML_RPC_Response(0, $this->xmlrpcerr['http_error'], $this->xmlrpcstr['http_error']);
Derek Allard2067d1a2008-11-13 22:59:24 +0000475 }
Andrey Andreevc8709832012-04-04 13:43:53 +0300476
Derek Allard2067d1a2008-11-13 22:59:24 +0000477 $resp = $msg->parseResponse($fp);
478 fclose($fp);
479 return $resp;
480 }
481
Andrey Andreevc8709832012-04-04 13:43:53 +0300482} // END XML_RPC_Client Class
Derek Allard2067d1a2008-11-13 22:59:24 +0000483
484/**
485 * XML-RPC Response class
486 *
487 * @category XML-RPC
Derek Jonesf4a4bd82011-10-20 12:18:42 -0500488 * @author EllisLab Dev Team
Derek Allard2067d1a2008-11-13 22:59:24 +0000489 * @link http://codeigniter.com/user_guide/libraries/xmlrpc.html
490 */
491class XML_RPC_Response
492{
Andrey Andreevc8709832012-04-04 13:43:53 +0300493 public $val = 0;
494 public $errno = 0;
495 public $errstr = '';
496 public $headers = array();
497 public $xss_clean = TRUE;
Derek Allard2067d1a2008-11-13 22:59:24 +0000498
Andrey Andreevc8709832012-04-04 13:43:53 +0300499 /**
500 * Constructor
501 *
502 * @param mixed
503 * @param int
504 * @param string
505 * @return void
506 */
Greg Akera9263282010-11-10 15:26:43 -0600507 public function __construct($val, $code = 0, $fstr = '')
Barry Mienydd671972010-10-04 16:33:58 +0200508 {
Alex Bilbied261b1e2012-06-02 11:12:16 +0100509 if ($code !== 0)
Derek Allard2067d1a2008-11-13 22:59:24 +0000510 {
511 // error
512 $this->errno = $code;
Andrey Andreevc8709832012-04-04 13:43:53 +0300513 $this->errstr = htmlspecialchars($fstr,
514 (is_php('5.4') ? ENT_XML1 | ENT_NOQUOTES : ENT_NOQUOTES),
515 'UTF-8');
Derek Allard2067d1a2008-11-13 22:59:24 +0000516 }
Andrey Andreev8f50b6b2012-03-28 14:12:09 +0300517 elseif ( ! is_object($val))
Derek Allard2067d1a2008-11-13 22:59:24 +0000518 {
519 // programmer error, not an object
Andrey Andreev8f50b6b2012-03-28 14:12:09 +0300520 error_log("Invalid type '".gettype($val)."' (value: ".$val.') passed to XML_RPC_Response. Defaulting to empty value.');
Derek Allard2067d1a2008-11-13 22:59:24 +0000521 $this->val = new XML_RPC_Values();
522 }
523 else
524 {
525 $this->val = $val;
526 }
527 }
528
Andrey Andreevc8709832012-04-04 13:43:53 +0300529 // --------------------------------------------------------------------
530
531 /**
532 * Fault code
533 *
534 * @return int
535 */
Andrey Andreeva30faf92011-12-25 18:15:34 +0200536 public function faultCode()
Derek Allard2067d1a2008-11-13 22:59:24 +0000537 {
538 return $this->errno;
539 }
540
Andrey Andreevc8709832012-04-04 13:43:53 +0300541 // --------------------------------------------------------------------
542
543 /**
544 * Fault string
545 *
546 * @return string
547 */
Andrey Andreeva30faf92011-12-25 18:15:34 +0200548 public function faultString()
Derek Allard2067d1a2008-11-13 22:59:24 +0000549 {
550 return $this->errstr;
551 }
552
Andrey Andreevc8709832012-04-04 13:43:53 +0300553 // --------------------------------------------------------------------
554
555 /**
556 * Value
557 *
558 * @return mixed
559 */
Andrey Andreeva30faf92011-12-25 18:15:34 +0200560 public function value()
Derek Allard2067d1a2008-11-13 22:59:24 +0000561 {
562 return $this->val;
563 }
Barry Mienydd671972010-10-04 16:33:58 +0200564
Andrey Andreevc8709832012-04-04 13:43:53 +0300565 // --------------------------------------------------------------------
566
567 /**
568 * Prepare response
569 *
570 * @return string xml
571 */
Andrey Andreeva30faf92011-12-25 18:15:34 +0200572 public function prepare_response()
Derek Allard2067d1a2008-11-13 22:59:24 +0000573 {
Andrey Andreeva30faf92011-12-25 18:15:34 +0200574 return "<methodResponse>\n"
Andrey Andreevc8709832012-04-04 13:43:53 +0300575 .($this->errno
576 ? '<fault>
Derek Allard2067d1a2008-11-13 22:59:24 +0000577 <value>
578 <struct>
579 <member>
580 <name>faultCode</name>
Andrey Andreevc8709832012-04-04 13:43:53 +0300581 <value><int>'.$this->errno.'</int></value>
Derek Allard2067d1a2008-11-13 22:59:24 +0000582 </member>
583 <member>
584 <name>faultString</name>
Andrey Andreevc8709832012-04-04 13:43:53 +0300585 <value><string>'.$this->errstr.'</string></value>
Derek Allard2067d1a2008-11-13 22:59:24 +0000586 </member>
587 </struct>
588 </value>
Andrey Andreeva30faf92011-12-25 18:15:34 +0200589</fault>'
Andrey Andreevc8709832012-04-04 13:43:53 +0300590 : "<params>\n<param>\n".$this->val->serialize_class()."</param>\n</params>")
591 ."\n</methodResponse>";
Derek Allard2067d1a2008-11-13 22:59:24 +0000592 }
Barry Mienydd671972010-10-04 16:33:58 +0200593
Andrey Andreevc8709832012-04-04 13:43:53 +0300594 // --------------------------------------------------------------------
595
596 /**
597 * Decode
598 *
599 * @param mixed
600 * @return array
601 */
Andrey Andreeva30faf92011-12-25 18:15:34 +0200602 public function decode($array = FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000603 {
604 $CI =& get_instance();
Andrey Andreeva30faf92011-12-25 18:15:34 +0200605
606 if (is_array($array))
Derek Allard2067d1a2008-11-13 22:59:24 +0000607 {
608 while (list($key) = each($array))
609 {
610 if (is_array($array[$key]))
611 {
612 $array[$key] = $this->decode($array[$key]);
613 }
614 else
615 {
Robin Sowell66a3fc02010-03-18 09:44:55 -0400616 $array[$key] = ($this->xss_clean) ? $CI->security->xss_clean($array[$key]) : $array[$key];
Derek Allard2067d1a2008-11-13 22:59:24 +0000617 }
618 }
Barry Mienydd671972010-10-04 16:33:58 +0200619
Andrey Andreevc8709832012-04-04 13:43:53 +0300620 return $array;
621 }
622
623 $result = $this->xmlrpc_decoder($this->val);
624
625 if (is_array($result))
626 {
627 $result = $this->decode($result);
Derek Allard2067d1a2008-11-13 22:59:24 +0000628 }
629 else
630 {
Andrey Andreevc8709832012-04-04 13:43:53 +0300631 $result = ($this->xss_clean) ? $CI->security->xss_clean($result) : $result;
Derek Allard2067d1a2008-11-13 22:59:24 +0000632 }
Barry Mienydd671972010-10-04 16:33:58 +0200633
Derek Allard2067d1a2008-11-13 22:59:24 +0000634 return $result;
635 }
636
Andrey Andreevc8709832012-04-04 13:43:53 +0300637 // --------------------------------------------------------------------
Derek Allard2067d1a2008-11-13 22:59:24 +0000638
Andrey Andreevc8709832012-04-04 13:43:53 +0300639 /**
640 * XML-RPC Object to PHP Types
641 *
642 * @param object
643 * @return array
644 */
Andrey Andreeva30faf92011-12-25 18:15:34 +0200645 public function xmlrpc_decoder($xmlrpc_val)
Derek Allard2067d1a2008-11-13 22:59:24 +0000646 {
647 $kind = $xmlrpc_val->kindOf();
648
Alex Bilbied261b1e2012-06-02 11:12:16 +0100649 if ($kind === 'scalar')
Derek Allard2067d1a2008-11-13 22:59:24 +0000650 {
651 return $xmlrpc_val->scalarval();
652 }
Alex Bilbied261b1e2012-06-02 11:12:16 +0100653 elseif ($kind === 'array')
Derek Allard2067d1a2008-11-13 22:59:24 +0000654 {
655 reset($xmlrpc_val->me);
Andrey Andreevadc11752011-12-30 14:46:08 +0200656 $b = current($xmlrpc_val->me);
Derek Allard2067d1a2008-11-13 22:59:24 +0000657 $arr = array();
658
Andrey Andreeva30faf92011-12-25 18:15:34 +0200659 for ($i = 0, $size = count($b); $i < $size; $i++)
Derek Allard2067d1a2008-11-13 22:59:24 +0000660 {
661 $arr[] = $this->xmlrpc_decoder($xmlrpc_val->me['array'][$i]);
662 }
663 return $arr;
664 }
Alex Bilbied261b1e2012-06-02 11:12:16 +0100665 elseif ($kind === 'struct')
Derek Allard2067d1a2008-11-13 22:59:24 +0000666 {
667 reset($xmlrpc_val->me['struct']);
668 $arr = array();
669
Pascal Kriete14287f32011-02-14 13:39:34 -0500670 while (list($key,$value) = each($xmlrpc_val->me['struct']))
Derek Allard2067d1a2008-11-13 22:59:24 +0000671 {
672 $arr[$key] = $this->xmlrpc_decoder($value);
673 }
674 return $arr;
675 }
676 }
Barry Mienydd671972010-10-04 16:33:58 +0200677
Andrey Andreevc8709832012-04-04 13:43:53 +0300678 // --------------------------------------------------------------------
Derek Allard2067d1a2008-11-13 22:59:24 +0000679
Andrey Andreevc8709832012-04-04 13:43:53 +0300680 /**
681 * ISO-8601 time to server or UTC time
682 *
683 * @param string
684 * @param bool
685 * @return int unix timestamp
686 */
687 public function iso8601_decode($time, $utc = FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000688 {
Andrey Andreevc8709832012-04-04 13:43:53 +0300689 // return a time in the localtime, or UTC
Derek Allard2067d1a2008-11-13 22:59:24 +0000690 $t = 0;
691 if (preg_match('/([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})/', $time, $regs))
692 {
Alex Bilbied261b1e2012-06-02 11:12:16 +0100693 $fnc = ($utc === TRUE) ? 'gmmktime' : 'mktime';
Pascal Kriete14287f32011-02-14 13:39:34 -0500694 $t = $fnc($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
Derek Allard2067d1a2008-11-13 22:59:24 +0000695 }
696 return $t;
697 }
Barry Mienydd671972010-10-04 16:33:58 +0200698
Andrey Andreevc8709832012-04-04 13:43:53 +0300699} // END XML_RPC_Response Class
Derek Allard2067d1a2008-11-13 22:59:24 +0000700
701/**
702 * XML-RPC Message class
703 *
704 * @category XML-RPC
Derek Jonesf4a4bd82011-10-20 12:18:42 -0500705 * @author EllisLab Dev Team
Derek Allard2067d1a2008-11-13 22:59:24 +0000706 * @link http://codeigniter.com/user_guide/libraries/xmlrpc.html
707 */
708class XML_RPC_Message extends CI_Xmlrpc
709{
Andrey Andreeva30faf92011-12-25 18:15:34 +0200710 public $payload;
711 public $method_name;
Andrey Andreevc8709832012-04-04 13:43:53 +0300712 public $params = array();
713 public $xh = array();
Derek Allard2067d1a2008-11-13 22:59:24 +0000714
Andrey Andreevc8709832012-04-04 13:43:53 +0300715 /**
716 * Constructor
717 *
718 * @param string method name
719 * @param array
720 * @return void
721 */
722 public function __construct($method, $pars = FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000723 {
Greg Akera9263282010-11-10 15:26:43 -0600724 parent::__construct();
Barry Mienydd671972010-10-04 16:33:58 +0200725
Derek Allard2067d1a2008-11-13 22:59:24 +0000726 $this->method_name = $method;
Derek Jones33559102009-02-02 18:50:38 +0000727 if (is_array($pars) && count($pars) > 0)
Derek Allard2067d1a2008-11-13 22:59:24 +0000728 {
Andrey Andreeva30faf92011-12-25 18:15:34 +0200729 for ($i = 0, $c = count($pars); $i < $c; $i++)
Derek Allard2067d1a2008-11-13 22:59:24 +0000730 {
731 // $pars[$i] = XML_RPC_Values
732 $this->params[] = $pars[$i];
733 }
734 }
735 }
Barry Mienydd671972010-10-04 16:33:58 +0200736
Andrey Andreevc8709832012-04-04 13:43:53 +0300737 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200738
Andrey Andreevc8709832012-04-04 13:43:53 +0300739 /**
740 * Create Payload to Send
741 *
742 * @return void
743 */
Andrey Andreeva30faf92011-12-25 18:15:34 +0200744 public function createPayload()
Derek Allard2067d1a2008-11-13 22:59:24 +0000745 {
Andrey Andreevc8709832012-04-04 13:43:53 +0300746 $this->payload = '<?xml version="1.0"?'.">\r\n<methodCall>\r\n"
747 .'<methodName>'.$this->method_name."</methodName>\r\n"
748 ."<params>\r\n";
Barry Mienydd671972010-10-04 16:33:58 +0200749
Andrey Andreeva30faf92011-12-25 18:15:34 +0200750 for ($i = 0, $c = count($this->params); $i < $c; $i++)
Derek Allard2067d1a2008-11-13 22:59:24 +0000751 {
752 // $p = XML_RPC_Values
753 $p = $this->params[$i];
754 $this->payload .= "<param>\r\n".$p->serialize_class()."</param>\r\n";
755 }
Barry Mienydd671972010-10-04 16:33:58 +0200756
Derek Allard2067d1a2008-11-13 22:59:24 +0000757 $this->payload .= "</params>\r\n</methodCall>\r\n";
758 }
Barry Mienydd671972010-10-04 16:33:58 +0200759
Andrey Andreevc8709832012-04-04 13:43:53 +0300760 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200761
Andrey Andreevc8709832012-04-04 13:43:53 +0300762 /**
763 * Parse External XML-RPC Server's Response
764 *
765 * @param resource
766 * @return object
767 */
Andrey Andreeva30faf92011-12-25 18:15:34 +0200768 public function parseResponse($fp)
Derek Allard2067d1a2008-11-13 22:59:24 +0000769 {
770 $data = '';
Barry Mienydd671972010-10-04 16:33:58 +0200771
Pascal Kriete14287f32011-02-14 13:39:34 -0500772 while ($datum = fread($fp, 4096))
Derek Allard2067d1a2008-11-13 22:59:24 +0000773 {
774 $data .= $datum;
775 }
Barry Mienydd671972010-10-04 16:33:58 +0200776
Andrey Andreevc8709832012-04-04 13:43:53 +0300777 // Display HTTP content for debugging
Derek Allard2067d1a2008-11-13 22:59:24 +0000778 if ($this->debug === TRUE)
779 {
Andrey Andreeva30faf92011-12-25 18:15:34 +0200780 echo "<pre>---DATA---\n".htmlspecialchars($data)."\n---END DATA---\n\n</pre>";
Derek Allard2067d1a2008-11-13 22:59:24 +0000781 }
Barry Mienydd671972010-10-04 16:33:58 +0200782
Andrey Andreevc8709832012-04-04 13:43:53 +0300783 // Check for data
Andrey Andreeva30faf92011-12-25 18:15:34 +0200784 if ($data === '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000785 {
786 error_log($this->xmlrpcstr['no_data']);
Andrey Andreevc8709832012-04-04 13:43:53 +0300787 return new XML_RPC_Response(0, $this->xmlrpcerr['no_data'], $this->xmlrpcstr['no_data']);
Derek Allard2067d1a2008-11-13 22:59:24 +0000788 }
Barry Mienydd671972010-10-04 16:33:58 +0200789
Andrey Andreevc8709832012-04-04 13:43:53 +0300790 // Check for HTTP 200 Response
Andrey Andreev3dad2e72012-06-14 15:10:56 +0300791 if (strpos($data, 'HTTP') === 0 && ! preg_match('/^HTTP\/[0-9\.]+ 200 /', $data))
Derek Allard2067d1a2008-11-13 22:59:24 +0000792 {
Andrey Andreevc8709832012-04-04 13:43:53 +0300793 $errstr = substr($data, 0, strpos($data, "\n")-1);
794 return new XML_RPC_Response(0, $this->xmlrpcerr['http_error'], $this->xmlrpcstr['http_error'].' ('.$errstr.')');
Derek Allard2067d1a2008-11-13 22:59:24 +0000795 }
Barry Mienydd671972010-10-04 16:33:58 +0200796
Derek Allard2067d1a2008-11-13 22:59:24 +0000797 //-------------------------------------
Derek Jones37f4b9c2011-07-01 17:56:50 -0500798 // Create and Set Up XML Parser
Derek Allard2067d1a2008-11-13 22:59:24 +0000799 //-------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200800
Derek Allard2067d1a2008-11-13 22:59:24 +0000801 $parser = xml_parser_create($this->xmlrpc_defencoding);
802
Andrey Andreeva30faf92011-12-25 18:15:34 +0200803 $this->xh[$parser] = array(
Andrey Andreevc8709832012-04-04 13:43:53 +0300804 'isf' => 0,
805 'ac' => '',
806 'headers' => array(),
807 'stack' => array(),
808 'valuestack' => array(),
809 'isf_reason' => 0
Andrey Andreeva30faf92011-12-25 18:15:34 +0200810 );
Derek Allard2067d1a2008-11-13 22:59:24 +0000811
812 xml_set_object($parser, $this);
Andrey Andreevc8709832012-04-04 13:43:53 +0300813 xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, TRUE);
Derek Allard2067d1a2008-11-13 22:59:24 +0000814 xml_set_element_handler($parser, 'open_tag', 'closing_tag');
815 xml_set_character_data_handler($parser, 'character_data');
816 //xml_set_default_handler($parser, 'default_handler');
817
Andrey Andreevc8709832012-04-04 13:43:53 +0300818 // Get headers
Derek Allard2067d1a2008-11-13 22:59:24 +0000819 $lines = explode("\r\n", $data);
820 while (($line = array_shift($lines)))
821 {
822 if (strlen($line) < 1)
823 {
824 break;
825 }
826 $this->xh[$parser]['headers'][] = $line;
827 }
828 $data = implode("\r\n", $lines);
Barry Mienydd671972010-10-04 16:33:58 +0200829
Andrey Andreevc8709832012-04-04 13:43:53 +0300830 // Parse XML data
Derek Jones33559102009-02-02 18:50:38 +0000831 if ( ! xml_parse($parser, $data, count($data)))
Derek Allard2067d1a2008-11-13 22:59:24 +0000832 {
833 $errstr = sprintf('XML error: %s at line %d',
Andrey Andreevc8709832012-04-04 13:43:53 +0300834 xml_error_string(xml_get_error_code($parser)),
835 xml_get_current_line_number($parser));
Derek Allard2067d1a2008-11-13 22:59:24 +0000836 //error_log($errstr);
837 $r = new XML_RPC_Response(0, $this->xmlrpcerr['invalid_return'], $this->xmlrpcstr['invalid_return']);
838 xml_parser_free($parser);
839 return $r;
840 }
841 xml_parser_free($parser);
Barry Mienydd671972010-10-04 16:33:58 +0200842
Andrey Andreevc8709832012-04-04 13:43:53 +0300843 // Got ourselves some badness, it seems
Derek Allard2067d1a2008-11-13 22:59:24 +0000844 if ($this->xh[$parser]['isf'] > 1)
845 {
846 if ($this->debug === TRUE)
847 {
Andrey Andreeva30faf92011-12-25 18:15:34 +0200848 echo "---Invalid Return---\n".$this->xh[$parser]['isf_reason']."---Invalid Return---\n\n";
Derek Allard2067d1a2008-11-13 22:59:24 +0000849 }
Barry Mienydd671972010-10-04 16:33:58 +0200850
Andrey Andreevc8709832012-04-04 13:43:53 +0300851 return new XML_RPC_Response(0, $this->xmlrpcerr['invalid_return'], $this->xmlrpcstr['invalid_return'].' '.$this->xh[$parser]['isf_reason']);
Derek Allard2067d1a2008-11-13 22:59:24 +0000852 }
853 elseif ( ! is_object($this->xh[$parser]['value']))
854 {
Andrey Andreevc8709832012-04-04 13:43:53 +0300855 return new XML_RPC_Response(0, $this->xmlrpcerr['invalid_return'], $this->xmlrpcstr['invalid_return'].' '.$this->xh[$parser]['isf_reason']);
Derek Allard2067d1a2008-11-13 22:59:24 +0000856 }
Barry Mienydd671972010-10-04 16:33:58 +0200857
Andrey Andreevc8709832012-04-04 13:43:53 +0300858 // Display XML content for debugging
Derek Allard2067d1a2008-11-13 22:59:24 +0000859 if ($this->debug === TRUE)
860 {
Andrey Andreev8f50b6b2012-03-28 14:12:09 +0300861 echo '<pre>';
Barry Mienydd671972010-10-04 16:33:58 +0200862
Derek Allard2067d1a2008-11-13 22:59:24 +0000863 if (count($this->xh[$parser]['headers'] > 0))
864 {
865 echo "---HEADERS---\n";
866 foreach ($this->xh[$parser]['headers'] as $header)
867 {
Andrey Andreev8f50b6b2012-03-28 14:12:09 +0300868 echo $header."\n";
Derek Allard2067d1a2008-11-13 22:59:24 +0000869 }
870 echo "---END HEADERS---\n\n";
871 }
Barry Mienydd671972010-10-04 16:33:58 +0200872
Andrey Andreeva30faf92011-12-25 18:15:34 +0200873 echo "---DATA---\n".htmlspecialchars($data)."\n---END DATA---\n\n---PARSED---\n";
Derek Allard2067d1a2008-11-13 22:59:24 +0000874 var_dump($this->xh[$parser]['value']);
875 echo "\n---END PARSED---</pre>";
876 }
Barry Mienydd671972010-10-04 16:33:58 +0200877
Andrey Andreevc8709832012-04-04 13:43:53 +0300878 // Send response
Derek Allard2067d1a2008-11-13 22:59:24 +0000879 $v = $this->xh[$parser]['value'];
Derek Allard2067d1a2008-11-13 22:59:24 +0000880 if ($this->xh[$parser]['isf'])
881 {
882 $errno_v = $v->me['struct']['faultCode'];
883 $errstr_v = $v->me['struct']['faultString'];
884 $errno = $errno_v->scalarval();
885
Alex Bilbied261b1e2012-06-02 11:12:16 +0100886 if ($errno === 0)
Derek Allard2067d1a2008-11-13 22:59:24 +0000887 {
888 // FAULT returned, errno needs to reflect that
889 $errno = -1;
890 }
891
892 $r = new XML_RPC_Response($v, $errno, $errstr_v->scalarval());
893 }
894 else
895 {
896 $r = new XML_RPC_Response($v);
897 }
898
899 $r->headers = $this->xh[$parser]['headers'];
900 return $r;
901 }
Barry Mienydd671972010-10-04 16:33:58 +0200902
Andrey Andreevc8709832012-04-04 13:43:53 +0300903 // --------------------------------------------------------------------
904
Derek Allard2067d1a2008-11-13 22:59:24 +0000905 // ------------------------------------
Derek Jones37f4b9c2011-07-01 17:56:50 -0500906 // Begin Return Message Parsing section
Derek Allard2067d1a2008-11-13 22:59:24 +0000907 // ------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200908
Derek Allard2067d1a2008-11-13 22:59:24 +0000909 // quick explanation of components:
Derek Jones37f4b9c2011-07-01 17:56:50 -0500910 // ac - used to accumulate values
911 // isf - used to indicate a fault
912 // lv - used to indicate "looking for a value": implements
Derek Allard2067d1a2008-11-13 22:59:24 +0000913 // the logic to allow values with no types to be strings
Derek Jones37f4b9c2011-07-01 17:56:50 -0500914 // params - used to store parameters in method calls
915 // method - used to store method name
Derek Allard2067d1a2008-11-13 22:59:24 +0000916 // stack - array with parent tree of the xml element,
917 // used to validate the nesting of elements
918
Andrey Andreevc8709832012-04-04 13:43:53 +0300919 // --------------------------------------------------------------------
Derek Allard2067d1a2008-11-13 22:59:24 +0000920
Andrey Andreevc8709832012-04-04 13:43:53 +0300921 /**
922 * Start Element Handler
923 *
924 * @param string
925 * @param string
926 * @return void
927 */
928 public function open_tag($the_parser, $name)
Derek Allard2067d1a2008-11-13 22:59:24 +0000929 {
930 // If invalid nesting, then return
931 if ($this->xh[$the_parser]['isf'] > 1) return;
Barry Mienydd671972010-10-04 16:33:58 +0200932
Derek Allard2067d1a2008-11-13 22:59:24 +0000933 // Evaluate and check for correct nesting of XML elements
Alex Bilbied261b1e2012-06-02 11:12:16 +0100934 if (count($this->xh[$the_parser]['stack']) === 0)
Derek Allard2067d1a2008-11-13 22:59:24 +0000935 {
Alex Bilbied261b1e2012-06-02 11:12:16 +0100936 if ($name !== 'METHODRESPONSE' && $name !== 'METHODCALL')
Derek Allard2067d1a2008-11-13 22:59:24 +0000937 {
938 $this->xh[$the_parser]['isf'] = 2;
939 $this->xh[$the_parser]['isf_reason'] = 'Top level XML-RPC element is missing';
940 return;
941 }
942 }
Andrey Andreevc8709832012-04-04 13:43:53 +0300943 // not top level element: see if parent is OK
944 elseif ( ! in_array($this->xh[$the_parser]['stack'][0], $this->valid_parents[$name], TRUE))
Derek Allard2067d1a2008-11-13 22:59:24 +0000945 {
Andrey Andreevc8709832012-04-04 13:43:53 +0300946 $this->xh[$the_parser]['isf'] = 2;
947 $this->xh[$the_parser]['isf_reason'] = 'XML-RPC element $name cannot be child of '.$this->xh[$the_parser]['stack'][0];
948 return;
Derek Allard2067d1a2008-11-13 22:59:24 +0000949 }
Barry Mienydd671972010-10-04 16:33:58 +0200950
Andrey Andreevc8709832012-04-04 13:43:53 +0300951 switch ($name)
Derek Allard2067d1a2008-11-13 22:59:24 +0000952 {
953 case 'STRUCT':
954 case 'ARRAY':
955 // Creates array for child elements
Andrey Andreev8f50b6b2012-03-28 14:12:09 +0300956 $cur_val = array('value' => array(), 'type' => $name);
Derek Allard2067d1a2008-11-13 22:59:24 +0000957 array_unshift($this->xh[$the_parser]['valuestack'], $cur_val);
Andrey Andreevc8709832012-04-04 13:43:53 +0300958 break;
Derek Allard2067d1a2008-11-13 22:59:24 +0000959 case 'METHODNAME':
960 case 'NAME':
961 $this->xh[$the_parser]['ac'] = '';
Andrey Andreevc8709832012-04-04 13:43:53 +0300962 break;
Derek Allard2067d1a2008-11-13 22:59:24 +0000963 case 'FAULT':
964 $this->xh[$the_parser]['isf'] = 1;
Andrey Andreevc8709832012-04-04 13:43:53 +0300965 break;
Derek Allard2067d1a2008-11-13 22:59:24 +0000966 case 'PARAM':
Pascal Kriete8761ef52011-02-14 13:13:52 -0500967 $this->xh[$the_parser]['value'] = NULL;
Andrey Andreevc8709832012-04-04 13:43:53 +0300968 break;
Derek Allard2067d1a2008-11-13 22:59:24 +0000969 case 'VALUE':
970 $this->xh[$the_parser]['vt'] = 'value';
971 $this->xh[$the_parser]['ac'] = '';
972 $this->xh[$the_parser]['lv'] = 1;
Andrey Andreevc8709832012-04-04 13:43:53 +0300973 break;
Derek Allard2067d1a2008-11-13 22:59:24 +0000974 case 'I4':
975 case 'INT':
976 case 'STRING':
977 case 'BOOLEAN':
978 case 'DOUBLE':
979 case 'DATETIME.ISO8601':
980 case 'BASE64':
Alex Bilbied261b1e2012-06-02 11:12:16 +0100981 if ($this->xh[$the_parser]['vt'] !== 'value')
Derek Allard2067d1a2008-11-13 22:59:24 +0000982 {
983 //two data elements inside a value: an error occurred!
984 $this->xh[$the_parser]['isf'] = 2;
Andrey Andreevc8709832012-04-04 13:43:53 +0300985 $this->xh[$the_parser]['isf_reason'] = "'Twas a ".$name.' element following a '
986 .$this->xh[$the_parser]['vt'].' element inside a single value';
Derek Allard2067d1a2008-11-13 22:59:24 +0000987 return;
988 }
Barry Mienydd671972010-10-04 16:33:58 +0200989
Derek Allard2067d1a2008-11-13 22:59:24 +0000990 $this->xh[$the_parser]['ac'] = '';
Andrey Andreevc8709832012-04-04 13:43:53 +0300991 break;
Derek Allard2067d1a2008-11-13 22:59:24 +0000992 case 'MEMBER':
993 // Set name of <member> to nothing to prevent errors later if no <name> is found
994 $this->xh[$the_parser]['valuestack'][0]['name'] = '';
Barry Mienydd671972010-10-04 16:33:58 +0200995
Derek Allard2067d1a2008-11-13 22:59:24 +0000996 // Set NULL value to check to see if value passed for this param/member
Pascal Kriete8761ef52011-02-14 13:13:52 -0500997 $this->xh[$the_parser]['value'] = NULL;
Andrey Andreevc8709832012-04-04 13:43:53 +0300998 break;
Derek Allard2067d1a2008-11-13 22:59:24 +0000999 case 'DATA':
1000 case 'METHODCALL':
1001 case 'METHODRESPONSE':
1002 case 'PARAMS':
1003 // valid elements that add little to processing
Andrey Andreevc8709832012-04-04 13:43:53 +03001004 break;
Derek Allard2067d1a2008-11-13 22:59:24 +00001005 default:
1006 /// An Invalid Element is Found, so we have trouble
1007 $this->xh[$the_parser]['isf'] = 2;
Andrey Andreevc8709832012-04-04 13:43:53 +03001008 $this->xh[$the_parser]['isf_reason'] = 'Invalid XML-RPC element found: '.$name;
1009 break;
Derek Allard2067d1a2008-11-13 22:59:24 +00001010 }
Barry Mienydd671972010-10-04 16:33:58 +02001011
Derek Allard2067d1a2008-11-13 22:59:24 +00001012 // Add current element name to stack, to allow validation of nesting
1013 array_unshift($this->xh[$the_parser]['stack'], $name);
1014
Alex Bilbied261b1e2012-06-02 11:12:16 +01001015 $name === 'VALUE' OR $this->xh[$the_parser]['lv'] = 0;
Derek Allard2067d1a2008-11-13 22:59:24 +00001016 }
Derek Allard2067d1a2008-11-13 22:59:24 +00001017
Andrey Andreevc8709832012-04-04 13:43:53 +03001018 // --------------------------------------------------------------------
Derek Allard2067d1a2008-11-13 22:59:24 +00001019
Andrey Andreevc8709832012-04-04 13:43:53 +03001020 /**
1021 * End Element Handler
1022 *
1023 * @param string
1024 * @param string
1025 * @return void
1026 */
Andrey Andreeva30faf92011-12-25 18:15:34 +02001027 public function closing_tag($the_parser, $name)
Derek Allard2067d1a2008-11-13 22:59:24 +00001028 {
1029 if ($this->xh[$the_parser]['isf'] > 1) return;
Barry Mienydd671972010-10-04 16:33:58 +02001030
Derek Allard2067d1a2008-11-13 22:59:24 +00001031 // Remove current element from stack and set variable
1032 // NOTE: If the XML validates, then we do not have to worry about
Andrey Andreevc8709832012-04-04 13:43:53 +03001033 // the opening and closing of elements. Nesting is checked on the opening
Derek Allard2067d1a2008-11-13 22:59:24 +00001034 // tag so we be safe there as well.
Barry Mienydd671972010-10-04 16:33:58 +02001035
Derek Allard2067d1a2008-11-13 22:59:24 +00001036 $curr_elem = array_shift($this->xh[$the_parser]['stack']);
Barry Mienydd671972010-10-04 16:33:58 +02001037
Andrey Andreevc8709832012-04-04 13:43:53 +03001038 switch ($name)
Derek Allard2067d1a2008-11-13 22:59:24 +00001039 {
1040 case 'STRUCT':
1041 case 'ARRAY':
1042 $cur_val = array_shift($this->xh[$the_parser]['valuestack']);
Andrey Andreevc8709832012-04-04 13:43:53 +03001043 $this->xh[$the_parser]['value'] = isset($cur_val['values']) ? $cur_val['values'] : array();
Derek Allard2067d1a2008-11-13 22:59:24 +00001044 $this->xh[$the_parser]['vt'] = strtolower($name);
Andrey Andreevc8709832012-04-04 13:43:53 +03001045 break;
Derek Allard2067d1a2008-11-13 22:59:24 +00001046 case 'NAME':
1047 $this->xh[$the_parser]['valuestack'][0]['name'] = $this->xh[$the_parser]['ac'];
Andrey Andreevc8709832012-04-04 13:43:53 +03001048 break;
Derek Allard2067d1a2008-11-13 22:59:24 +00001049 case 'BOOLEAN':
1050 case 'I4':
1051 case 'INT':
1052 case 'STRING':
1053 case 'DOUBLE':
1054 case 'DATETIME.ISO8601':
1055 case 'BASE64':
1056 $this->xh[$the_parser]['vt'] = strtolower($name);
Barry Mienydd671972010-10-04 16:33:58 +02001057
Alex Bilbied261b1e2012-06-02 11:12:16 +01001058 if ($name === 'STRING')
Derek Allard2067d1a2008-11-13 22:59:24 +00001059 {
1060 $this->xh[$the_parser]['value'] = $this->xh[$the_parser]['ac'];
1061 }
Alex Bilbied261b1e2012-06-02 11:12:16 +01001062 elseif ($name === 'DATETIME.ISO8601')
Derek Allard2067d1a2008-11-13 22:59:24 +00001063 {
1064 $this->xh[$the_parser]['vt'] = $this->xmlrpcDateTime;
1065 $this->xh[$the_parser]['value'] = $this->xh[$the_parser]['ac'];
1066 }
Alex Bilbied261b1e2012-06-02 11:12:16 +01001067 elseif ($name === 'BASE64')
Derek Allard2067d1a2008-11-13 22:59:24 +00001068 {
1069 $this->xh[$the_parser]['value'] = base64_decode($this->xh[$the_parser]['ac']);
1070 }
Alex Bilbied261b1e2012-06-02 11:12:16 +01001071 elseif ($name === 'BOOLEAN')
Derek Allard2067d1a2008-11-13 22:59:24 +00001072 {
1073 // Translated BOOLEAN values to TRUE AND FALSE
Andrey Andreevc8709832012-04-04 13:43:53 +03001074 $this->xh[$the_parser]['value'] = (bool) $this->xh[$the_parser]['ac'];
Derek Allard2067d1a2008-11-13 22:59:24 +00001075 }
1076 elseif ($name=='DOUBLE')
1077 {
1078 // we have a DOUBLE
1079 // we must check that only 0123456789-.<space> are characters here
Andrey Andreevc8709832012-04-04 13:43:53 +03001080 $this->xh[$the_parser]['value'] = preg_match('/^[+-]?[eE0-9\t \.]+$/', $this->xh[$the_parser]['ac'])
1081 ? (float) $this->xh[$the_parser]['ac']
1082 : 'ERROR_NON_NUMERIC_FOUND';
Derek Allard2067d1a2008-11-13 22:59:24 +00001083 }
1084 else
1085 {
1086 // we have an I4/INT
1087 // we must check that only 0123456789-<space> are characters here
Andrey Andreevc8709832012-04-04 13:43:53 +03001088 $this->xh[$the_parser]['value'] = preg_match('/^[+-]?[0-9\t ]+$/', $this->xh[$the_parser]['ac'])
George Petsagourakis306b3782012-05-02 20:31:08 +03001089 ? (int) $this->xh[$the_parser]['ac']
Andrey Andreevc8709832012-04-04 13:43:53 +03001090 : 'ERROR_NON_NUMERIC_FOUND';
Derek Allard2067d1a2008-11-13 22:59:24 +00001091 }
1092 $this->xh[$the_parser]['ac'] = '';
1093 $this->xh[$the_parser]['lv'] = 3; // indicate we've found a value
Andrey Andreevc8709832012-04-04 13:43:53 +03001094 break;
Derek Allard2067d1a2008-11-13 22:59:24 +00001095 case 'VALUE':
1096 // This if() detects if no scalar was inside <VALUE></VALUE>
1097 if ($this->xh[$the_parser]['vt']=='value')
1098 {
1099 $this->xh[$the_parser]['value'] = $this->xh[$the_parser]['ac'];
1100 $this->xh[$the_parser]['vt'] = $this->xmlrpcString;
1101 }
Barry Mienydd671972010-10-04 16:33:58 +02001102
Derek Allard2067d1a2008-11-13 22:59:24 +00001103 // build the XML-RPC value out of the data received, and substitute it
1104 $temp = new XML_RPC_Values($this->xh[$the_parser]['value'], $this->xh[$the_parser]['vt']);
Barry Mienydd671972010-10-04 16:33:58 +02001105
Alex Bilbied261b1e2012-06-02 11:12:16 +01001106 if (count($this->xh[$the_parser]['valuestack']) && $this->xh[$the_parser]['valuestack'][0]['type'] === 'ARRAY')
Derek Allard2067d1a2008-11-13 22:59:24 +00001107 {
1108 // Array
1109 $this->xh[$the_parser]['valuestack'][0]['values'][] = $temp;
1110 }
1111 else
1112 {
1113 // Struct
1114 $this->xh[$the_parser]['value'] = $temp;
1115 }
Andrey Andreevc8709832012-04-04 13:43:53 +03001116 break;
Derek Allard2067d1a2008-11-13 22:59:24 +00001117 case 'MEMBER':
Andrey Andreevc8709832012-04-04 13:43:53 +03001118 $this->xh[$the_parser]['ac'] = '';
Barry Mienydd671972010-10-04 16:33:58 +02001119
Derek Allard2067d1a2008-11-13 22:59:24 +00001120 // If value add to array in the stack for the last element built
1121 if ($this->xh[$the_parser]['value'])
1122 {
1123 $this->xh[$the_parser]['valuestack'][0]['values'][$this->xh[$the_parser]['valuestack'][0]['name']] = $this->xh[$the_parser]['value'];
1124 }
Andrey Andreevc8709832012-04-04 13:43:53 +03001125 break;
Derek Allard2067d1a2008-11-13 22:59:24 +00001126 case 'DATA':
Andrey Andreevc8709832012-04-04 13:43:53 +03001127 $this->xh[$the_parser]['ac'] = '';
1128 break;
Derek Allard2067d1a2008-11-13 22:59:24 +00001129 case 'PARAM':
1130 if ($this->xh[$the_parser]['value'])
1131 {
1132 $this->xh[$the_parser]['params'][] = $this->xh[$the_parser]['value'];
1133 }
Andrey Andreevc8709832012-04-04 13:43:53 +03001134 break;
Derek Allard2067d1a2008-11-13 22:59:24 +00001135 case 'METHODNAME':
1136 $this->xh[$the_parser]['method'] = ltrim($this->xh[$the_parser]['ac']);
Andrey Andreevc8709832012-04-04 13:43:53 +03001137 break;
Derek Allard2067d1a2008-11-13 22:59:24 +00001138 case 'PARAMS':
1139 case 'FAULT':
1140 case 'METHODCALL':
1141 case 'METHORESPONSE':
1142 // We're all good kids with nuthin' to do
Andrey Andreevc8709832012-04-04 13:43:53 +03001143 break;
Derek Allard2067d1a2008-11-13 22:59:24 +00001144 default:
Andrey Andreevc8709832012-04-04 13:43:53 +03001145 // End of an Invalid Element. Taken care of during the opening tag though
1146 break;
Derek Allard2067d1a2008-11-13 22:59:24 +00001147 }
1148 }
1149
Andrey Andreevc8709832012-04-04 13:43:53 +03001150 // --------------------------------------------------------------------
Derek Allard2067d1a2008-11-13 22:59:24 +00001151
Andrey Andreevc8709832012-04-04 13:43:53 +03001152 /**
1153 * Parse character data
1154 *
1155 * @param string
1156 * @param string
1157 * @return void
1158 */
Andrey Andreeva30faf92011-12-25 18:15:34 +02001159 public function character_data($the_parser, $data)
Derek Allard2067d1a2008-11-13 22:59:24 +00001160 {
1161 if ($this->xh[$the_parser]['isf'] > 1) return; // XML Fault found already
Barry Mienydd671972010-10-04 16:33:58 +02001162
Derek Allard2067d1a2008-11-13 22:59:24 +00001163 // If a value has not been found
Alex Bilbied261b1e2012-06-02 11:12:16 +01001164 if ($this->xh[$the_parser]['lv'] !== 3)
Derek Allard2067d1a2008-11-13 22:59:24 +00001165 {
Alex Bilbied261b1e2012-06-02 11:12:16 +01001166 if ($this->xh[$the_parser]['lv'] === 1)
Derek Allard2067d1a2008-11-13 22:59:24 +00001167 {
1168 $this->xh[$the_parser]['lv'] = 2; // Found a value
1169 }
Barry Mienydd671972010-10-04 16:33:58 +02001170
Andrey Andreevc8709832012-04-04 13:43:53 +03001171 if ( ! isset($this->xh[$the_parser]['ac']))
Derek Allard2067d1a2008-11-13 22:59:24 +00001172 {
1173 $this->xh[$the_parser]['ac'] = '';
1174 }
Barry Mienydd671972010-10-04 16:33:58 +02001175
Derek Allard2067d1a2008-11-13 22:59:24 +00001176 $this->xh[$the_parser]['ac'] .= $data;
1177 }
1178 }
Barry Mienydd671972010-10-04 16:33:58 +02001179
Andrey Andreevc8709832012-04-04 13:43:53 +03001180 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +02001181
Andrey Andreevc8709832012-04-04 13:43:53 +03001182 /**
1183 * Add parameter
1184 *
1185 * @param mixed
1186 * @return void
1187 */
Andrey Andreeva30faf92011-12-25 18:15:34 +02001188 public function addParam($par)
1189 {
1190 $this->params[] = $par;
1191 }
Barry Mienydd671972010-10-04 16:33:58 +02001192
Andrey Andreevc8709832012-04-04 13:43:53 +03001193 // --------------------------------------------------------------------
1194
1195 /**
1196 * Output parameters
1197 *
1198 * @param array
1199 * @return array
1200 */
Andrey Andreeva30faf92011-12-25 18:15:34 +02001201 public function output_parameters($array = FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +00001202 {
Barry Mienydd671972010-10-04 16:33:58 +02001203 $CI =& get_instance();
Andrey Andreeva30faf92011-12-25 18:15:34 +02001204
1205 if (is_array($array))
Derek Allard2067d1a2008-11-13 22:59:24 +00001206 {
1207 while (list($key) = each($array))
1208 {
1209 if (is_array($array[$key]))
1210 {
1211 $array[$key] = $this->output_parameters($array[$key]);
1212 }
1213 else
1214 {
Derek Jonesa9647e82010-03-02 22:59:07 -06001215 // 'bits' is for the MetaWeblog API image bits
1216 // @todo - this needs to be made more general purpose
Alex Bilbied261b1e2012-06-02 11:12:16 +01001217 $array[$key] = ($key === 'bits' OR $this->xss_clean === FALSE) ? $array[$key] : $CI->security->xss_clean($array[$key]);
Derek Allard2067d1a2008-11-13 22:59:24 +00001218 }
1219 }
Barry Mienydd671972010-10-04 16:33:58 +02001220
Andrey Andreevc8709832012-04-04 13:43:53 +03001221 return $array;
Derek Allard2067d1a2008-11-13 22:59:24 +00001222 }
Andrey Andreevc8709832012-04-04 13:43:53 +03001223
1224 $parameters = array();
1225
1226 for ($i = 0, $c = count($this->params); $i < $c; $i++)
Derek Allard2067d1a2008-11-13 22:59:24 +00001227 {
Andrey Andreevc8709832012-04-04 13:43:53 +03001228 $a_param = $this->decode_message($this->params[$i]);
Barry Mienydd671972010-10-04 16:33:58 +02001229
Andrey Andreevc8709832012-04-04 13:43:53 +03001230 if (is_array($a_param))
Derek Allard2067d1a2008-11-13 22:59:24 +00001231 {
Andrey Andreevc8709832012-04-04 13:43:53 +03001232 $parameters[] = $this->output_parameters($a_param);
1233 }
1234 else
1235 {
1236 $parameters[] = ($this->xss_clean) ? $CI->security->xss_clean($a_param) : $a_param;
Barry Mienydd671972010-10-04 16:33:58 +02001237 }
Derek Allard2067d1a2008-11-13 22:59:24 +00001238 }
Barry Mienydd671972010-10-04 16:33:58 +02001239
Derek Allard2067d1a2008-11-13 22:59:24 +00001240 return $parameters;
1241 }
Barry Mienydd671972010-10-04 16:33:58 +02001242
Andrey Andreevc8709832012-04-04 13:43:53 +03001243 // --------------------------------------------------------------------
1244
1245 /**
1246 * Decode message
1247 *
1248 * @param object
1249 * @return mixed
1250 */
Andrey Andreeva30faf92011-12-25 18:15:34 +02001251 public function decode_message($param)
Derek Allard2067d1a2008-11-13 22:59:24 +00001252 {
1253 $kind = $param->kindOf();
1254
Alex Bilbied261b1e2012-06-02 11:12:16 +01001255 if ($kind === 'scalar')
Derek Allard2067d1a2008-11-13 22:59:24 +00001256 {
1257 return $param->scalarval();
1258 }
Alex Bilbied261b1e2012-06-02 11:12:16 +01001259 elseif ($kind === 'array')
Derek Allard2067d1a2008-11-13 22:59:24 +00001260 {
1261 reset($param->me);
Andrey Andreevadc11752011-12-30 14:46:08 +02001262 $b = current($param->me);
Derek Allard2067d1a2008-11-13 22:59:24 +00001263 $arr = array();
1264
Andrey Andreevc8709832012-04-04 13:43:53 +03001265 for ($i = 0, $c = count($b); $i < $c; $i++)
Derek Allard2067d1a2008-11-13 22:59:24 +00001266 {
1267 $arr[] = $this->decode_message($param->me['array'][$i]);
1268 }
Barry Mienydd671972010-10-04 16:33:58 +02001269
Derek Allard2067d1a2008-11-13 22:59:24 +00001270 return $arr;
1271 }
Alex Bilbied261b1e2012-06-02 11:12:16 +01001272 elseif ($kind === 'struct')
Derek Allard2067d1a2008-11-13 22:59:24 +00001273 {
1274 reset($param->me['struct']);
Derek Allard2067d1a2008-11-13 22:59:24 +00001275 $arr = array();
1276
Pascal Kriete14287f32011-02-14 13:39:34 -05001277 while (list($key,$value) = each($param->me['struct']))
Derek Allard2067d1a2008-11-13 22:59:24 +00001278 {
1279 $arr[$key] = $this->decode_message($value);
1280 }
Barry Mienydd671972010-10-04 16:33:58 +02001281
Derek Allard2067d1a2008-11-13 22:59:24 +00001282 return $arr;
1283 }
1284 }
Barry Mienydd671972010-10-04 16:33:58 +02001285
Andrey Andreevc8709832012-04-04 13:43:53 +03001286} // END XML_RPC_Message Class
Derek Allard2067d1a2008-11-13 22:59:24 +00001287
1288/**
1289 * XML-RPC Values class
1290 *
1291 * @category XML-RPC
Derek Jonesf4a4bd82011-10-20 12:18:42 -05001292 * @author EllisLab Dev Team
Derek Allard2067d1a2008-11-13 22:59:24 +00001293 * @link http://codeigniter.com/user_guide/libraries/xmlrpc.html
1294 */
1295class XML_RPC_Values extends CI_Xmlrpc
1296{
Andrey Andreeva30faf92011-12-25 18:15:34 +02001297 public $me = array();
1298 public $mytype = 0;
Derek Allard2067d1a2008-11-13 22:59:24 +00001299
Andrey Andreevc8709832012-04-04 13:43:53 +03001300 /**
1301 * Constructor
1302 *
1303 * @param mixed
1304 * @param string
1305 * @return void
1306 */
Andrey Andreeva30faf92011-12-25 18:15:34 +02001307 public function __construct($val = -1, $type = '')
Barry Mienydd671972010-10-04 16:33:58 +02001308 {
Greg Akera9263282010-11-10 15:26:43 -06001309 parent::__construct();
Barry Mienydd671972010-10-04 16:33:58 +02001310
Alex Bilbied261b1e2012-06-02 11:12:16 +01001311 if ($val !== -1 OR $type !== '')
Derek Allard2067d1a2008-11-13 22:59:24 +00001312 {
Alex Bilbied261b1e2012-06-02 11:12:16 +01001313 $type = $type === '' ? 'string' : $type;
Barry Mienydd671972010-10-04 16:33:58 +02001314
Alex Bilbied261b1e2012-06-02 11:12:16 +01001315 if ($this->xmlrpcTypes[$type] === 1)
Derek Allard2067d1a2008-11-13 22:59:24 +00001316 {
1317 $this->addScalar($val,$type);
1318 }
Alex Bilbied261b1e2012-06-02 11:12:16 +01001319 elseif ($this->xmlrpcTypes[$type] === 2)
Derek Allard2067d1a2008-11-13 22:59:24 +00001320 {
1321 $this->addArray($val);
1322 }
Alex Bilbied261b1e2012-06-02 11:12:16 +01001323 elseif ($this->xmlrpcTypes[$type] === 3)
Derek Allard2067d1a2008-11-13 22:59:24 +00001324 {
1325 $this->addStruct($val);
1326 }
1327 }
1328 }
1329
Andrey Andreevc8709832012-04-04 13:43:53 +03001330 // --------------------------------------------------------------------
1331
1332 /**
1333 * Add scalar value
1334 *
1335 * @param scalar
1336 * @param string
1337 * @return int
1338 */
Andrey Andreeva30faf92011-12-25 18:15:34 +02001339 public function addScalar($val, $type = 'string')
Derek Allard2067d1a2008-11-13 22:59:24 +00001340 {
1341 $typeof = $this->xmlrpcTypes[$type];
Barry Mienydd671972010-10-04 16:33:58 +02001342
Alex Bilbied261b1e2012-06-02 11:12:16 +01001343 if ($this->mytype === 1)
Derek Allard2067d1a2008-11-13 22:59:24 +00001344 {
1345 echo '<strong>XML_RPC_Values</strong>: scalar can have only one value<br />';
1346 return 0;
1347 }
Barry Mienydd671972010-10-04 16:33:58 +02001348
Alex Bilbied261b1e2012-06-02 11:12:16 +01001349 if ($typeof !== 1)
Derek Allard2067d1a2008-11-13 22:59:24 +00001350 {
1351 echo '<strong>XML_RPC_Values</strong>: not a scalar type (${typeof})<br />';
1352 return 0;
1353 }
1354
Alex Bilbied261b1e2012-06-02 11:12:16 +01001355 if ($type === $this->xmlrpcBoolean)
Derek Allard2067d1a2008-11-13 22:59:24 +00001356 {
Andrey Andreevc8709832012-04-04 13:43:53 +03001357 $val = (int) (strcasecmp($val,'true') === 0 OR $val === 1 OR ($val === TRUE && strcasecmp($val, 'false')));
Derek Allard2067d1a2008-11-13 22:59:24 +00001358 }
1359
Alex Bilbied261b1e2012-06-02 11:12:16 +01001360 if ($this->mytype === 2)
Derek Allard2067d1a2008-11-13 22:59:24 +00001361 {
1362 // adding to an array here
1363 $ar = $this->me['array'];
1364 $ar[] = new XML_RPC_Values($val, $type);
1365 $this->me['array'] = $ar;
1366 }
1367 else
1368 {
1369 // a scalar, so set the value and remember we're scalar
1370 $this->me[$type] = $val;
1371 $this->mytype = $typeof;
1372 }
Andrey Andreevc8709832012-04-04 13:43:53 +03001373
Derek Allard2067d1a2008-11-13 22:59:24 +00001374 return 1;
1375 }
1376
Andrey Andreevc8709832012-04-04 13:43:53 +03001377 // --------------------------------------------------------------------
1378
1379 /**
1380 * Add array value
1381 *
1382 * @param array
1383 * @return int
1384 */
Andrey Andreeva30faf92011-12-25 18:15:34 +02001385 public function addArray($vals)
Derek Allard2067d1a2008-11-13 22:59:24 +00001386 {
Alex Bilbied261b1e2012-06-02 11:12:16 +01001387 if ($this->mytype !== 0)
Derek Allard2067d1a2008-11-13 22:59:24 +00001388 {
1389 echo '<strong>XML_RPC_Values</strong>: already initialized as a [' . $this->kindOf() . ']<br />';
1390 return 0;
1391 }
1392
1393 $this->mytype = $this->xmlrpcTypes['array'];
1394 $this->me['array'] = $vals;
1395 return 1;
1396 }
1397
Andrey Andreevc8709832012-04-04 13:43:53 +03001398 // --------------------------------------------------------------------
1399
1400 /**
1401 * Add struct value
1402 *
1403 * @param object
1404 * @return int
1405 */
Andrey Andreeva30faf92011-12-25 18:15:34 +02001406 public function addStruct($vals)
Derek Allard2067d1a2008-11-13 22:59:24 +00001407 {
Alex Bilbied261b1e2012-06-02 11:12:16 +01001408 if ($this->mytype !== 0)
Derek Allard2067d1a2008-11-13 22:59:24 +00001409 {
1410 echo '<strong>XML_RPC_Values</strong>: already initialized as a [' . $this->kindOf() . ']<br />';
1411 return 0;
1412 }
1413 $this->mytype = $this->xmlrpcTypes['struct'];
1414 $this->me['struct'] = $vals;
1415 return 1;
1416 }
1417
Andrey Andreevc8709832012-04-04 13:43:53 +03001418 // --------------------------------------------------------------------
1419
1420 /**
1421 * Get value type
1422 *
1423 * @return string
1424 */
Andrey Andreeva30faf92011-12-25 18:15:34 +02001425 public function kindOf()
Derek Allard2067d1a2008-11-13 22:59:24 +00001426 {
Andrey Andreevc8709832012-04-04 13:43:53 +03001427 switch ($this->mytype)
Derek Allard2067d1a2008-11-13 22:59:24 +00001428 {
Andrey Andreevc8709832012-04-04 13:43:53 +03001429 case 3: return 'struct';
1430 case 2: return 'array';
1431 case 1: return 'scalar';
1432 default: return 'undef';
Derek Allard2067d1a2008-11-13 22:59:24 +00001433 }
1434 }
1435
Andrey Andreevc8709832012-04-04 13:43:53 +03001436 // --------------------------------------------------------------------
1437
1438 /**
1439 * Serialize data
1440 *
1441 * @param string
1442 * @param mixed
1443 */
Andrey Andreeva30faf92011-12-25 18:15:34 +02001444 public function serializedata($typ, $val)
Derek Allard2067d1a2008-11-13 22:59:24 +00001445 {
1446 $rs = '';
Derek Jonesa9647e82010-03-02 22:59:07 -06001447
Andrey Andreevc8709832012-04-04 13:43:53 +03001448 switch ($this->xmlrpcTypes[$typ])
Derek Allard2067d1a2008-11-13 22:59:24 +00001449 {
1450 case 3:
1451 // struct
1452 $rs .= "<struct>\n";
1453 reset($val);
Pascal Kriete14287f32011-02-14 13:39:34 -05001454 while (list($key2, $val2) = each($val))
Derek Allard2067d1a2008-11-13 22:59:24 +00001455 {
Andrey Andreeva30faf92011-12-25 18:15:34 +02001456 $rs .= "<member>\n<name>{$key2}</name>\n".$this->serializeval($val2)."</member>\n";
Derek Allard2067d1a2008-11-13 22:59:24 +00001457 }
1458 $rs .= '</struct>';
Andrey Andreevc8709832012-04-04 13:43:53 +03001459 break;
Derek Allard2067d1a2008-11-13 22:59:24 +00001460 case 2:
1461 // array
1462 $rs .= "<array>\n<data>\n";
Andrey Andreevc8709832012-04-04 13:43:53 +03001463 for ($i = 0, $c = count($val); $i < $c; $i++)
Derek Allard2067d1a2008-11-13 22:59:24 +00001464 {
1465 $rs .= $this->serializeval($val[$i]);
1466 }
Andrey Andreeva30faf92011-12-25 18:15:34 +02001467 $rs .= "</data>\n</array>\n";
Derek Allard2067d1a2008-11-13 22:59:24 +00001468 break;
1469 case 1:
1470 // others
1471 switch ($typ)
1472 {
1473 case $this->xmlrpcBase64:
Andrey Andreevc8709832012-04-04 13:43:53 +03001474 $rs .= '<'.$typ.'>'.base64_encode( (string) $val).'</'.$typ.">\n";
1475 break;
Derek Allard2067d1a2008-11-13 22:59:24 +00001476 case $this->xmlrpcBoolean:
Andrey Andreevc8709832012-04-04 13:43:53 +03001477 $rs .= '<'.$typ.'>'.( (bool) $val ? '1' : '0').'</'.$typ.">\n";
1478 break;
Derek Allard2067d1a2008-11-13 22:59:24 +00001479 case $this->xmlrpcString:
Andrey Andreevc8709832012-04-04 13:43:53 +03001480 $rs .= '<'.$typ.'>'.htmlspecialchars( (string) $val).'</'.$typ.">\n";
1481 break;
Derek Allard2067d1a2008-11-13 22:59:24 +00001482 default:
Andrey Andreevc8709832012-04-04 13:43:53 +03001483 $rs .= '<'.$typ.'>'.$val.'</'.$typ.">\n";
1484 break;
Derek Allard2067d1a2008-11-13 22:59:24 +00001485 }
1486 default:
Andrey Andreevc8709832012-04-04 13:43:53 +03001487 break;
Derek Allard2067d1a2008-11-13 22:59:24 +00001488 }
Andrey Andreevc8709832012-04-04 13:43:53 +03001489
Derek Allard2067d1a2008-11-13 22:59:24 +00001490 return $rs;
1491 }
1492
Andrey Andreevc8709832012-04-04 13:43:53 +03001493 // --------------------------------------------------------------------
1494
1495 /**
1496 * Serialize class
1497 *
1498 * @return string
1499 */
Andrey Andreeva30faf92011-12-25 18:15:34 +02001500 public function serialize_class()
Derek Allard2067d1a2008-11-13 22:59:24 +00001501 {
1502 return $this->serializeval($this);
1503 }
1504
Andrey Andreevc8709832012-04-04 13:43:53 +03001505 // --------------------------------------------------------------------
1506
1507 /**
1508 * Serialize value
1509 *
1510 * @param object
1511 * @return string
1512 */
Andrey Andreeva30faf92011-12-25 18:15:34 +02001513 public function serializeval($o)
Derek Allard2067d1a2008-11-13 22:59:24 +00001514 {
1515 $ar = $o->me;
1516 reset($ar);
Barry Mienydd671972010-10-04 16:33:58 +02001517
Derek Allard2067d1a2008-11-13 22:59:24 +00001518 list($typ, $val) = each($ar);
Andrey Andreeva30faf92011-12-25 18:15:34 +02001519 return "<value>\n".$this->serializedata($typ, $val)."</value>\n";
Derek Allard2067d1a2008-11-13 22:59:24 +00001520 }
Barry Mienydd671972010-10-04 16:33:58 +02001521
Andrey Andreevc8709832012-04-04 13:43:53 +03001522 // --------------------------------------------------------------------
1523
1524 /**
1525 * Scalar value
1526 *
1527 * @return mixed
1528 */
Andrey Andreeva30faf92011-12-25 18:15:34 +02001529 public function scalarval()
Derek Allard2067d1a2008-11-13 22:59:24 +00001530 {
1531 reset($this->me);
Andrey Andreevadc11752011-12-30 14:46:08 +02001532 return current($this->me);
Derek Allard2067d1a2008-11-13 22:59:24 +00001533 }
1534
Andrey Andreevc8709832012-04-04 13:43:53 +03001535 // --------------------------------------------------------------------
Derek Allard2067d1a2008-11-13 22:59:24 +00001536
Andrey Andreevc8709832012-04-04 13:43:53 +03001537 /**
1538 * Encode time in ISO-8601 form.
1539 * Useful for sending time in XML-RPC
1540 *
1541 * @param int unix timestamp
1542 * @param bool
1543 * @return string
1544 */
1545 public function iso8601_encode($time, $utc = FALSE)
Barry Mienydd671972010-10-04 16:33:58 +02001546 {
Andrey Andreev62090152011-12-30 12:49:27 +02001547 return ($utc) ? strftime('%Y%m%dT%H:%i:%s', $time) : gmstrftime('%Y%m%dT%H:%i:%s', $time);
Derek Allard2067d1a2008-11-13 22:59:24 +00001548 }
Barry Mienydd671972010-10-04 16:33:58 +02001549
Andrey Andreevc8709832012-04-04 13:43:53 +03001550} // END XML_RPC_Values Class
Derek Allard2067d1a2008-11-13 22:59:24 +00001551
1552/* End of file Xmlrpc.php */
Andrey Andreev8f50b6b2012-03-28 14:12:09 +03001553/* Location: ./system/libraries/Xmlrpc.php */