blob: 0d25338557e19d609db085ce011598b520e7258c [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 */
Andrey Andreev8f50b6b2012-03-28 14:12:09 +0300177 public function server($url, $port = 80)
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
Derek Allard2067d1a2008-11-13 22:59:24 +0000193 $this->client = new XML_RPC_Client($path, $parts['host'], $port);
194 }
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 {
Andrey Andreeva30faf92011-12-25 18:15:34 +0200259 $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 {
Andrey Andreeva30faf92011-12-25 18:15:34 +0200280 if (is_array($value[0]) && ($value[1] == 'struct' OR $value[1] == 'array'))
281 {
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;
388 public $errno = '';
389 public $errstring = '';
390 public $timeout = 5;
391 public $no_multicall = FALSE;
Derek Allard2067d1a2008-11-13 22:59:24 +0000392
Andrey Andreevc8709832012-04-04 13:43:53 +0300393 /**
394 * Constructor
395 *
396 * @param string
397 * @param object
398 * @param int
399 * @return void
400 */
Andrey Andreev8f50b6b2012-03-28 14:12:09 +0300401 public function __construct($path, $server, $port = 80)
Derek Allard2067d1a2008-11-13 22:59:24 +0000402 {
Greg Akera9263282010-11-10 15:26:43 -0600403 parent::__construct();
Barry Mienydd671972010-10-04 16:33:58 +0200404
Derek Allard2067d1a2008-11-13 22:59:24 +0000405 $this->port = $port;
406 $this->server = $server;
407 $this->path = $path;
408 }
Barry Mienydd671972010-10-04 16:33:58 +0200409
Andrey Andreevc8709832012-04-04 13:43:53 +0300410 // --------------------------------------------------------------------
411
412 /**
413 * Send message
414 *
415 * @param mixed
416 * @return object
417 */
Andrey Andreeva30faf92011-12-25 18:15:34 +0200418 public function send($msg)
Derek Allard2067d1a2008-11-13 22:59:24 +0000419 {
420 if (is_array($msg))
421 {
422 // Multi-call disabled
Andrey Andreevc8709832012-04-04 13:43:53 +0300423 return new XML_RPC_Response(0, $this->xmlrpcerr['multicall_recursion'], $this->xmlrpcstr['multicall_recursion']);
Derek Allard2067d1a2008-11-13 22:59:24 +0000424 }
425
426 return $this->sendPayload($msg);
427 }
428
Andrey Andreevc8709832012-04-04 13:43:53 +0300429 // --------------------------------------------------------------------
430
431 /**
432 * Send payload
433 *
434 * @param object
435 * @return object
436 */
Andrey Andreeva30faf92011-12-25 18:15:34 +0200437 public function sendPayload($msg)
Barry Mienydd671972010-10-04 16:33:58 +0200438 {
George Petsagourakis306b3782012-05-02 20:31:08 +0300439 $fp = @fsockopen($this->server, $this->port,$this->errno, $this->errstring, $this->timeout);
Barry Mienydd671972010-10-04 16:33:58 +0200440
Derek Allard2067d1a2008-11-13 22:59:24 +0000441 if ( ! is_resource($fp))
442 {
443 error_log($this->xmlrpcstr['http_error']);
Andrey Andreevc8709832012-04-04 13:43:53 +0300444 return new XML_RPC_Response(0, $this->xmlrpcerr['http_error'], $this->xmlrpcstr['http_error']);
Derek Allard2067d1a2008-11-13 22:59:24 +0000445 }
Barry Mienydd671972010-10-04 16:33:58 +0200446
Pascal Kriete14287f32011-02-14 13:39:34 -0500447 if (empty($msg->payload))
Derek Allard2067d1a2008-11-13 22:59:24 +0000448 {
449 // $msg = XML_RPC_Messages
450 $msg->createPayload();
451 }
Barry Mienydd671972010-10-04 16:33:58 +0200452
Derek Allard2067d1a2008-11-13 22:59:24 +0000453 $r = "\r\n";
Andrey Andreev8f50b6b2012-03-28 14:12:09 +0300454 $op = 'POST '.$this->path.' HTTP/1.0'.$r
455 .'Host: '.$this->server.$r
456 .'Content-Type: text/xml'.$r
457 .'User-Agent: '.$this->xmlrpcName.$r
458 .'Content-Length: '.strlen($msg->payload).$r.$r
459 .$msg->payload;
Barry Mienydd671972010-10-04 16:33:58 +0200460
George Petsagourakis306b3782012-05-02 20:31:08 +0300461 if ( ! fwrite($fp, $op, strlen($op)))
Derek Allard2067d1a2008-11-13 22:59:24 +0000462 {
463 error_log($this->xmlrpcstr['http_error']);
Andrey Andreevc8709832012-04-04 13:43:53 +0300464 return new XML_RPC_Response(0, $this->xmlrpcerr['http_error'], $this->xmlrpcstr['http_error']);
Derek Allard2067d1a2008-11-13 22:59:24 +0000465 }
Andrey Andreevc8709832012-04-04 13:43:53 +0300466
Derek Allard2067d1a2008-11-13 22:59:24 +0000467 $resp = $msg->parseResponse($fp);
468 fclose($fp);
469 return $resp;
470 }
471
Andrey Andreevc8709832012-04-04 13:43:53 +0300472} // END XML_RPC_Client Class
Derek Allard2067d1a2008-11-13 22:59:24 +0000473
474/**
475 * XML-RPC Response class
476 *
477 * @category XML-RPC
Derek Jonesf4a4bd82011-10-20 12:18:42 -0500478 * @author EllisLab Dev Team
Derek Allard2067d1a2008-11-13 22:59:24 +0000479 * @link http://codeigniter.com/user_guide/libraries/xmlrpc.html
480 */
481class XML_RPC_Response
482{
Andrey Andreevc8709832012-04-04 13:43:53 +0300483 public $val = 0;
484 public $errno = 0;
485 public $errstr = '';
486 public $headers = array();
487 public $xss_clean = TRUE;
Derek Allard2067d1a2008-11-13 22:59:24 +0000488
Andrey Andreevc8709832012-04-04 13:43:53 +0300489 /**
490 * Constructor
491 *
492 * @param mixed
493 * @param int
494 * @param string
495 * @return void
496 */
Greg Akera9263282010-11-10 15:26:43 -0600497 public function __construct($val, $code = 0, $fstr = '')
Barry Mienydd671972010-10-04 16:33:58 +0200498 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000499 if ($code != 0)
500 {
501 // error
502 $this->errno = $code;
Andrey Andreevc8709832012-04-04 13:43:53 +0300503 $this->errstr = htmlspecialchars($fstr,
504 (is_php('5.4') ? ENT_XML1 | ENT_NOQUOTES : ENT_NOQUOTES),
505 'UTF-8');
Derek Allard2067d1a2008-11-13 22:59:24 +0000506 }
Andrey Andreev8f50b6b2012-03-28 14:12:09 +0300507 elseif ( ! is_object($val))
Derek Allard2067d1a2008-11-13 22:59:24 +0000508 {
509 // programmer error, not an object
Andrey Andreev8f50b6b2012-03-28 14:12:09 +0300510 error_log("Invalid type '".gettype($val)."' (value: ".$val.') passed to XML_RPC_Response. Defaulting to empty value.');
Derek Allard2067d1a2008-11-13 22:59:24 +0000511 $this->val = new XML_RPC_Values();
512 }
513 else
514 {
515 $this->val = $val;
516 }
517 }
518
Andrey Andreevc8709832012-04-04 13:43:53 +0300519 // --------------------------------------------------------------------
520
521 /**
522 * Fault code
523 *
524 * @return int
525 */
Andrey Andreeva30faf92011-12-25 18:15:34 +0200526 public function faultCode()
Derek Allard2067d1a2008-11-13 22:59:24 +0000527 {
528 return $this->errno;
529 }
530
Andrey Andreevc8709832012-04-04 13:43:53 +0300531 // --------------------------------------------------------------------
532
533 /**
534 * Fault string
535 *
536 * @return string
537 */
Andrey Andreeva30faf92011-12-25 18:15:34 +0200538 public function faultString()
Derek Allard2067d1a2008-11-13 22:59:24 +0000539 {
540 return $this->errstr;
541 }
542
Andrey Andreevc8709832012-04-04 13:43:53 +0300543 // --------------------------------------------------------------------
544
545 /**
546 * Value
547 *
548 * @return mixed
549 */
Andrey Andreeva30faf92011-12-25 18:15:34 +0200550 public function value()
Derek Allard2067d1a2008-11-13 22:59:24 +0000551 {
552 return $this->val;
553 }
Barry Mienydd671972010-10-04 16:33:58 +0200554
Andrey Andreevc8709832012-04-04 13:43:53 +0300555 // --------------------------------------------------------------------
556
557 /**
558 * Prepare response
559 *
560 * @return string xml
561 */
Andrey Andreeva30faf92011-12-25 18:15:34 +0200562 public function prepare_response()
Derek Allard2067d1a2008-11-13 22:59:24 +0000563 {
Andrey Andreeva30faf92011-12-25 18:15:34 +0200564 return "<methodResponse>\n"
Andrey Andreevc8709832012-04-04 13:43:53 +0300565 .($this->errno
566 ? '<fault>
Derek Allard2067d1a2008-11-13 22:59:24 +0000567 <value>
568 <struct>
569 <member>
570 <name>faultCode</name>
Andrey Andreevc8709832012-04-04 13:43:53 +0300571 <value><int>'.$this->errno.'</int></value>
Derek Allard2067d1a2008-11-13 22:59:24 +0000572 </member>
573 <member>
574 <name>faultString</name>
Andrey Andreevc8709832012-04-04 13:43:53 +0300575 <value><string>'.$this->errstr.'</string></value>
Derek Allard2067d1a2008-11-13 22:59:24 +0000576 </member>
577 </struct>
578 </value>
Andrey Andreeva30faf92011-12-25 18:15:34 +0200579</fault>'
Andrey Andreevc8709832012-04-04 13:43:53 +0300580 : "<params>\n<param>\n".$this->val->serialize_class()."</param>\n</params>")
581 ."\n</methodResponse>";
Derek Allard2067d1a2008-11-13 22:59:24 +0000582 }
Barry Mienydd671972010-10-04 16:33:58 +0200583
Andrey Andreevc8709832012-04-04 13:43:53 +0300584 // --------------------------------------------------------------------
585
586 /**
587 * Decode
588 *
589 * @param mixed
590 * @return array
591 */
Andrey Andreeva30faf92011-12-25 18:15:34 +0200592 public function decode($array = FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000593 {
594 $CI =& get_instance();
Andrey Andreeva30faf92011-12-25 18:15:34 +0200595
596 if (is_array($array))
Derek Allard2067d1a2008-11-13 22:59:24 +0000597 {
598 while (list($key) = each($array))
599 {
600 if (is_array($array[$key]))
601 {
602 $array[$key] = $this->decode($array[$key]);
603 }
604 else
605 {
Robin Sowell66a3fc02010-03-18 09:44:55 -0400606 $array[$key] = ($this->xss_clean) ? $CI->security->xss_clean($array[$key]) : $array[$key];
Derek Allard2067d1a2008-11-13 22:59:24 +0000607 }
608 }
Barry Mienydd671972010-10-04 16:33:58 +0200609
Andrey Andreevc8709832012-04-04 13:43:53 +0300610 return $array;
611 }
612
613 $result = $this->xmlrpc_decoder($this->val);
614
615 if (is_array($result))
616 {
617 $result = $this->decode($result);
Derek Allard2067d1a2008-11-13 22:59:24 +0000618 }
619 else
620 {
Andrey Andreevc8709832012-04-04 13:43:53 +0300621 $result = ($this->xss_clean) ? $CI->security->xss_clean($result) : $result;
Derek Allard2067d1a2008-11-13 22:59:24 +0000622 }
Barry Mienydd671972010-10-04 16:33:58 +0200623
Derek Allard2067d1a2008-11-13 22:59:24 +0000624 return $result;
625 }
626
Andrey Andreevc8709832012-04-04 13:43:53 +0300627 // --------------------------------------------------------------------
Derek Allard2067d1a2008-11-13 22:59:24 +0000628
Andrey Andreevc8709832012-04-04 13:43:53 +0300629 /**
630 * XML-RPC Object to PHP Types
631 *
632 * @param object
633 * @return array
634 */
Andrey Andreeva30faf92011-12-25 18:15:34 +0200635 public function xmlrpc_decoder($xmlrpc_val)
Derek Allard2067d1a2008-11-13 22:59:24 +0000636 {
637 $kind = $xmlrpc_val->kindOf();
638
Pascal Kriete14287f32011-02-14 13:39:34 -0500639 if ($kind == 'scalar')
Derek Allard2067d1a2008-11-13 22:59:24 +0000640 {
641 return $xmlrpc_val->scalarval();
642 }
Pascal Kriete14287f32011-02-14 13:39:34 -0500643 elseif ($kind == 'array')
Derek Allard2067d1a2008-11-13 22:59:24 +0000644 {
645 reset($xmlrpc_val->me);
Andrey Andreevadc11752011-12-30 14:46:08 +0200646 $b = current($xmlrpc_val->me);
Derek Allard2067d1a2008-11-13 22:59:24 +0000647 $arr = array();
648
Andrey Andreeva30faf92011-12-25 18:15:34 +0200649 for ($i = 0, $size = count($b); $i < $size; $i++)
Derek Allard2067d1a2008-11-13 22:59:24 +0000650 {
651 $arr[] = $this->xmlrpc_decoder($xmlrpc_val->me['array'][$i]);
652 }
653 return $arr;
654 }
Pascal Kriete14287f32011-02-14 13:39:34 -0500655 elseif ($kind == 'struct')
Derek Allard2067d1a2008-11-13 22:59:24 +0000656 {
657 reset($xmlrpc_val->me['struct']);
658 $arr = array();
659
Pascal Kriete14287f32011-02-14 13:39:34 -0500660 while (list($key,$value) = each($xmlrpc_val->me['struct']))
Derek Allard2067d1a2008-11-13 22:59:24 +0000661 {
662 $arr[$key] = $this->xmlrpc_decoder($value);
663 }
664 return $arr;
665 }
666 }
Barry Mienydd671972010-10-04 16:33:58 +0200667
Andrey Andreevc8709832012-04-04 13:43:53 +0300668 // --------------------------------------------------------------------
Derek Allard2067d1a2008-11-13 22:59:24 +0000669
Andrey Andreevc8709832012-04-04 13:43:53 +0300670 /**
671 * ISO-8601 time to server or UTC time
672 *
673 * @param string
674 * @param bool
675 * @return int unix timestamp
676 */
677 public function iso8601_decode($time, $utc = FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000678 {
Andrey Andreevc8709832012-04-04 13:43:53 +0300679 // return a time in the localtime, or UTC
Derek Allard2067d1a2008-11-13 22:59:24 +0000680 $t = 0;
681 if (preg_match('/([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})/', $time, $regs))
682 {
Andrey Andreevc8709832012-04-04 13:43:53 +0300683 $fnc = ($utc == TRUE) ? 'gmmktime' : 'mktime';
Pascal Kriete14287f32011-02-14 13:39:34 -0500684 $t = $fnc($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
Derek Allard2067d1a2008-11-13 22:59:24 +0000685 }
686 return $t;
687 }
Barry Mienydd671972010-10-04 16:33:58 +0200688
Andrey Andreevc8709832012-04-04 13:43:53 +0300689} // END XML_RPC_Response Class
Derek Allard2067d1a2008-11-13 22:59:24 +0000690
691/**
692 * XML-RPC Message class
693 *
694 * @category XML-RPC
Derek Jonesf4a4bd82011-10-20 12:18:42 -0500695 * @author EllisLab Dev Team
Derek Allard2067d1a2008-11-13 22:59:24 +0000696 * @link http://codeigniter.com/user_guide/libraries/xmlrpc.html
697 */
698class XML_RPC_Message extends CI_Xmlrpc
699{
Andrey Andreeva30faf92011-12-25 18:15:34 +0200700 public $payload;
701 public $method_name;
Andrey Andreevc8709832012-04-04 13:43:53 +0300702 public $params = array();
703 public $xh = array();
Derek Allard2067d1a2008-11-13 22:59:24 +0000704
Andrey Andreevc8709832012-04-04 13:43:53 +0300705 /**
706 * Constructor
707 *
708 * @param string method name
709 * @param array
710 * @return void
711 */
712 public function __construct($method, $pars = FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000713 {
Greg Akera9263282010-11-10 15:26:43 -0600714 parent::__construct();
Barry Mienydd671972010-10-04 16:33:58 +0200715
Derek Allard2067d1a2008-11-13 22:59:24 +0000716 $this->method_name = $method;
Derek Jones33559102009-02-02 18:50:38 +0000717 if (is_array($pars) && count($pars) > 0)
Derek Allard2067d1a2008-11-13 22:59:24 +0000718 {
Andrey Andreeva30faf92011-12-25 18:15:34 +0200719 for ($i = 0, $c = count($pars); $i < $c; $i++)
Derek Allard2067d1a2008-11-13 22:59:24 +0000720 {
721 // $pars[$i] = XML_RPC_Values
722 $this->params[] = $pars[$i];
723 }
724 }
725 }
Barry Mienydd671972010-10-04 16:33:58 +0200726
Andrey Andreevc8709832012-04-04 13:43:53 +0300727 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200728
Andrey Andreevc8709832012-04-04 13:43:53 +0300729 /**
730 * Create Payload to Send
731 *
732 * @return void
733 */
Andrey Andreeva30faf92011-12-25 18:15:34 +0200734 public function createPayload()
Derek Allard2067d1a2008-11-13 22:59:24 +0000735 {
Andrey Andreevc8709832012-04-04 13:43:53 +0300736 $this->payload = '<?xml version="1.0"?'.">\r\n<methodCall>\r\n"
737 .'<methodName>'.$this->method_name."</methodName>\r\n"
738 ."<params>\r\n";
Barry Mienydd671972010-10-04 16:33:58 +0200739
Andrey Andreeva30faf92011-12-25 18:15:34 +0200740 for ($i = 0, $c = count($this->params); $i < $c; $i++)
Derek Allard2067d1a2008-11-13 22:59:24 +0000741 {
742 // $p = XML_RPC_Values
743 $p = $this->params[$i];
744 $this->payload .= "<param>\r\n".$p->serialize_class()."</param>\r\n";
745 }
Barry Mienydd671972010-10-04 16:33:58 +0200746
Derek Allard2067d1a2008-11-13 22:59:24 +0000747 $this->payload .= "</params>\r\n</methodCall>\r\n";
748 }
Barry Mienydd671972010-10-04 16:33:58 +0200749
Andrey Andreevc8709832012-04-04 13:43:53 +0300750 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200751
Andrey Andreevc8709832012-04-04 13:43:53 +0300752 /**
753 * Parse External XML-RPC Server's Response
754 *
755 * @param resource
756 * @return object
757 */
Andrey Andreeva30faf92011-12-25 18:15:34 +0200758 public function parseResponse($fp)
Derek Allard2067d1a2008-11-13 22:59:24 +0000759 {
760 $data = '';
Barry Mienydd671972010-10-04 16:33:58 +0200761
Pascal Kriete14287f32011-02-14 13:39:34 -0500762 while ($datum = fread($fp, 4096))
Derek Allard2067d1a2008-11-13 22:59:24 +0000763 {
764 $data .= $datum;
765 }
Barry Mienydd671972010-10-04 16:33:58 +0200766
Andrey Andreevc8709832012-04-04 13:43:53 +0300767 // Display HTTP content for debugging
Derek Allard2067d1a2008-11-13 22:59:24 +0000768 if ($this->debug === TRUE)
769 {
Andrey Andreeva30faf92011-12-25 18:15:34 +0200770 echo "<pre>---DATA---\n".htmlspecialchars($data)."\n---END DATA---\n\n</pre>";
Derek Allard2067d1a2008-11-13 22:59:24 +0000771 }
Barry Mienydd671972010-10-04 16:33:58 +0200772
Andrey Andreevc8709832012-04-04 13:43:53 +0300773 // Check for data
Andrey Andreeva30faf92011-12-25 18:15:34 +0200774 if ($data === '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000775 {
776 error_log($this->xmlrpcstr['no_data']);
Andrey Andreevc8709832012-04-04 13:43:53 +0300777 return new XML_RPC_Response(0, $this->xmlrpcerr['no_data'], $this->xmlrpcstr['no_data']);
Derek Allard2067d1a2008-11-13 22:59:24 +0000778 }
Barry Mienydd671972010-10-04 16:33:58 +0200779
Andrey Andreevc8709832012-04-04 13:43:53 +0300780 // Check for HTTP 200 Response
Andrey Andreeva30faf92011-12-25 18:15:34 +0200781 if (strncmp($data, 'HTTP', 4) === 0 && ! preg_match('/^HTTP\/[0-9\.]+ 200 /', $data))
Derek Allard2067d1a2008-11-13 22:59:24 +0000782 {
Andrey Andreevc8709832012-04-04 13:43:53 +0300783 $errstr = substr($data, 0, strpos($data, "\n")-1);
784 return new XML_RPC_Response(0, $this->xmlrpcerr['http_error'], $this->xmlrpcstr['http_error'].' ('.$errstr.')');
Derek Allard2067d1a2008-11-13 22:59:24 +0000785 }
Barry Mienydd671972010-10-04 16:33:58 +0200786
Derek Allard2067d1a2008-11-13 22:59:24 +0000787 //-------------------------------------
Derek Jones37f4b9c2011-07-01 17:56:50 -0500788 // Create and Set Up XML Parser
Derek Allard2067d1a2008-11-13 22:59:24 +0000789 //-------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200790
Derek Allard2067d1a2008-11-13 22:59:24 +0000791 $parser = xml_parser_create($this->xmlrpc_defencoding);
792
Andrey Andreeva30faf92011-12-25 18:15:34 +0200793 $this->xh[$parser] = array(
Andrey Andreevc8709832012-04-04 13:43:53 +0300794 'isf' => 0,
795 'ac' => '',
796 'headers' => array(),
797 'stack' => array(),
798 'valuestack' => array(),
799 'isf_reason' => 0
Andrey Andreeva30faf92011-12-25 18:15:34 +0200800 );
Derek Allard2067d1a2008-11-13 22:59:24 +0000801
802 xml_set_object($parser, $this);
Andrey Andreevc8709832012-04-04 13:43:53 +0300803 xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, TRUE);
Derek Allard2067d1a2008-11-13 22:59:24 +0000804 xml_set_element_handler($parser, 'open_tag', 'closing_tag');
805 xml_set_character_data_handler($parser, 'character_data');
806 //xml_set_default_handler($parser, 'default_handler');
807
Andrey Andreevc8709832012-04-04 13:43:53 +0300808 // Get headers
Derek Allard2067d1a2008-11-13 22:59:24 +0000809 $lines = explode("\r\n", $data);
810 while (($line = array_shift($lines)))
811 {
812 if (strlen($line) < 1)
813 {
814 break;
815 }
816 $this->xh[$parser]['headers'][] = $line;
817 }
818 $data = implode("\r\n", $lines);
Barry Mienydd671972010-10-04 16:33:58 +0200819
Andrey Andreevc8709832012-04-04 13:43:53 +0300820 // Parse XML data
Derek Jones33559102009-02-02 18:50:38 +0000821 if ( ! xml_parse($parser, $data, count($data)))
Derek Allard2067d1a2008-11-13 22:59:24 +0000822 {
823 $errstr = sprintf('XML error: %s at line %d',
Andrey Andreevc8709832012-04-04 13:43:53 +0300824 xml_error_string(xml_get_error_code($parser)),
825 xml_get_current_line_number($parser));
Derek Allard2067d1a2008-11-13 22:59:24 +0000826 //error_log($errstr);
827 $r = new XML_RPC_Response(0, $this->xmlrpcerr['invalid_return'], $this->xmlrpcstr['invalid_return']);
828 xml_parser_free($parser);
829 return $r;
830 }
831 xml_parser_free($parser);
Barry Mienydd671972010-10-04 16:33:58 +0200832
Andrey Andreevc8709832012-04-04 13:43:53 +0300833 // Got ourselves some badness, it seems
Derek Allard2067d1a2008-11-13 22:59:24 +0000834 if ($this->xh[$parser]['isf'] > 1)
835 {
836 if ($this->debug === TRUE)
837 {
Andrey Andreeva30faf92011-12-25 18:15:34 +0200838 echo "---Invalid Return---\n".$this->xh[$parser]['isf_reason']."---Invalid Return---\n\n";
Derek Allard2067d1a2008-11-13 22:59:24 +0000839 }
Barry Mienydd671972010-10-04 16:33:58 +0200840
Andrey Andreevc8709832012-04-04 13:43:53 +0300841 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 +0000842 }
843 elseif ( ! is_object($this->xh[$parser]['value']))
844 {
Andrey Andreevc8709832012-04-04 13:43:53 +0300845 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 +0000846 }
Barry Mienydd671972010-10-04 16:33:58 +0200847
Andrey Andreevc8709832012-04-04 13:43:53 +0300848 // Display XML content for debugging
Derek Allard2067d1a2008-11-13 22:59:24 +0000849 if ($this->debug === TRUE)
850 {
Andrey Andreev8f50b6b2012-03-28 14:12:09 +0300851 echo '<pre>';
Barry Mienydd671972010-10-04 16:33:58 +0200852
Derek Allard2067d1a2008-11-13 22:59:24 +0000853 if (count($this->xh[$parser]['headers'] > 0))
854 {
855 echo "---HEADERS---\n";
856 foreach ($this->xh[$parser]['headers'] as $header)
857 {
Andrey Andreev8f50b6b2012-03-28 14:12:09 +0300858 echo $header."\n";
Derek Allard2067d1a2008-11-13 22:59:24 +0000859 }
860 echo "---END HEADERS---\n\n";
861 }
Barry Mienydd671972010-10-04 16:33:58 +0200862
Andrey Andreeva30faf92011-12-25 18:15:34 +0200863 echo "---DATA---\n".htmlspecialchars($data)."\n---END DATA---\n\n---PARSED---\n";
Derek Allard2067d1a2008-11-13 22:59:24 +0000864 var_dump($this->xh[$parser]['value']);
865 echo "\n---END PARSED---</pre>";
866 }
Barry Mienydd671972010-10-04 16:33:58 +0200867
Andrey Andreevc8709832012-04-04 13:43:53 +0300868 // Send response
Derek Allard2067d1a2008-11-13 22:59:24 +0000869 $v = $this->xh[$parser]['value'];
Derek Allard2067d1a2008-11-13 22:59:24 +0000870 if ($this->xh[$parser]['isf'])
871 {
872 $errno_v = $v->me['struct']['faultCode'];
873 $errstr_v = $v->me['struct']['faultString'];
874 $errno = $errno_v->scalarval();
875
876 if ($errno == 0)
877 {
878 // FAULT returned, errno needs to reflect that
879 $errno = -1;
880 }
881
882 $r = new XML_RPC_Response($v, $errno, $errstr_v->scalarval());
883 }
884 else
885 {
886 $r = new XML_RPC_Response($v);
887 }
888
889 $r->headers = $this->xh[$parser]['headers'];
890 return $r;
891 }
Barry Mienydd671972010-10-04 16:33:58 +0200892
Andrey Andreevc8709832012-04-04 13:43:53 +0300893 // --------------------------------------------------------------------
894
Derek Allard2067d1a2008-11-13 22:59:24 +0000895 // ------------------------------------
Derek Jones37f4b9c2011-07-01 17:56:50 -0500896 // Begin Return Message Parsing section
Derek Allard2067d1a2008-11-13 22:59:24 +0000897 // ------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200898
Derek Allard2067d1a2008-11-13 22:59:24 +0000899 // quick explanation of components:
Derek Jones37f4b9c2011-07-01 17:56:50 -0500900 // ac - used to accumulate values
901 // isf - used to indicate a fault
902 // lv - used to indicate "looking for a value": implements
Derek Allard2067d1a2008-11-13 22:59:24 +0000903 // the logic to allow values with no types to be strings
Derek Jones37f4b9c2011-07-01 17:56:50 -0500904 // params - used to store parameters in method calls
905 // method - used to store method name
Derek Allard2067d1a2008-11-13 22:59:24 +0000906 // stack - array with parent tree of the xml element,
907 // used to validate the nesting of elements
908
Andrey Andreevc8709832012-04-04 13:43:53 +0300909 // --------------------------------------------------------------------
Derek Allard2067d1a2008-11-13 22:59:24 +0000910
Andrey Andreevc8709832012-04-04 13:43:53 +0300911 /**
912 * Start Element Handler
913 *
914 * @param string
915 * @param string
916 * @return void
917 */
918 public function open_tag($the_parser, $name)
Derek Allard2067d1a2008-11-13 22:59:24 +0000919 {
920 // If invalid nesting, then return
921 if ($this->xh[$the_parser]['isf'] > 1) return;
Barry Mienydd671972010-10-04 16:33:58 +0200922
Derek Allard2067d1a2008-11-13 22:59:24 +0000923 // Evaluate and check for correct nesting of XML elements
Derek Allard2067d1a2008-11-13 22:59:24 +0000924 if (count($this->xh[$the_parser]['stack']) == 0)
925 {
926 if ($name != 'METHODRESPONSE' && $name != 'METHODCALL')
927 {
928 $this->xh[$the_parser]['isf'] = 2;
929 $this->xh[$the_parser]['isf_reason'] = 'Top level XML-RPC element is missing';
930 return;
931 }
932 }
Andrey Andreevc8709832012-04-04 13:43:53 +0300933 // not top level element: see if parent is OK
934 elseif ( ! in_array($this->xh[$the_parser]['stack'][0], $this->valid_parents[$name], TRUE))
Derek Allard2067d1a2008-11-13 22:59:24 +0000935 {
Andrey Andreevc8709832012-04-04 13:43:53 +0300936 $this->xh[$the_parser]['isf'] = 2;
937 $this->xh[$the_parser]['isf_reason'] = 'XML-RPC element $name cannot be child of '.$this->xh[$the_parser]['stack'][0];
938 return;
Derek Allard2067d1a2008-11-13 22:59:24 +0000939 }
Barry Mienydd671972010-10-04 16:33:58 +0200940
Andrey Andreevc8709832012-04-04 13:43:53 +0300941 switch ($name)
Derek Allard2067d1a2008-11-13 22:59:24 +0000942 {
943 case 'STRUCT':
944 case 'ARRAY':
945 // Creates array for child elements
Andrey Andreev8f50b6b2012-03-28 14:12:09 +0300946 $cur_val = array('value' => array(), 'type' => $name);
Derek Allard2067d1a2008-11-13 22:59:24 +0000947 array_unshift($this->xh[$the_parser]['valuestack'], $cur_val);
Andrey Andreevc8709832012-04-04 13:43:53 +0300948 break;
Derek Allard2067d1a2008-11-13 22:59:24 +0000949 case 'METHODNAME':
950 case 'NAME':
951 $this->xh[$the_parser]['ac'] = '';
Andrey Andreevc8709832012-04-04 13:43:53 +0300952 break;
Derek Allard2067d1a2008-11-13 22:59:24 +0000953 case 'FAULT':
954 $this->xh[$the_parser]['isf'] = 1;
Andrey Andreevc8709832012-04-04 13:43:53 +0300955 break;
Derek Allard2067d1a2008-11-13 22:59:24 +0000956 case 'PARAM':
Pascal Kriete8761ef52011-02-14 13:13:52 -0500957 $this->xh[$the_parser]['value'] = NULL;
Andrey Andreevc8709832012-04-04 13:43:53 +0300958 break;
Derek Allard2067d1a2008-11-13 22:59:24 +0000959 case 'VALUE':
960 $this->xh[$the_parser]['vt'] = 'value';
961 $this->xh[$the_parser]['ac'] = '';
962 $this->xh[$the_parser]['lv'] = 1;
Andrey Andreevc8709832012-04-04 13:43:53 +0300963 break;
Derek Allard2067d1a2008-11-13 22:59:24 +0000964 case 'I4':
965 case 'INT':
966 case 'STRING':
967 case 'BOOLEAN':
968 case 'DOUBLE':
969 case 'DATETIME.ISO8601':
970 case 'BASE64':
971 if ($this->xh[$the_parser]['vt'] != 'value')
972 {
973 //two data elements inside a value: an error occurred!
974 $this->xh[$the_parser]['isf'] = 2;
Andrey Andreevc8709832012-04-04 13:43:53 +0300975 $this->xh[$the_parser]['isf_reason'] = "'Twas a ".$name.' element following a '
976 .$this->xh[$the_parser]['vt'].' element inside a single value';
Derek Allard2067d1a2008-11-13 22:59:24 +0000977 return;
978 }
Barry Mienydd671972010-10-04 16:33:58 +0200979
Derek Allard2067d1a2008-11-13 22:59:24 +0000980 $this->xh[$the_parser]['ac'] = '';
Andrey Andreevc8709832012-04-04 13:43:53 +0300981 break;
Derek Allard2067d1a2008-11-13 22:59:24 +0000982 case 'MEMBER':
983 // Set name of <member> to nothing to prevent errors later if no <name> is found
984 $this->xh[$the_parser]['valuestack'][0]['name'] = '';
Barry Mienydd671972010-10-04 16:33:58 +0200985
Derek Allard2067d1a2008-11-13 22:59:24 +0000986 // Set NULL value to check to see if value passed for this param/member
Pascal Kriete8761ef52011-02-14 13:13:52 -0500987 $this->xh[$the_parser]['value'] = NULL;
Andrey Andreevc8709832012-04-04 13:43:53 +0300988 break;
Derek Allard2067d1a2008-11-13 22:59:24 +0000989 case 'DATA':
990 case 'METHODCALL':
991 case 'METHODRESPONSE':
992 case 'PARAMS':
993 // valid elements that add little to processing
Andrey Andreevc8709832012-04-04 13:43:53 +0300994 break;
Derek Allard2067d1a2008-11-13 22:59:24 +0000995 default:
996 /// An Invalid Element is Found, so we have trouble
997 $this->xh[$the_parser]['isf'] = 2;
Andrey Andreevc8709832012-04-04 13:43:53 +0300998 $this->xh[$the_parser]['isf_reason'] = 'Invalid XML-RPC element found: '.$name;
999 break;
Derek Allard2067d1a2008-11-13 22:59:24 +00001000 }
Barry Mienydd671972010-10-04 16:33:58 +02001001
Derek Allard2067d1a2008-11-13 22:59:24 +00001002 // Add current element name to stack, to allow validation of nesting
1003 array_unshift($this->xh[$the_parser]['stack'], $name);
1004
Andrey Andreevc8709832012-04-04 13:43:53 +03001005 $name == 'VALUE' OR $this->xh[$the_parser]['lv'] = 0;
Derek Allard2067d1a2008-11-13 22:59:24 +00001006 }
Derek Allard2067d1a2008-11-13 22:59:24 +00001007
Andrey Andreevc8709832012-04-04 13:43:53 +03001008 // --------------------------------------------------------------------
Derek Allard2067d1a2008-11-13 22:59:24 +00001009
Andrey Andreevc8709832012-04-04 13:43:53 +03001010 /**
1011 * End Element Handler
1012 *
1013 * @param string
1014 * @param string
1015 * @return void
1016 */
Andrey Andreeva30faf92011-12-25 18:15:34 +02001017 public function closing_tag($the_parser, $name)
Derek Allard2067d1a2008-11-13 22:59:24 +00001018 {
1019 if ($this->xh[$the_parser]['isf'] > 1) return;
Barry Mienydd671972010-10-04 16:33:58 +02001020
Derek Allard2067d1a2008-11-13 22:59:24 +00001021 // Remove current element from stack and set variable
1022 // NOTE: If the XML validates, then we do not have to worry about
Andrey Andreevc8709832012-04-04 13:43:53 +03001023 // the opening and closing of elements. Nesting is checked on the opening
Derek Allard2067d1a2008-11-13 22:59:24 +00001024 // tag so we be safe there as well.
Barry Mienydd671972010-10-04 16:33:58 +02001025
Derek Allard2067d1a2008-11-13 22:59:24 +00001026 $curr_elem = array_shift($this->xh[$the_parser]['stack']);
Barry Mienydd671972010-10-04 16:33:58 +02001027
Andrey Andreevc8709832012-04-04 13:43:53 +03001028 switch ($name)
Derek Allard2067d1a2008-11-13 22:59:24 +00001029 {
1030 case 'STRUCT':
1031 case 'ARRAY':
1032 $cur_val = array_shift($this->xh[$the_parser]['valuestack']);
Andrey Andreevc8709832012-04-04 13:43:53 +03001033 $this->xh[$the_parser]['value'] = isset($cur_val['values']) ? $cur_val['values'] : array();
Derek Allard2067d1a2008-11-13 22:59:24 +00001034 $this->xh[$the_parser]['vt'] = strtolower($name);
Andrey Andreevc8709832012-04-04 13:43:53 +03001035 break;
Derek Allard2067d1a2008-11-13 22:59:24 +00001036 case 'NAME':
1037 $this->xh[$the_parser]['valuestack'][0]['name'] = $this->xh[$the_parser]['ac'];
Andrey Andreevc8709832012-04-04 13:43:53 +03001038 break;
Derek Allard2067d1a2008-11-13 22:59:24 +00001039 case 'BOOLEAN':
1040 case 'I4':
1041 case 'INT':
1042 case 'STRING':
1043 case 'DOUBLE':
1044 case 'DATETIME.ISO8601':
1045 case 'BASE64':
1046 $this->xh[$the_parser]['vt'] = strtolower($name);
Barry Mienydd671972010-10-04 16:33:58 +02001047
Derek Allard2067d1a2008-11-13 22:59:24 +00001048 if ($name == 'STRING')
1049 {
1050 $this->xh[$the_parser]['value'] = $this->xh[$the_parser]['ac'];
1051 }
Andrey Andreevc8709832012-04-04 13:43:53 +03001052 elseif ($name == 'DATETIME.ISO8601')
Derek Allard2067d1a2008-11-13 22:59:24 +00001053 {
1054 $this->xh[$the_parser]['vt'] = $this->xmlrpcDateTime;
1055 $this->xh[$the_parser]['value'] = $this->xh[$the_parser]['ac'];
1056 }
Andrey Andreevc8709832012-04-04 13:43:53 +03001057 elseif ($name == 'BASE64')
Derek Allard2067d1a2008-11-13 22:59:24 +00001058 {
1059 $this->xh[$the_parser]['value'] = base64_decode($this->xh[$the_parser]['ac']);
1060 }
Andrey Andreevc8709832012-04-04 13:43:53 +03001061 elseif ($name == 'BOOLEAN')
Derek Allard2067d1a2008-11-13 22:59:24 +00001062 {
1063 // Translated BOOLEAN values to TRUE AND FALSE
Andrey Andreevc8709832012-04-04 13:43:53 +03001064 $this->xh[$the_parser]['value'] = (bool) $this->xh[$the_parser]['ac'];
Derek Allard2067d1a2008-11-13 22:59:24 +00001065 }
1066 elseif ($name=='DOUBLE')
1067 {
1068 // we have a DOUBLE
1069 // we must check that only 0123456789-.<space> are characters here
Andrey Andreevc8709832012-04-04 13:43:53 +03001070 $this->xh[$the_parser]['value'] = preg_match('/^[+-]?[eE0-9\t \.]+$/', $this->xh[$the_parser]['ac'])
1071 ? (float) $this->xh[$the_parser]['ac']
1072 : 'ERROR_NON_NUMERIC_FOUND';
Derek Allard2067d1a2008-11-13 22:59:24 +00001073 }
1074 else
1075 {
1076 // we have an I4/INT
1077 // we must check that only 0123456789-<space> are characters here
Andrey Andreevc8709832012-04-04 13:43:53 +03001078 $this->xh[$the_parser]['value'] = preg_match('/^[+-]?[0-9\t ]+$/', $this->xh[$the_parser]['ac'])
George Petsagourakis306b3782012-05-02 20:31:08 +03001079 ? (int) $this->xh[$the_parser]['ac']
Andrey Andreevc8709832012-04-04 13:43:53 +03001080 : 'ERROR_NON_NUMERIC_FOUND';
Derek Allard2067d1a2008-11-13 22:59:24 +00001081 }
1082 $this->xh[$the_parser]['ac'] = '';
1083 $this->xh[$the_parser]['lv'] = 3; // indicate we've found a value
Andrey Andreevc8709832012-04-04 13:43:53 +03001084 break;
Derek Allard2067d1a2008-11-13 22:59:24 +00001085 case 'VALUE':
1086 // This if() detects if no scalar was inside <VALUE></VALUE>
1087 if ($this->xh[$the_parser]['vt']=='value')
1088 {
1089 $this->xh[$the_parser]['value'] = $this->xh[$the_parser]['ac'];
1090 $this->xh[$the_parser]['vt'] = $this->xmlrpcString;
1091 }
Barry Mienydd671972010-10-04 16:33:58 +02001092
Derek Allard2067d1a2008-11-13 22:59:24 +00001093 // build the XML-RPC value out of the data received, and substitute it
1094 $temp = new XML_RPC_Values($this->xh[$the_parser]['value'], $this->xh[$the_parser]['vt']);
Barry Mienydd671972010-10-04 16:33:58 +02001095
Derek Allard2067d1a2008-11-13 22:59:24 +00001096 if (count($this->xh[$the_parser]['valuestack']) && $this->xh[$the_parser]['valuestack'][0]['type'] == 'ARRAY')
1097 {
1098 // Array
1099 $this->xh[$the_parser]['valuestack'][0]['values'][] = $temp;
1100 }
1101 else
1102 {
1103 // Struct
1104 $this->xh[$the_parser]['value'] = $temp;
1105 }
Andrey Andreevc8709832012-04-04 13:43:53 +03001106 break;
Derek Allard2067d1a2008-11-13 22:59:24 +00001107 case 'MEMBER':
Andrey Andreevc8709832012-04-04 13:43:53 +03001108 $this->xh[$the_parser]['ac'] = '';
Barry Mienydd671972010-10-04 16:33:58 +02001109
Derek Allard2067d1a2008-11-13 22:59:24 +00001110 // If value add to array in the stack for the last element built
1111 if ($this->xh[$the_parser]['value'])
1112 {
1113 $this->xh[$the_parser]['valuestack'][0]['values'][$this->xh[$the_parser]['valuestack'][0]['name']] = $this->xh[$the_parser]['value'];
1114 }
Andrey Andreevc8709832012-04-04 13:43:53 +03001115 break;
Derek Allard2067d1a2008-11-13 22:59:24 +00001116 case 'DATA':
Andrey Andreevc8709832012-04-04 13:43:53 +03001117 $this->xh[$the_parser]['ac'] = '';
1118 break;
Derek Allard2067d1a2008-11-13 22:59:24 +00001119 case 'PARAM':
1120 if ($this->xh[$the_parser]['value'])
1121 {
1122 $this->xh[$the_parser]['params'][] = $this->xh[$the_parser]['value'];
1123 }
Andrey Andreevc8709832012-04-04 13:43:53 +03001124 break;
Derek Allard2067d1a2008-11-13 22:59:24 +00001125 case 'METHODNAME':
1126 $this->xh[$the_parser]['method'] = ltrim($this->xh[$the_parser]['ac']);
Andrey Andreevc8709832012-04-04 13:43:53 +03001127 break;
Derek Allard2067d1a2008-11-13 22:59:24 +00001128 case 'PARAMS':
1129 case 'FAULT':
1130 case 'METHODCALL':
1131 case 'METHORESPONSE':
1132 // We're all good kids with nuthin' to do
Andrey Andreevc8709832012-04-04 13:43:53 +03001133 break;
Derek Allard2067d1a2008-11-13 22:59:24 +00001134 default:
Andrey Andreevc8709832012-04-04 13:43:53 +03001135 // End of an Invalid Element. Taken care of during the opening tag though
1136 break;
Derek Allard2067d1a2008-11-13 22:59:24 +00001137 }
1138 }
1139
Andrey Andreevc8709832012-04-04 13:43:53 +03001140 // --------------------------------------------------------------------
Derek Allard2067d1a2008-11-13 22:59:24 +00001141
Andrey Andreevc8709832012-04-04 13:43:53 +03001142 /**
1143 * Parse character data
1144 *
1145 * @param string
1146 * @param string
1147 * @return void
1148 */
Andrey Andreeva30faf92011-12-25 18:15:34 +02001149 public function character_data($the_parser, $data)
Derek Allard2067d1a2008-11-13 22:59:24 +00001150 {
1151 if ($this->xh[$the_parser]['isf'] > 1) return; // XML Fault found already
Barry Mienydd671972010-10-04 16:33:58 +02001152
Derek Allard2067d1a2008-11-13 22:59:24 +00001153 // If a value has not been found
1154 if ($this->xh[$the_parser]['lv'] != 3)
1155 {
1156 if ($this->xh[$the_parser]['lv'] == 1)
1157 {
1158 $this->xh[$the_parser]['lv'] = 2; // Found a value
1159 }
Barry Mienydd671972010-10-04 16:33:58 +02001160
Andrey Andreevc8709832012-04-04 13:43:53 +03001161 if ( ! isset($this->xh[$the_parser]['ac']))
Derek Allard2067d1a2008-11-13 22:59:24 +00001162 {
1163 $this->xh[$the_parser]['ac'] = '';
1164 }
Barry Mienydd671972010-10-04 16:33:58 +02001165
Derek Allard2067d1a2008-11-13 22:59:24 +00001166 $this->xh[$the_parser]['ac'] .= $data;
1167 }
1168 }
Barry Mienydd671972010-10-04 16:33:58 +02001169
Andrey Andreevc8709832012-04-04 13:43:53 +03001170 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +02001171
Andrey Andreevc8709832012-04-04 13:43:53 +03001172 /**
1173 * Add parameter
1174 *
1175 * @param mixed
1176 * @return void
1177 */
Andrey Andreeva30faf92011-12-25 18:15:34 +02001178 public function addParam($par)
1179 {
1180 $this->params[] = $par;
1181 }
Barry Mienydd671972010-10-04 16:33:58 +02001182
Andrey Andreevc8709832012-04-04 13:43:53 +03001183 // --------------------------------------------------------------------
1184
1185 /**
1186 * Output parameters
1187 *
1188 * @param array
1189 * @return array
1190 */
Andrey Andreeva30faf92011-12-25 18:15:34 +02001191 public function output_parameters($array = FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +00001192 {
Barry Mienydd671972010-10-04 16:33:58 +02001193 $CI =& get_instance();
Andrey Andreeva30faf92011-12-25 18:15:34 +02001194
1195 if (is_array($array))
Derek Allard2067d1a2008-11-13 22:59:24 +00001196 {
1197 while (list($key) = each($array))
1198 {
1199 if (is_array($array[$key]))
1200 {
1201 $array[$key] = $this->output_parameters($array[$key]);
1202 }
1203 else
1204 {
Derek Jonesa9647e82010-03-02 22:59:07 -06001205 // 'bits' is for the MetaWeblog API image bits
1206 // @todo - this needs to be made more general purpose
Robin Sowell66a3fc02010-03-18 09:44:55 -04001207 $array[$key] = ($key == 'bits' OR $this->xss_clean == FALSE) ? $array[$key] : $CI->security->xss_clean($array[$key]);
Derek Allard2067d1a2008-11-13 22:59:24 +00001208 }
1209 }
Barry Mienydd671972010-10-04 16:33:58 +02001210
Andrey Andreevc8709832012-04-04 13:43:53 +03001211 return $array;
Derek Allard2067d1a2008-11-13 22:59:24 +00001212 }
Andrey Andreevc8709832012-04-04 13:43:53 +03001213
1214 $parameters = array();
1215
1216 for ($i = 0, $c = count($this->params); $i < $c; $i++)
Derek Allard2067d1a2008-11-13 22:59:24 +00001217 {
Andrey Andreevc8709832012-04-04 13:43:53 +03001218 $a_param = $this->decode_message($this->params[$i]);
Barry Mienydd671972010-10-04 16:33:58 +02001219
Andrey Andreevc8709832012-04-04 13:43:53 +03001220 if (is_array($a_param))
Derek Allard2067d1a2008-11-13 22:59:24 +00001221 {
Andrey Andreevc8709832012-04-04 13:43:53 +03001222 $parameters[] = $this->output_parameters($a_param);
1223 }
1224 else
1225 {
1226 $parameters[] = ($this->xss_clean) ? $CI->security->xss_clean($a_param) : $a_param;
Barry Mienydd671972010-10-04 16:33:58 +02001227 }
Derek Allard2067d1a2008-11-13 22:59:24 +00001228 }
Barry Mienydd671972010-10-04 16:33:58 +02001229
Derek Allard2067d1a2008-11-13 22:59:24 +00001230 return $parameters;
1231 }
Barry Mienydd671972010-10-04 16:33:58 +02001232
Andrey Andreevc8709832012-04-04 13:43:53 +03001233 // --------------------------------------------------------------------
1234
1235 /**
1236 * Decode message
1237 *
1238 * @param object
1239 * @return mixed
1240 */
Andrey Andreeva30faf92011-12-25 18:15:34 +02001241 public function decode_message($param)
Derek Allard2067d1a2008-11-13 22:59:24 +00001242 {
1243 $kind = $param->kindOf();
1244
Pascal Kriete14287f32011-02-14 13:39:34 -05001245 if ($kind == 'scalar')
Derek Allard2067d1a2008-11-13 22:59:24 +00001246 {
1247 return $param->scalarval();
1248 }
Pascal Kriete14287f32011-02-14 13:39:34 -05001249 elseif ($kind == 'array')
Derek Allard2067d1a2008-11-13 22:59:24 +00001250 {
1251 reset($param->me);
Andrey Andreevadc11752011-12-30 14:46:08 +02001252 $b = current($param->me);
Derek Allard2067d1a2008-11-13 22:59:24 +00001253 $arr = array();
1254
Andrey Andreevc8709832012-04-04 13:43:53 +03001255 for ($i = 0, $c = count($b); $i < $c; $i++)
Derek Allard2067d1a2008-11-13 22:59:24 +00001256 {
1257 $arr[] = $this->decode_message($param->me['array'][$i]);
1258 }
Barry Mienydd671972010-10-04 16:33:58 +02001259
Derek Allard2067d1a2008-11-13 22:59:24 +00001260 return $arr;
1261 }
Pascal Kriete14287f32011-02-14 13:39:34 -05001262 elseif ($kind == 'struct')
Derek Allard2067d1a2008-11-13 22:59:24 +00001263 {
1264 reset($param->me['struct']);
Derek Allard2067d1a2008-11-13 22:59:24 +00001265 $arr = array();
1266
Pascal Kriete14287f32011-02-14 13:39:34 -05001267 while (list($key,$value) = each($param->me['struct']))
Derek Allard2067d1a2008-11-13 22:59:24 +00001268 {
1269 $arr[$key] = $this->decode_message($value);
1270 }
Barry Mienydd671972010-10-04 16:33:58 +02001271
Derek Allard2067d1a2008-11-13 22:59:24 +00001272 return $arr;
1273 }
1274 }
Barry Mienydd671972010-10-04 16:33:58 +02001275
Andrey Andreevc8709832012-04-04 13:43:53 +03001276} // END XML_RPC_Message Class
Derek Allard2067d1a2008-11-13 22:59:24 +00001277
1278/**
1279 * XML-RPC Values class
1280 *
1281 * @category XML-RPC
Derek Jonesf4a4bd82011-10-20 12:18:42 -05001282 * @author EllisLab Dev Team
Derek Allard2067d1a2008-11-13 22:59:24 +00001283 * @link http://codeigniter.com/user_guide/libraries/xmlrpc.html
1284 */
1285class XML_RPC_Values extends CI_Xmlrpc
1286{
Andrey Andreeva30faf92011-12-25 18:15:34 +02001287 public $me = array();
1288 public $mytype = 0;
Derek Allard2067d1a2008-11-13 22:59:24 +00001289
Andrey Andreevc8709832012-04-04 13:43:53 +03001290 /**
1291 * Constructor
1292 *
1293 * @param mixed
1294 * @param string
1295 * @return void
1296 */
Andrey Andreeva30faf92011-12-25 18:15:34 +02001297 public function __construct($val = -1, $type = '')
Barry Mienydd671972010-10-04 16:33:58 +02001298 {
Greg Akera9263282010-11-10 15:26:43 -06001299 parent::__construct();
Barry Mienydd671972010-10-04 16:33:58 +02001300
Derek Allard2067d1a2008-11-13 22:59:24 +00001301 if ($val != -1 OR $type != '')
1302 {
1303 $type = $type == '' ? 'string' : $type;
Barry Mienydd671972010-10-04 16:33:58 +02001304
Derek Allard2067d1a2008-11-13 22:59:24 +00001305 if ($this->xmlrpcTypes[$type] == 1)
1306 {
1307 $this->addScalar($val,$type);
1308 }
1309 elseif ($this->xmlrpcTypes[$type] == 2)
1310 {
1311 $this->addArray($val);
1312 }
1313 elseif ($this->xmlrpcTypes[$type] == 3)
1314 {
1315 $this->addStruct($val);
1316 }
1317 }
1318 }
1319
Andrey Andreevc8709832012-04-04 13:43:53 +03001320 // --------------------------------------------------------------------
1321
1322 /**
1323 * Add scalar value
1324 *
1325 * @param scalar
1326 * @param string
1327 * @return int
1328 */
Andrey Andreeva30faf92011-12-25 18:15:34 +02001329 public function addScalar($val, $type = 'string')
Derek Allard2067d1a2008-11-13 22:59:24 +00001330 {
1331 $typeof = $this->xmlrpcTypes[$type];
Barry Mienydd671972010-10-04 16:33:58 +02001332
Andrey Andreevc8709832012-04-04 13:43:53 +03001333 if ($this->mytype == 1)
Derek Allard2067d1a2008-11-13 22:59:24 +00001334 {
1335 echo '<strong>XML_RPC_Values</strong>: scalar can have only one value<br />';
1336 return 0;
1337 }
Barry Mienydd671972010-10-04 16:33:58 +02001338
Derek Allard2067d1a2008-11-13 22:59:24 +00001339 if ($typeof != 1)
1340 {
1341 echo '<strong>XML_RPC_Values</strong>: not a scalar type (${typeof})<br />';
1342 return 0;
1343 }
1344
1345 if ($type == $this->xmlrpcBoolean)
1346 {
Andrey Andreevc8709832012-04-04 13:43:53 +03001347 $val = (int) (strcasecmp($val,'true') === 0 OR $val === 1 OR ($val === TRUE && strcasecmp($val, 'false')));
Derek Allard2067d1a2008-11-13 22:59:24 +00001348 }
1349
1350 if ($this->mytype == 2)
1351 {
1352 // adding to an array here
1353 $ar = $this->me['array'];
1354 $ar[] = new XML_RPC_Values($val, $type);
1355 $this->me['array'] = $ar;
1356 }
1357 else
1358 {
1359 // a scalar, so set the value and remember we're scalar
1360 $this->me[$type] = $val;
1361 $this->mytype = $typeof;
1362 }
Andrey Andreevc8709832012-04-04 13:43:53 +03001363
Derek Allard2067d1a2008-11-13 22:59:24 +00001364 return 1;
1365 }
1366
Andrey Andreevc8709832012-04-04 13:43:53 +03001367 // --------------------------------------------------------------------
1368
1369 /**
1370 * Add array value
1371 *
1372 * @param array
1373 * @return int
1374 */
Andrey Andreeva30faf92011-12-25 18:15:34 +02001375 public function addArray($vals)
Derek Allard2067d1a2008-11-13 22:59:24 +00001376 {
1377 if ($this->mytype != 0)
1378 {
1379 echo '<strong>XML_RPC_Values</strong>: already initialized as a [' . $this->kindOf() . ']<br />';
1380 return 0;
1381 }
1382
1383 $this->mytype = $this->xmlrpcTypes['array'];
1384 $this->me['array'] = $vals;
1385 return 1;
1386 }
1387
Andrey Andreevc8709832012-04-04 13:43:53 +03001388 // --------------------------------------------------------------------
1389
1390 /**
1391 * Add struct value
1392 *
1393 * @param object
1394 * @return int
1395 */
Andrey Andreeva30faf92011-12-25 18:15:34 +02001396 public function addStruct($vals)
Derek Allard2067d1a2008-11-13 22:59:24 +00001397 {
1398 if ($this->mytype != 0)
1399 {
1400 echo '<strong>XML_RPC_Values</strong>: already initialized as a [' . $this->kindOf() . ']<br />';
1401 return 0;
1402 }
1403 $this->mytype = $this->xmlrpcTypes['struct'];
1404 $this->me['struct'] = $vals;
1405 return 1;
1406 }
1407
Andrey Andreevc8709832012-04-04 13:43:53 +03001408 // --------------------------------------------------------------------
1409
1410 /**
1411 * Get value type
1412 *
1413 * @return string
1414 */
Andrey Andreeva30faf92011-12-25 18:15:34 +02001415 public function kindOf()
Derek Allard2067d1a2008-11-13 22:59:24 +00001416 {
Andrey Andreevc8709832012-04-04 13:43:53 +03001417 switch ($this->mytype)
Derek Allard2067d1a2008-11-13 22:59:24 +00001418 {
Andrey Andreevc8709832012-04-04 13:43:53 +03001419 case 3: return 'struct';
1420 case 2: return 'array';
1421 case 1: return 'scalar';
1422 default: return 'undef';
Derek Allard2067d1a2008-11-13 22:59:24 +00001423 }
1424 }
1425
Andrey Andreevc8709832012-04-04 13:43:53 +03001426 // --------------------------------------------------------------------
1427
1428 /**
1429 * Serialize data
1430 *
1431 * @param string
1432 * @param mixed
1433 */
Andrey Andreeva30faf92011-12-25 18:15:34 +02001434 public function serializedata($typ, $val)
Derek Allard2067d1a2008-11-13 22:59:24 +00001435 {
1436 $rs = '';
Derek Jonesa9647e82010-03-02 22:59:07 -06001437
Andrey Andreevc8709832012-04-04 13:43:53 +03001438 switch ($this->xmlrpcTypes[$typ])
Derek Allard2067d1a2008-11-13 22:59:24 +00001439 {
1440 case 3:
1441 // struct
1442 $rs .= "<struct>\n";
1443 reset($val);
Pascal Kriete14287f32011-02-14 13:39:34 -05001444 while (list($key2, $val2) = each($val))
Derek Allard2067d1a2008-11-13 22:59:24 +00001445 {
Andrey Andreeva30faf92011-12-25 18:15:34 +02001446 $rs .= "<member>\n<name>{$key2}</name>\n".$this->serializeval($val2)."</member>\n";
Derek Allard2067d1a2008-11-13 22:59:24 +00001447 }
1448 $rs .= '</struct>';
Andrey Andreevc8709832012-04-04 13:43:53 +03001449 break;
Derek Allard2067d1a2008-11-13 22:59:24 +00001450 case 2:
1451 // array
1452 $rs .= "<array>\n<data>\n";
Andrey Andreevc8709832012-04-04 13:43:53 +03001453 for ($i = 0, $c = count($val); $i < $c; $i++)
Derek Allard2067d1a2008-11-13 22:59:24 +00001454 {
1455 $rs .= $this->serializeval($val[$i]);
1456 }
Andrey Andreeva30faf92011-12-25 18:15:34 +02001457 $rs .= "</data>\n</array>\n";
Derek Allard2067d1a2008-11-13 22:59:24 +00001458 break;
1459 case 1:
1460 // others
1461 switch ($typ)
1462 {
1463 case $this->xmlrpcBase64:
Andrey Andreevc8709832012-04-04 13:43:53 +03001464 $rs .= '<'.$typ.'>'.base64_encode( (string) $val).'</'.$typ.">\n";
1465 break;
Derek Allard2067d1a2008-11-13 22:59:24 +00001466 case $this->xmlrpcBoolean:
Andrey Andreevc8709832012-04-04 13:43:53 +03001467 $rs .= '<'.$typ.'>'.( (bool) $val ? '1' : '0').'</'.$typ.">\n";
1468 break;
Derek Allard2067d1a2008-11-13 22:59:24 +00001469 case $this->xmlrpcString:
Andrey Andreevc8709832012-04-04 13:43:53 +03001470 $rs .= '<'.$typ.'>'.htmlspecialchars( (string) $val).'</'.$typ.">\n";
1471 break;
Derek Allard2067d1a2008-11-13 22:59:24 +00001472 default:
Andrey Andreevc8709832012-04-04 13:43:53 +03001473 $rs .= '<'.$typ.'>'.$val.'</'.$typ.">\n";
1474 break;
Derek Allard2067d1a2008-11-13 22:59:24 +00001475 }
1476 default:
Andrey Andreevc8709832012-04-04 13:43:53 +03001477 break;
Derek Allard2067d1a2008-11-13 22:59:24 +00001478 }
Andrey Andreevc8709832012-04-04 13:43:53 +03001479
Derek Allard2067d1a2008-11-13 22:59:24 +00001480 return $rs;
1481 }
1482
Andrey Andreevc8709832012-04-04 13:43:53 +03001483 // --------------------------------------------------------------------
1484
1485 /**
1486 * Serialize class
1487 *
1488 * @return string
1489 */
Andrey Andreeva30faf92011-12-25 18:15:34 +02001490 public function serialize_class()
Derek Allard2067d1a2008-11-13 22:59:24 +00001491 {
1492 return $this->serializeval($this);
1493 }
1494
Andrey Andreevc8709832012-04-04 13:43:53 +03001495 // --------------------------------------------------------------------
1496
1497 /**
1498 * Serialize value
1499 *
1500 * @param object
1501 * @return string
1502 */
Andrey Andreeva30faf92011-12-25 18:15:34 +02001503 public function serializeval($o)
Derek Allard2067d1a2008-11-13 22:59:24 +00001504 {
1505 $ar = $o->me;
1506 reset($ar);
Barry Mienydd671972010-10-04 16:33:58 +02001507
Derek Allard2067d1a2008-11-13 22:59:24 +00001508 list($typ, $val) = each($ar);
Andrey Andreeva30faf92011-12-25 18:15:34 +02001509 return "<value>\n".$this->serializedata($typ, $val)."</value>\n";
Derek Allard2067d1a2008-11-13 22:59:24 +00001510 }
Barry Mienydd671972010-10-04 16:33:58 +02001511
Andrey Andreevc8709832012-04-04 13:43:53 +03001512 // --------------------------------------------------------------------
1513
1514 /**
1515 * Scalar value
1516 *
1517 * @return mixed
1518 */
Andrey Andreeva30faf92011-12-25 18:15:34 +02001519 public function scalarval()
Derek Allard2067d1a2008-11-13 22:59:24 +00001520 {
1521 reset($this->me);
Andrey Andreevadc11752011-12-30 14:46:08 +02001522 return current($this->me);
Derek Allard2067d1a2008-11-13 22:59:24 +00001523 }
1524
Andrey Andreevc8709832012-04-04 13:43:53 +03001525 // --------------------------------------------------------------------
Derek Allard2067d1a2008-11-13 22:59:24 +00001526
Andrey Andreevc8709832012-04-04 13:43:53 +03001527 /**
1528 * Encode time in ISO-8601 form.
1529 * Useful for sending time in XML-RPC
1530 *
1531 * @param int unix timestamp
1532 * @param bool
1533 * @return string
1534 */
1535 public function iso8601_encode($time, $utc = FALSE)
Barry Mienydd671972010-10-04 16:33:58 +02001536 {
Andrey Andreev62090152011-12-30 12:49:27 +02001537 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 +00001538 }
Barry Mienydd671972010-10-04 16:33:58 +02001539
Andrey Andreevc8709832012-04-04 13:43:53 +03001540} // END XML_RPC_Values Class
Derek Allard2067d1a2008-11-13 22:59:24 +00001541
1542/* End of file Xmlrpc.php */
Andrey Andreev8f50b6b2012-03-28 14:12:09 +03001543/* Location: ./system/libraries/Xmlrpc.php */