Subversion-Projekte lars-tiefland.ci

Revision

Revision 68 | Revision 2049 | Zur aktuellen Revision | Details | Vergleich mit vorheriger | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
68 lars 1
<?php
2
/**
3
 * CodeIgniter
4
 *
5
 * An open source application development framework for PHP
6
 *
7
 * This content is released under the MIT License (MIT)
8
 *
9
 * Copyright (c) 2014 - 2016, British Columbia Institute of Technology
10
 *
11
 * Permission is hereby granted, free of charge, to any person obtaining a copy
12
 * of this software and associated documentation files (the "Software"), to deal
13
 * in the Software without restriction, including without limitation the rights
14
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
 * copies of the Software, and to permit persons to whom the Software is
16
 * furnished to do so, subject to the following conditions:
17
 *
18
 * The above copyright notice and this permission notice shall be included in
19
 * all copies or substantial portions of the Software.
20
 *
21
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27
 * THE SOFTWARE.
28
 *
29
 * @package	CodeIgniter
30
 * @author	EllisLab Dev Team
31
 * @copyright	Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
32
 * @copyright	Copyright (c) 2014 - 2016, British Columbia Institute of Technology (http://bcit.ca/)
33
 * @license	http://opensource.org/licenses/MIT	MIT License
34
 * @link	https://codeigniter.com
35
 * @since	Version 1.0.0
36
 * @filesource
37
 */
38
defined('BASEPATH') OR exit('No direct script access allowed');
39
 
40
if ( ! function_exists('xml_parser_create'))
41
{
42
	show_error('Your PHP installation does not support XML');
43
}
44
 
45
// ------------------------------------------------------------------------
46
 
47
/**
48
 * XML-RPC request handler class
49
 *
50
 * @package		CodeIgniter
51
 * @subpackage	Libraries
52
 * @category	XML-RPC
53
 * @author		EllisLab Dev Team
54
 * @link		https://codeigniter.com/user_guide/libraries/xmlrpc.html
55
 */
56
class CI_Xmlrpc {
57
 
58
	/**
59
	 * Debug flag
60
	 *
61
	 * @var	bool
62
	 */
63
	public $debug		= FALSE;
64
 
65
	/**
66
	 * I4 data type
67
	 *
68
	 * @var	string
69
	 */
70
	public $xmlrpcI4	= 'i4';
71
 
72
	/**
73
	 * Integer data type
74
	 *
75
	 * @var	string
76
	 */
77
	public $xmlrpcInt	= 'int';
78
 
79
	/**
80
	 * Boolean data type
81
	 *
82
	 * @var	string
83
	 */
84
	public $xmlrpcBoolean	= 'boolean';
85
 
86
	/**
87
	 * Double data type
88
	 *
89
	 * @var	string
90
	 */
91
	public $xmlrpcDouble	= 'double';
92
 
93
	/**
94
	 * String data type
95
	 *
96
	 * @var	string
97
	 */
98
	public $xmlrpcString	= 'string';
99
 
100
	/**
101
	 * DateTime format
102
	 *
103
	 * @var	string
104
	 */
105
	public $xmlrpcDateTime	= 'dateTime.iso8601';
106
 
107
	/**
108
	 * Base64 data type
109
	 *
110
	 * @var	string
111
	 */
112
	public $xmlrpcBase64	= 'base64';
113
 
114
	/**
115
	 * Array data type
116
	 *
117
	 * @var	string
118
	 */
119
	public $xmlrpcArray	= 'array';
120
 
121
	/**
122
	 * Struct data type
123
	 *
124
	 * @var	string
125
	 */
126
	public $xmlrpcStruct	= 'struct';
127
 
128
	/**
129
	 * Data types list
130
	 *
131
	 * @var	array
132
	 */
133
	public $xmlrpcTypes	= array();
134
 
135
	/**
136
	 * Valid parents list
137
	 *
138
	 * @var	array
139
	 */
140
	public $valid_parents	= array();
141
 
142
	/**
143
	 * Response error numbers list
144
	 *
145
	 * @var	array
146
	 */
147
	public $xmlrpcerr		= array();
148
 
149
	/**
150
	 * Response error messages list
151
	 *
152
	 * @var	string[]
153
	 */
154
	public $xmlrpcstr		= array();
155
 
156
	/**
157
	 * Encoding charset
158
	 *
159
	 * @var	string
160
	 */
161
	public $xmlrpc_defencoding	= 'UTF-8';
162
 
163
	/**
164
	 * XML-RPC client name
165
	 *
166
	 * @var	string
167
	 */
168
	public $xmlrpcName		= 'XML-RPC for CodeIgniter';
169
 
170
	/**
171
	 * XML-RPC version
172
	 *
173
	 * @var	string
174
	 */
175
	public $xmlrpcVersion		= '1.1';
176
 
177
	/**
178
	 * Start of user errors
179
	 *
180
	 * @var	int
181
	 */
182
	public $xmlrpcerruser		= 800;
183
 
184
	/**
185
	 * Start of XML parse errors
186
	 *
187
	 * @var	int
188
	 */
189
	public $xmlrpcerrxml		= 100;
190
 
191
	/**
192
	 * Backslash replacement value
193
	 *
194
	 * @var	string
195
	 */
196
	public $xmlrpc_backslash	= '';
197
 
198
	/**
199
	 * XML-RPC Client object
200
	 *
201
	 * @var	object
202
	 */
203
	public $client;
204
 
205
	/**
206
	 * XML-RPC Method name
207
	 *
208
	 * @var	string
209
	 */
210
	public $method;
211
 
212
	/**
213
	 * XML-RPC Data
214
	 *
215
	 * @var	array
216
	 */
217
	public $data;
218
 
219
	/**
220
	 * XML-RPC Message
221
	 *
222
	 * @var	string
223
	 */
224
	public $message			= '';
225
 
226
	/**
227
	 * Request error message
228
	 *
229
	 * @var	string
230
	 */
231
	public $error			= '';
232
 
233
	/**
234
	 * XML-RPC result object
235
	 *
236
	 * @var	object
237
	 */
238
	public $result;
239
 
240
	/**
241
	 * XML-RPC Reponse
242
	 *
243
	 * @var	array
244
	 */
245
	public $response		= array(); // Response from remote server
246
 
247
	/**
248
	 * XSS Filter flag
249
	 *
250
	 * @var	bool
251
	 */
252
	public $xss_clean		= TRUE;
253
 
254
	// --------------------------------------------------------------------
255
 
256
	/**
257
	 * Constructor
258
	 *
259
	 * Initializes property default values
260
	 *
261
	 * @param	array	$config
262
	 * @return	void
263
	 */
264
	public function __construct($config = array())
265
	{
266
		$this->xmlrpc_backslash = chr(92).chr(92);
267
 
268
		// Types for info sent back and forth
269
		$this->xmlrpcTypes = array(
270
			$this->xmlrpcI4	 		=> '1',
271
			$this->xmlrpcInt		=> '1',
272
			$this->xmlrpcBoolean	=> '1',
273
			$this->xmlrpcString		=> '1',
274
			$this->xmlrpcDouble		=> '1',
275
			$this->xmlrpcDateTime	=> '1',
276
			$this->xmlrpcBase64		=> '1',
277
			$this->xmlrpcArray		=> '2',
278
			$this->xmlrpcStruct		=> '3'
279
		);
280
 
281
		// Array of Valid Parents for Various XML-RPC elements
282
		$this->valid_parents = array('BOOLEAN' => array('VALUE'),
283
			'I4'				=> array('VALUE'),
284
			'INT'				=> array('VALUE'),
285
			'STRING'			=> array('VALUE'),
286
			'DOUBLE'			=> array('VALUE'),
287
			'DATETIME.ISO8601'	=> array('VALUE'),
288
			'BASE64'			=> array('VALUE'),
289
			'ARRAY'			=> array('VALUE'),
290
			'STRUCT'			=> array('VALUE'),
291
			'PARAM'			=> array('PARAMS'),
292
			'METHODNAME'		=> array('METHODCALL'),
293
			'PARAMS'			=> array('METHODCALL', 'METHODRESPONSE'),
294
			'MEMBER'			=> array('STRUCT'),
295
			'NAME'				=> array('MEMBER'),
296
			'DATA'				=> array('ARRAY'),
297
			'FAULT'			=> array('METHODRESPONSE'),
298
			'VALUE'			=> array('MEMBER', 'DATA', 'PARAM', 'FAULT')
299
		);
300
 
301
		// XML-RPC Responses
302
		$this->xmlrpcerr['unknown_method'] = '1';
303
		$this->xmlrpcstr['unknown_method'] = 'This is not a known method for this XML-RPC Server';
304
		$this->xmlrpcerr['invalid_return'] = '2';
305
		$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.';
306
		$this->xmlrpcerr['incorrect_params'] = '3';
307
		$this->xmlrpcstr['incorrect_params'] = 'Incorrect parameters were passed to method';
308
		$this->xmlrpcerr['introspect_unknown'] = '4';
309
		$this->xmlrpcstr['introspect_unknown'] = 'Cannot inspect signature for request: method unknown';
310
		$this->xmlrpcerr['http_error'] = '5';
311
		$this->xmlrpcstr['http_error'] = "Did not receive a '200 OK' response from remote server.";
312
		$this->xmlrpcerr['no_data'] = '6';
313
		$this->xmlrpcstr['no_data'] = 'No data received from server.';
314
 
315
		$this->initialize($config);
316
 
317
		log_message('info', 'XML-RPC Class Initialized');
318
	}
319
 
320
	// --------------------------------------------------------------------
321
 
322
	/**
323
	 * Initialize
324
	 *
325
	 * @param	array	$config
326
	 * @return	void
327
	 */
328
	public function initialize($config = array())
329
	{
330
		if (count($config) > 0)
331
		{
332
			foreach ($config as $key => $val)
333
			{
334
				if (isset($this->$key))
335
				{
336
					$this->$key = $val;
337
				}
338
			}
339
		}
340
	}
341
 
342
	// --------------------------------------------------------------------
343
 
344
	/**
345
	 * Parse server URL
346
	 *
347
	 * @param	string	$url
348
	 * @param	int	$port
349
	 * @param	string	$proxy
350
	 * @param	int	$proxy_port
351
	 * @return	void
352
	 */
353
	public function server($url, $port = 80, $proxy = FALSE, $proxy_port = 8080)
354
	{
1257 lars 355
		if (stripos($url, 'http') !== 0)
68 lars 356
		{
357
			$url = 'http://'.$url;
358
		}
359
 
360
		$parts = parse_url($url);
361
 
362
		if (isset($parts['user'], $parts['pass']))
363
		{
364
			$parts['host'] = $parts['user'].':'.$parts['pass'].'@'.$parts['host'];
365
		}
366
 
367
		$path = isset($parts['path']) ? $parts['path'] : '/';
368
 
369
		if ( ! empty($parts['query']))
370
		{
371
			$path .= '?'.$parts['query'];
372
		}
373
 
374
		$this->client = new XML_RPC_Client($path, $parts['host'], $port, $proxy, $proxy_port);
375
	}
376
 
377
	// --------------------------------------------------------------------
378
 
379
	/**
380
	 * Set Timeout
381
	 *
382
	 * @param	int	$seconds
383
	 * @return	void
384
	 */
385
	public function timeout($seconds = 5)
386
	{
387
		if ($this->client !== NULL && is_int($seconds))
388
		{
389
			$this->client->timeout = $seconds;
390
		}
391
	}
392
 
393
	// --------------------------------------------------------------------
394
 
395
	/**
396
	 * Set Methods
397
	 *
398
	 * @param	string	$function	Method name
399
	 * @return	void
400
	 */
401
	public function method($function)
402
	{
403
		$this->method = $function;
404
	}
405
 
406
	// --------------------------------------------------------------------
407
 
408
	/**
409
	 * Take Array of Data and Create Objects
410
	 *
411
	 * @param	array	$incoming
412
	 * @return	void
413
	 */
414
	public function request($incoming)
415
	{
416
		if ( ! is_array($incoming))
417
		{
418
			// Send Error
419
			return;
420
		}
421
 
422
		$this->data = array();
423
 
424
		foreach ($incoming as $key => $value)
425
		{
426
			$this->data[$key] = $this->values_parsing($value);
427
		}
428
	}
429
 
430
	// --------------------------------------------------------------------
431
 
432
	/**
433
	 * Set Debug
434
	 *
435
	 * @param	bool	$flag
436
	 * @return	void
437
	 */
438
	public function set_debug($flag = TRUE)
439
	{
440
		$this->debug = ($flag === TRUE);
441
	}
442
 
443
	// --------------------------------------------------------------------
444
 
445
	/**
446
	 * Values Parsing
447
	 *
448
	 * @param	mixed	$value
449
	 * @return	object
450
	 */
451
	public function values_parsing($value)
452
	{
453
		if (is_array($value) && array_key_exists(0, $value))
454
		{
455
			if ( ! isset($value[1], $this->xmlrpcTypes[$value[1]]))
456
			{
457
				$temp = new XML_RPC_Values($value[0], (is_array($value[0]) ? 'array' : 'string'));
458
			}
459
			else
460
			{
461
				if (is_array($value[0]) && ($value[1] === 'struct' OR $value[1] === 'array'))
462
				{
463
					while (list($k) = each($value[0]))
464
					{
465
						$value[0][$k] = $this->values_parsing($value[0][$k]);
466
					}
467
				}
468
 
469
				$temp = new XML_RPC_Values($value[0], $value[1]);
470
			}
471
		}
472
		else
473
		{
474
			$temp = new XML_RPC_Values($value, 'string');
475
		}
476
 
477
		return $temp;
478
	}
479
 
480
	// --------------------------------------------------------------------
481
 
482
	/**
483
	 * Sends XML-RPC Request
484
	 *
485
	 * @return	bool
486
	 */
487
	public function send_request()
488
	{
489
		$this->message = new XML_RPC_Message($this->method, $this->data);
490
		$this->message->debug = $this->debug;
491
 
492
		if ( ! $this->result = $this->client->send($this->message) OR ! is_object($this->result->val))
493
		{
494
			$this->error = $this->result->errstr;
495
			return FALSE;
496
		}
497
 
498
		$this->response = $this->result->decode();
499
		return TRUE;
500
	}
501
 
502
	// --------------------------------------------------------------------
503
 
504
	/**
505
	 * Returns Error
506
	 *
507
	 * @return	string
508
	 */
509
	public function display_error()
510
	{
511
		return $this->error;
512
	}
513
 
514
	// --------------------------------------------------------------------
515
 
516
	/**
517
	 * Returns Remote Server Response
518
	 *
519
	 * @return	string
520
	 */
521
	public function display_response()
522
	{
523
		return $this->response;
524
	}
525
 
526
	// --------------------------------------------------------------------
527
 
528
	/**
529
	 * Sends an Error Message for Server Request
530
	 *
531
	 * @param	int	$number
532
	 * @param	string	$message
533
	 * @return	object
534
	 */
535
	public function send_error_message($number, $message)
536
	{
537
		return new XML_RPC_Response(0, $number, $message);
538
	}
539
 
540
	// --------------------------------------------------------------------
541
 
542
	/**
543
	 * Send Response for Server Request
544
	 *
545
	 * @param	array	$response
546
	 * @return	object
547
	 */
548
	public function send_response($response)
549
	{
550
		// $response should be array of values, which will be parsed
551
		// based on their data and type into a valid group of XML-RPC values
552
		return new XML_RPC_Response($this->values_parsing($response));
553
	}
554
 
555
} // END XML_RPC Class
556
 
557
/**
558
 * XML-RPC Client class
559
 *
560
 * @category	XML-RPC
561
 * @author		EllisLab Dev Team
562
 * @link		https://codeigniter.com/user_guide/libraries/xmlrpc.html
563
 */
564
class XML_RPC_Client extends CI_Xmlrpc
565
{
566
	/**
567
	 * Path
568
	 *
569
	 * @var	string
570
	 */
571
	public $path			= '';
572
 
573
	/**
574
	 * Server hostname
575
	 *
576
	 * @var	string
577
	 */
578
	public $server			= '';
579
 
580
	/**
581
	 * Server port
582
	 *
583
	 * @var	int
584
	 */
585
	public $port			= 80;
586
 
587
	/**
588
	 *
589
	 * Server username
590
	 *
591
	 * @var	string
592
	 */
593
	public $username;
594
 
595
	/**
596
	 * Server password
597
	 *
598
	 * @var	string
599
	 */
600
	public $password;
601
 
602
	/**
603
	 * Proxy hostname
604
	 *
605
	 * @var	string
606
	 */
607
	public $proxy			= FALSE;
608
 
609
	/**
610
	 * Proxy port
611
	 *
612
	 * @var	int
613
	 */
614
	public $proxy_port		= 8080;
615
 
616
	/**
617
	 * Error number
618
	 *
619
	 * @var	string
620
	 */
621
	public $errno			= '';
622
 
623
	/**
624
	 * Error message
625
	 *
626
	 * @var	string
627
	 */
628
	public $errstring		= '';
629
 
630
	/**
631
	 * Timeout in seconds
632
	 *
633
	 * @var	int
634
	 */
635
	public $timeout		= 5;
636
 
637
	/**
638
	 * No Multicall flag
639
	 *
640
	 * @var	bool
641
	 */
642
	public $no_multicall	= FALSE;
643
 
644
	// --------------------------------------------------------------------
645
 
646
	/**
647
	 * Constructor
648
	 *
649
	 * @param	string	$path
650
	 * @param	object	$server
651
	 * @param	int	$port
652
	 * @param	string	$proxy
653
	 * @param	int	$proxy_port
654
	 * @return	void
655
	 */
656
	public function __construct($path, $server, $port = 80, $proxy = FALSE, $proxy_port = 8080)
657
	{
658
		parent::__construct();
659
 
660
		$url = parse_url('http://'.$server);
661
 
662
		if (isset($url['user'], $url['pass']))
663
		{
664
			$this->username = $url['user'];
665
			$this->password = $url['pass'];
666
		}
667
 
668
		$this->port = $port;
669
		$this->server = $url['host'];
670
		$this->path = $path;
671
		$this->proxy = $proxy;
672
		$this->proxy_port = $proxy_port;
673
	}
674
 
675
	// --------------------------------------------------------------------
676
 
677
	/**
678
	 * Send message
679
	 *
680
	 * @param	mixed	$msg
681
	 * @return	object
682
	 */
683
	public function send($msg)
684
	{
685
		if (is_array($msg))
686
		{
687
			// Multi-call disabled
688
			return new XML_RPC_Response(0, $this->xmlrpcerr['multicall_recursion'], $this->xmlrpcstr['multicall_recursion']);
689
		}
690
 
691
		return $this->sendPayload($msg);
692
	}
693
 
694
	// --------------------------------------------------------------------
695
 
696
	/**
697
	 * Send payload
698
	 *
699
	 * @param	object	$msg
700
	 * @return	object
701
	 */
702
	public function sendPayload($msg)
703
	{
704
		if ($this->proxy === FALSE)
705
		{
706
			$server = $this->server;
707
			$port = $this->port;
708
		}
709
		else
710
		{
711
			$server = $this->proxy;
712
			$port = $this->proxy_port;
713
		}
714
 
715
		$fp = @fsockopen($server, $port, $this->errno, $this->errstring, $this->timeout);
716
 
717
		if ( ! is_resource($fp))
718
		{
719
			error_log($this->xmlrpcstr['http_error']);
720
			return new XML_RPC_Response(0, $this->xmlrpcerr['http_error'], $this->xmlrpcstr['http_error']);
721
		}
722
 
723
		if (empty($msg->payload))
724
		{
725
			// $msg = XML_RPC_Messages
726
			$msg->createPayload();
727
		}
728
 
729
		$r = "\r\n";
730
		$op = 'POST '.$this->path.' HTTP/1.0'.$r
731
			.'Host: '.$this->server.$r
732
			.'Content-Type: text/xml'.$r
733
			.(isset($this->username, $this->password) ? 'Authorization: Basic '.base64_encode($this->username.':'.$this->password).$r : '')
734
			.'User-Agent: '.$this->xmlrpcName.$r
735
			.'Content-Length: '.strlen($msg->payload).$r.$r
736
			.$msg->payload;
737
 
1257 lars 738
		stream_set_timeout($fp, $this->timeout); // set timeout for subsequent operations
739
 
68 lars 740
		for ($written = $timestamp = 0, $length = strlen($op); $written < $length; $written += $result)
741
		{
742
			if (($result = fwrite($fp, substr($op, $written))) === FALSE)
743
			{
744
				break;
745
			}
746
			// See https://bugs.php.net/bug.php?id=39598 and http://php.net/manual/en/function.fwrite.php#96951
747
			elseif ($result === 0)
748
			{
749
				if ($timestamp === 0)
750
				{
751
					$timestamp = time();
752
				}
753
				elseif ($timestamp < (time() - $this->timeout))
754
				{
755
					$result = FALSE;
756
					break;
757
				}
758
			}
759
			else
760
			{
761
				$timestamp = 0;
762
			}
763
		}
764
 
765
		if ($result === FALSE)
766
		{
767
			error_log($this->xmlrpcstr['http_error']);
768
			return new XML_RPC_Response(0, $this->xmlrpcerr['http_error'], $this->xmlrpcstr['http_error']);
769
		}
770
 
771
		$resp = $msg->parseResponse($fp);
772
		fclose($fp);
773
		return $resp;
774
	}
775
 
776
} // END XML_RPC_Client Class
777
 
778
/**
779
 * XML-RPC Response class
780
 *
781
 * @category	XML-RPC
782
 * @author		EllisLab Dev Team
783
 * @link		https://codeigniter.com/user_guide/libraries/xmlrpc.html
784
 */
785
class XML_RPC_Response
786
{
787
 
788
	/**
789
	 * Value
790
	 *
791
	 * @var	mixed
792
	 */
793
	public $val		= 0;
794
 
795
	/**
796
	 * Error number
797
	 *
798
	 * @var	int
799
	 */
800
	public $errno		= 0;
801
 
802
	/**
803
	 * Error message
804
	 *
805
	 * @var	string
806
	 */
807
	public $errstr		= '';
808
 
809
	/**
810
	 * Headers list
811
	 *
812
	 * @var	array
813
	 */
814
	public $headers		= array();
815
 
816
	/**
817
	 * XSS Filter flag
818
	 *
819
	 * @var	bool
820
	 */
821
	public $xss_clean	= TRUE;
822
 
823
	// --------------------------------------------------------------------
824
 
825
	/**
826
	 * Constructor
827
	 *
828
	 * @param	mixed	$val
829
	 * @param	int	$code
830
	 * @param	string	$fstr
831
	 * @return	void
832
	 */
833
	public function __construct($val, $code = 0, $fstr = '')
834
	{
835
		if ($code !== 0)
836
		{
837
			// error
838
			$this->errno = $code;
839
			$this->errstr = htmlspecialchars($fstr,
840
							(is_php('5.4') ? ENT_XML1 | ENT_NOQUOTES : ENT_NOQUOTES),
841
							'UTF-8');
842
		}
843
		elseif ( ! is_object($val))
844
		{
845
			// programmer error, not an object
846
			error_log("Invalid type '".gettype($val)."' (value: ".$val.') passed to XML_RPC_Response. Defaulting to empty value.');
847
			$this->val = new XML_RPC_Values();
848
		}
849
		else
850
		{
851
			$this->val = $val;
852
		}
853
	}
854
 
855
	// --------------------------------------------------------------------
856
 
857
	/**
858
	 * Fault code
859
	 *
860
	 * @return	int
861
	 */
862
	public function faultCode()
863
	{
864
		return $this->errno;
865
	}
866
 
867
	// --------------------------------------------------------------------
868
 
869
	/**
870
	 * Fault string
871
	 *
872
	 * @return	string
873
	 */
874
	public function faultString()
875
	{
876
		return $this->errstr;
877
	}
878
 
879
	// --------------------------------------------------------------------
880
 
881
	/**
882
	 * Value
883
	 *
884
	 * @return	mixed
885
	 */
886
	public function value()
887
	{
888
		return $this->val;
889
	}
890
 
891
	// --------------------------------------------------------------------
892
 
893
	/**
894
	 * Prepare response
895
	 *
896
	 * @return	string	xml
897
	 */
898
	public function prepare_response()
899
	{
900
		return "<methodResponse>\n"
901
			.($this->errno
902
				? '<fault>
903
	<value>
904
		<struct>
905
			<member>
906
				<name>faultCode</name>
907
				<value><int>'.$this->errno.'</int></value>
908
			</member>
909
			<member>
910
				<name>faultString</name>
911
				<value><string>'.$this->errstr.'</string></value>
912
			</member>
913
		</struct>
914
	</value>
915
</fault>'
916
				: "<params>\n<param>\n".$this->val->serialize_class()."</param>\n</params>")
917
			."\n</methodResponse>";
918
	}
919
 
920
	// --------------------------------------------------------------------
921
 
922
	/**
923
	 * Decode
924
	 *
925
	 * @param	mixed	$array
926
	 * @return	array
927
	 */
928
	public function decode($array = NULL)
929
	{
930
		$CI =& get_instance();
931
 
932
		if (is_array($array))
933
		{
934
			while (list($key) = each($array))
935
			{
936
				if (is_array($array[$key]))
937
				{
938
					$array[$key] = $this->decode($array[$key]);
939
				}
940
				elseif ($this->xss_clean)
941
				{
942
					$array[$key] = $CI->security->xss_clean($array[$key]);
943
				}
944
			}
945
 
946
			return $array;
947
		}
948
 
949
		$result = $this->xmlrpc_decoder($this->val);
950
 
951
		if (is_array($result))
952
		{
953
			$result = $this->decode($result);
954
		}
955
		elseif ($this->xss_clean)
956
		{
957
			$result = $CI->security->xss_clean($result);
958
		}
959
 
960
		return $result;
961
	}
962
 
963
	// --------------------------------------------------------------------
964
 
965
	/**
966
	 * XML-RPC Object to PHP Types
967
	 *
968
	 * @param	object
969
	 * @return	array
970
	 */
971
	public function xmlrpc_decoder($xmlrpc_val)
972
	{
973
		$kind = $xmlrpc_val->kindOf();
974
 
975
		if ($kind === 'scalar')
976
		{
977
			return $xmlrpc_val->scalarval();
978
		}
979
		elseif ($kind === 'array')
980
		{
981
			reset($xmlrpc_val->me);
982
			$b = current($xmlrpc_val->me);
983
			$arr = array();
984
 
985
			for ($i = 0, $size = count($b); $i < $size; $i++)
986
			{
987
				$arr[] = $this->xmlrpc_decoder($xmlrpc_val->me['array'][$i]);
988
			}
989
			return $arr;
990
		}
991
		elseif ($kind === 'struct')
992
		{
993
			reset($xmlrpc_val->me['struct']);
994
			$arr = array();
995
 
996
			while (list($key,$value) = each($xmlrpc_val->me['struct']))
997
			{
998
				$arr[$key] = $this->xmlrpc_decoder($value);
999
			}
1000
			return $arr;
1001
		}
1002
	}
1003
 
1004
	// --------------------------------------------------------------------
1005
 
1006
	/**
1007
	 * ISO-8601 time to server or UTC time
1008
	 *
1009
	 * @param	string
1010
	 * @param	bool
1011
	 * @return	int	unix timestamp
1012
	 */
1013
	public function iso8601_decode($time, $utc = FALSE)
1014
	{
1015
		// Return a time in the localtime, or UTC
1016
		$t = 0;
1017
		if (preg_match('/([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})/', $time, $regs))
1018
		{
1019
			$fnc = ($utc === TRUE) ? 'gmmktime' : 'mktime';
1020
			$t = $fnc($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
1021
		}
1022
		return $t;
1023
	}
1024
 
1025
} // END XML_RPC_Response Class
1026
 
1027
/**
1028
 * XML-RPC Message class
1029
 *
1030
 * @category	XML-RPC
1031
 * @author		EllisLab Dev Team
1032
 * @link		https://codeigniter.com/user_guide/libraries/xmlrpc.html
1033
 */
1034
class XML_RPC_Message extends CI_Xmlrpc
1035
{
1036
 
1037
	/**
1038
	 * Payload
1039
	 *
1040
	 * @var	string
1041
	 */
1042
	public $payload;
1043
 
1044
	/**
1045
	 * Method name
1046
	 *
1047
	 * @var	string
1048
	 */
1049
	public $method_name;
1050
 
1051
	/**
1052
	 * Parameter list
1053
	 *
1054
	 * @var	array
1055
	 */
1056
	public $params		= array();
1057
 
1058
	/**
1059
	 * XH?
1060
	 *
1061
	 * @var	array
1062
	 */
1063
	public $xh		= array();
1064
 
1065
	// --------------------------------------------------------------------
1066
 
1067
	/**
1068
	 * Constructor
1069
	 *
1070
	 * @param	string	$method
1071
	 * @param	array	$pars
1072
	 * @return	void
1073
	 */
1074
	public function __construct($method, $pars = FALSE)
1075
	{
1076
		parent::__construct();
1077
 
1078
		$this->method_name = $method;
1079
		if (is_array($pars) && count($pars) > 0)
1080
		{
1081
			for ($i = 0, $c = count($pars); $i < $c; $i++)
1082
			{
1083
				// $pars[$i] = XML_RPC_Values
1084
				$this->params[] = $pars[$i];
1085
			}
1086
		}
1087
	}
1088
 
1089
	// --------------------------------------------------------------------
1090
 
1091
	/**
1092
	 * Create Payload to Send
1093
	 *
1094
	 * @return	void
1095
	 */
1096
	public function createPayload()
1097
	{
1098
		$this->payload = '<?xml version="1.0"?'.">\r\n<methodCall>\r\n"
1099
				.'<methodName>'.$this->method_name."</methodName>\r\n"
1100
				."<params>\r\n";
1101
 
1102
		for ($i = 0, $c = count($this->params); $i < $c; $i++)
1103
		{
1104
			// $p = XML_RPC_Values
1105
			$p = $this->params[$i];
1106
			$this->payload .= "<param>\r\n".$p->serialize_class()."</param>\r\n";
1107
		}
1108
 
1109
		$this->payload .= "</params>\r\n</methodCall>\r\n";
1110
	}
1111
 
1112
	// --------------------------------------------------------------------
1113
 
1114
	/**
1115
	 * Parse External XML-RPC Server's Response
1116
	 *
1117
	 * @param	resource
1118
	 * @return	object
1119
	 */
1120
	public function parseResponse($fp)
1121
	{
1122
		$data = '';
1123
 
1124
		while ($datum = fread($fp, 4096))
1125
		{
1126
			$data .= $datum;
1127
		}
1128
 
1129
		// Display HTTP content for debugging
1130
		if ($this->debug === TRUE)
1131
		{
1132
			echo "<pre>---DATA---\n".htmlspecialchars($data)."\n---END DATA---\n\n</pre>";
1133
		}
1134
 
1135
		// Check for data
1136
		if ($data === '')
1137
		{
1138
			error_log($this->xmlrpcstr['no_data']);
1139
			return new XML_RPC_Response(0, $this->xmlrpcerr['no_data'], $this->xmlrpcstr['no_data']);
1140
		}
1141
 
1142
		// Check for HTTP 200 Response
1143
		if (strpos($data, 'HTTP') === 0 && ! preg_match('/^HTTP\/[0-9\.]+ 200 /', $data))
1144
		{
1145
			$errstr = substr($data, 0, strpos($data, "\n")-1);
1146
			return new XML_RPC_Response(0, $this->xmlrpcerr['http_error'], $this->xmlrpcstr['http_error'].' ('.$errstr.')');
1147
		}
1148
 
1149
		//-------------------------------------
1150
		// Create and Set Up XML Parser
1151
		//-------------------------------------
1152
 
1153
		$parser = xml_parser_create($this->xmlrpc_defencoding);
1154
		$pname = (string) $parser;
1155
		$this->xh[$pname] = array(
1156
			'isf'		=> 0,
1157
			'ac'		=> '',
1158
			'headers'	=> array(),
1159
			'stack'		=> array(),
1160
			'valuestack'	=> array(),
1161
			'isf_reason'	=> 0
1162
		);
1163
 
1164
		xml_set_object($parser, $this);
1165
		xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, TRUE);
1166
		xml_set_element_handler($parser, 'open_tag', 'closing_tag');
1167
		xml_set_character_data_handler($parser, 'character_data');
1168
		//xml_set_default_handler($parser, 'default_handler');
1169
 
1170
		// Get headers
1171
		$lines = explode("\r\n", $data);
1172
		while (($line = array_shift($lines)))
1173
		{
1174
			if (strlen($line) < 1)
1175
			{
1176
				break;
1177
			}
1178
			$this->xh[$pname]['headers'][] = $line;
1179
		}
1180
		$data = implode("\r\n", $lines);
1181
 
1182
		// Parse XML data
1183
		if ( ! xml_parse($parser, $data, count($data)))
1184
		{
1185
			$errstr = sprintf('XML error: %s at line %d',
1186
						xml_error_string(xml_get_error_code($parser)),
1187
						xml_get_current_line_number($parser));
1188
 
1189
			$r = new XML_RPC_Response(0, $this->xmlrpcerr['invalid_return'], $this->xmlrpcstr['invalid_return']);
1190
			xml_parser_free($parser);
1191
			return $r;
1192
		}
1193
		xml_parser_free($parser);
1194
 
1195
		// Got ourselves some badness, it seems
1196
		if ($this->xh[$pname]['isf'] > 1)
1197
		{
1198
			if ($this->debug === TRUE)
1199
			{
1200
				echo "---Invalid Return---\n".$this->xh[$pname]['isf_reason']."---Invalid Return---\n\n";
1201
			}
1202
 
1203
			return new XML_RPC_Response(0, $this->xmlrpcerr['invalid_return'], $this->xmlrpcstr['invalid_return'].' '.$this->xh[$pname]['isf_reason']);
1204
		}
1205
		elseif ( ! is_object($this->xh[$pname]['value']))
1206
		{
1207
			return new XML_RPC_Response(0, $this->xmlrpcerr['invalid_return'], $this->xmlrpcstr['invalid_return'].' '.$this->xh[$pname]['isf_reason']);
1208
		}
1209
 
1210
		// Display XML content for debugging
1211
		if ($this->debug === TRUE)
1212
		{
1213
			echo '<pre>';
1214
 
1215
			if (count($this->xh[$pname]['headers'] > 0))
1216
			{
1217
				echo "---HEADERS---\n";
1218
				foreach ($this->xh[$pname]['headers'] as $header)
1219
				{
1220
					echo $header."\n";
1221
				}
1222
				echo "---END HEADERS---\n\n";
1223
			}
1224
 
1225
			echo "---DATA---\n".htmlspecialchars($data)."\n---END DATA---\n\n---PARSED---\n";
1226
			var_dump($this->xh[$pname]['value']);
1227
			echo "\n---END PARSED---</pre>";
1228
		}
1229
 
1230
		// Send response
1231
		$v = $this->xh[$pname]['value'];
1232
		if ($this->xh[$pname]['isf'])
1233
		{
1234
			$errno_v = $v->me['struct']['faultCode'];
1235
			$errstr_v = $v->me['struct']['faultString'];
1236
			$errno = $errno_v->scalarval();
1237
 
1238
			if ($errno === 0)
1239
			{
1240
				// FAULT returned, errno needs to reflect that
1241
				$errno = -1;
1242
			}
1243
 
1244
			$r = new XML_RPC_Response($v, $errno, $errstr_v->scalarval());
1245
		}
1246
		else
1247
		{
1248
			$r = new XML_RPC_Response($v);
1249
		}
1250
 
1251
		$r->headers = $this->xh[$pname]['headers'];
1252
		return $r;
1253
	}
1254
 
1255
	// --------------------------------------------------------------------
1256
 
1257
	// ------------------------------------
1258
	//  Begin Return Message Parsing section
1259
	// ------------------------------------
1260
 
1261
	// quick explanation of components:
1262
	//   ac - used to accumulate values
1263
	//   isf - used to indicate a fault
1264
	//   lv - used to indicate "looking for a value": implements
1265
	//		the logic to allow values with no types to be strings
1266
	//   params - used to store parameters in method calls
1267
	//   method - used to store method name
1268
	//	 stack - array with parent tree of the xml element,
1269
	//			 used to validate the nesting of elements
1270
 
1271
	// --------------------------------------------------------------------
1272
 
1273
	/**
1274
	 * Start Element Handler
1275
	 *
1276
	 * @param	string
1277
	 * @param	string
1278
	 * @return	void
1279
	 */
1280
	public function open_tag($the_parser, $name)
1281
	{
1282
		$the_parser = (string) $the_parser;
1283
 
1284
		// If invalid nesting, then return
1285
		if ($this->xh[$the_parser]['isf'] > 1) return;
1286
 
1287
		// Evaluate and check for correct nesting of XML elements
1288
		if (count($this->xh[$the_parser]['stack']) === 0)
1289
		{
1290
			if ($name !== 'METHODRESPONSE' && $name !== 'METHODCALL')
1291
			{
1292
				$this->xh[$the_parser]['isf'] = 2;
1293
				$this->xh[$the_parser]['isf_reason'] = 'Top level XML-RPC element is missing';
1294
				return;
1295
			}
1296
		}
1297
		// not top level element: see if parent is OK
1298
		elseif ( ! in_array($this->xh[$the_parser]['stack'][0], $this->valid_parents[$name], TRUE))
1299
		{
1300
			$this->xh[$the_parser]['isf'] = 2;
1301
			$this->xh[$the_parser]['isf_reason'] = 'XML-RPC element '.$name.' cannot be child of '.$this->xh[$the_parser]['stack'][0];
1302
			return;
1303
		}
1304
 
1305
		switch ($name)
1306
		{
1307
			case 'STRUCT':
1308
			case 'ARRAY':
1309
				// Creates array for child elements
1310
				$cur_val = array('value' => array(), 'type' => $name);
1311
				array_unshift($this->xh[$the_parser]['valuestack'], $cur_val);
1312
				break;
1313
			case 'METHODNAME':
1314
			case 'NAME':
1315
				$this->xh[$the_parser]['ac'] = '';
1316
				break;
1317
			case 'FAULT':
1318
				$this->xh[$the_parser]['isf'] = 1;
1319
				break;
1320
			case 'PARAM':
1321
				$this->xh[$the_parser]['value'] = NULL;
1322
				break;
1323
			case 'VALUE':
1324
				$this->xh[$the_parser]['vt'] = 'value';
1325
				$this->xh[$the_parser]['ac'] = '';
1326
				$this->xh[$the_parser]['lv'] = 1;
1327
				break;
1328
			case 'I4':
1329
			case 'INT':
1330
			case 'STRING':
1331
			case 'BOOLEAN':
1332
			case 'DOUBLE':
1333
			case 'DATETIME.ISO8601':
1334
			case 'BASE64':
1335
				if ($this->xh[$the_parser]['vt'] !== 'value')
1336
				{
1337
					//two data elements inside a value: an error occurred!
1338
					$this->xh[$the_parser]['isf'] = 2;
1339
					$this->xh[$the_parser]['isf_reason'] = 'There is a '.$name.' element following a '
1340
										.$this->xh[$the_parser]['vt'].' element inside a single value';
1341
					return;
1342
				}
1343
 
1344
				$this->xh[$the_parser]['ac'] = '';
1345
				break;
1346
			case 'MEMBER':
1347
				// Set name of <member> to nothing to prevent errors later if no <name> is found
1348
				$this->xh[$the_parser]['valuestack'][0]['name'] = '';
1349
 
1350
				// Set NULL value to check to see if value passed for this param/member
1351
				$this->xh[$the_parser]['value'] = NULL;
1352
				break;
1353
			case 'DATA':
1354
			case 'METHODCALL':
1355
			case 'METHODRESPONSE':
1356
			case 'PARAMS':
1357
				// valid elements that add little to processing
1358
				break;
1359
			default:
1360
				/// An Invalid Element is Found, so we have trouble
1361
				$this->xh[$the_parser]['isf'] = 2;
1362
				$this->xh[$the_parser]['isf_reason'] = 'Invalid XML-RPC element found: '.$name;
1363
				break;
1364
		}
1365
 
1366
		// Add current element name to stack, to allow validation of nesting
1367
		array_unshift($this->xh[$the_parser]['stack'], $name);
1368
 
1369
		$name === 'VALUE' OR $this->xh[$the_parser]['lv'] = 0;
1370
	}
1371
 
1372
	// --------------------------------------------------------------------
1373
 
1374
	/**
1375
	 * End Element Handler
1376
	 *
1377
	 * @param	string
1378
	 * @param	string
1379
	 * @return	void
1380
	 */
1381
	public function closing_tag($the_parser, $name)
1382
	{
1383
		$the_parser = (string) $the_parser;
1384
 
1385
		if ($this->xh[$the_parser]['isf'] > 1) return;
1386
 
1387
		// Remove current element from stack and set variable
1388
		// NOTE: If the XML validates, then we do not have to worry about
1389
		// the opening and closing of elements. Nesting is checked on the opening
1390
		// tag so we be safe there as well.
1391
 
1392
		$curr_elem = array_shift($this->xh[$the_parser]['stack']);
1393
 
1394
		switch ($name)
1395
		{
1396
			case 'STRUCT':
1397
			case 'ARRAY':
1398
				$cur_val = array_shift($this->xh[$the_parser]['valuestack']);
1399
				$this->xh[$the_parser]['value'] = isset($cur_val['values']) ? $cur_val['values'] : array();
1400
				$this->xh[$the_parser]['vt']	= strtolower($name);
1401
				break;
1402
			case 'NAME':
1403
				$this->xh[$the_parser]['valuestack'][0]['name'] = $this->xh[$the_parser]['ac'];
1404
				break;
1405
			case 'BOOLEAN':
1406
			case 'I4':
1407
			case 'INT':
1408
			case 'STRING':
1409
			case 'DOUBLE':
1410
			case 'DATETIME.ISO8601':
1411
			case 'BASE64':
1412
				$this->xh[$the_parser]['vt'] = strtolower($name);
1413
 
1414
				if ($name === 'STRING')
1415
				{
1416
					$this->xh[$the_parser]['value'] = $this->xh[$the_parser]['ac'];
1417
				}
1418
				elseif ($name === 'DATETIME.ISO8601')
1419
				{
1420
					$this->xh[$the_parser]['vt']	= $this->xmlrpcDateTime;
1421
					$this->xh[$the_parser]['value'] = $this->xh[$the_parser]['ac'];
1422
				}
1423
				elseif ($name === 'BASE64')
1424
				{
1425
					$this->xh[$the_parser]['value'] = base64_decode($this->xh[$the_parser]['ac']);
1426
				}
1427
				elseif ($name === 'BOOLEAN')
1428
				{
1429
					// Translated BOOLEAN values to TRUE AND FALSE
1430
					$this->xh[$the_parser]['value'] = (bool) $this->xh[$the_parser]['ac'];
1431
				}
1432
				elseif ($name=='DOUBLE')
1433
				{
1434
					// we have a DOUBLE
1435
					// we must check that only 0123456789-.<space> are characters here
1436
					$this->xh[$the_parser]['value'] = preg_match('/^[+-]?[eE0-9\t \.]+$/', $this->xh[$the_parser]['ac'])
1437
										? (float) $this->xh[$the_parser]['ac']
1438
										: 'ERROR_NON_NUMERIC_FOUND';
1439
				}
1440
				else
1441
				{
1442
					// we have an I4/INT
1443
					// we must check that only 0123456789-<space> are characters here
1444
					$this->xh[$the_parser]['value'] = preg_match('/^[+-]?[0-9\t ]+$/', $this->xh[$the_parser]['ac'])
1445
										? (int) $this->xh[$the_parser]['ac']
1446
										: 'ERROR_NON_NUMERIC_FOUND';
1447
				}
1448
				$this->xh[$the_parser]['ac'] = '';
1449
				$this->xh[$the_parser]['lv'] = 3; // indicate we've found a value
1450
				break;
1451
			case 'VALUE':
1452
				// This if() detects if no scalar was inside <VALUE></VALUE>
1453
				if ($this->xh[$the_parser]['vt'] == 'value')
1454
				{
1455
					$this->xh[$the_parser]['value']	= $this->xh[$the_parser]['ac'];
1456
					$this->xh[$the_parser]['vt']	= $this->xmlrpcString;
1457
				}
1458
 
1459
				// build the XML-RPC value out of the data received, and substitute it
1460
				$temp = new XML_RPC_Values($this->xh[$the_parser]['value'], $this->xh[$the_parser]['vt']);
1461
 
1462
				if (count($this->xh[$the_parser]['valuestack']) && $this->xh[$the_parser]['valuestack'][0]['type'] === 'ARRAY')
1463
				{
1464
					// Array
1465
					$this->xh[$the_parser]['valuestack'][0]['values'][] = $temp;
1466
				}
1467
				else
1468
				{
1469
					// Struct
1470
					$this->xh[$the_parser]['value'] = $temp;
1471
				}
1472
				break;
1473
			case 'MEMBER':
1474
				$this->xh[$the_parser]['ac'] = '';
1475
 
1476
				// If value add to array in the stack for the last element built
1477
				if ($this->xh[$the_parser]['value'])
1478
				{
1479
					$this->xh[$the_parser]['valuestack'][0]['values'][$this->xh[$the_parser]['valuestack'][0]['name']] = $this->xh[$the_parser]['value'];
1480
				}
1481
				break;
1482
			case 'DATA':
1483
				$this->xh[$the_parser]['ac'] = '';
1484
				break;
1485
			case 'PARAM':
1486
				if ($this->xh[$the_parser]['value'])
1487
				{
1488
					$this->xh[$the_parser]['params'][] = $this->xh[$the_parser]['value'];
1489
				}
1490
				break;
1491
			case 'METHODNAME':
1492
				$this->xh[$the_parser]['method'] = ltrim($this->xh[$the_parser]['ac']);
1493
				break;
1494
			case 'PARAMS':
1495
			case 'FAULT':
1496
			case 'METHODCALL':
1497
			case 'METHORESPONSE':
1498
				// We're all good kids with nuthin' to do
1499
				break;
1500
			default:
1501
				// End of an Invalid Element. Taken care of during the opening tag though
1502
				break;
1503
		}
1504
	}
1505
 
1506
	// --------------------------------------------------------------------
1507
 
1508
	/**
1509
	 * Parse character data
1510
	 *
1511
	 * @param	string
1512
	 * @param	string
1513
	 * @return	void
1514
	 */
1515
	public function character_data($the_parser, $data)
1516
	{
1517
		$the_parser = (string) $the_parser;
1518
 
1519
		if ($this->xh[$the_parser]['isf'] > 1) return; // XML Fault found already
1520
 
1521
		// If a value has not been found
1522
		if ($this->xh[$the_parser]['lv'] !== 3)
1523
		{
1524
			if ($this->xh[$the_parser]['lv'] === 1)
1525
			{
1526
				$this->xh[$the_parser]['lv'] = 2; // Found a value
1527
			}
1528
 
1529
			if ( ! isset($this->xh[$the_parser]['ac']))
1530
			{
1531
				$this->xh[$the_parser]['ac'] = '';
1532
			}
1533
 
1534
			$this->xh[$the_parser]['ac'] .= $data;
1535
		}
1536
	}
1537
 
1538
	// --------------------------------------------------------------------
1539
 
1540
	/**
1541
	 * Add parameter
1542
	 *
1543
	 * @param	mixed
1544
	 * @return	void
1545
	 */
1546
	public function addParam($par)
1547
	{
1548
		$this->params[] = $par;
1549
	}
1550
 
1551
	// --------------------------------------------------------------------
1552
 
1553
	/**
1554
	 * Output parameters
1555
	 *
1556
	 * @param	array	$array
1557
	 * @return	array
1558
	 */
1559
	public function output_parameters(array $array = array())
1560
	{
1561
		$CI =& get_instance();
1562
 
1563
		if ( ! empty($array))
1564
		{
1565
			while (list($key) = each($array))
1566
			{
1567
				if (is_array($array[$key]))
1568
				{
1569
					$array[$key] = $this->output_parameters($array[$key]);
1570
				}
1571
				elseif ($key !== 'bits' && $this->xss_clean)
1572
				{
1573
					// 'bits' is for the MetaWeblog API image bits
1574
					// @todo - this needs to be made more general purpose
1575
					$array[$key] = $CI->security->xss_clean($array[$key]);
1576
				}
1577
			}
1578
 
1579
			return $array;
1580
		}
1581
 
1582
		$parameters = array();
1583
 
1584
		for ($i = 0, $c = count($this->params); $i < $c; $i++)
1585
		{
1586
			$a_param = $this->decode_message($this->params[$i]);
1587
 
1588
			if (is_array($a_param))
1589
			{
1590
				$parameters[] = $this->output_parameters($a_param);
1591
			}
1592
			else
1593
			{
1594
				$parameters[] = ($this->xss_clean) ? $CI->security->xss_clean($a_param) : $a_param;
1595
			}
1596
		}
1597
 
1598
		return $parameters;
1599
	}
1600
 
1601
	// --------------------------------------------------------------------
1602
 
1603
	/**
1604
	 * Decode message
1605
	 *
1606
	 * @param	object
1607
	 * @return	mixed
1608
	 */
1609
	public function decode_message($param)
1610
	{
1611
		$kind = $param->kindOf();
1612
 
1613
		if ($kind === 'scalar')
1614
		{
1615
			return $param->scalarval();
1616
		}
1617
		elseif ($kind === 'array')
1618
		{
1619
			reset($param->me);
1620
			$b = current($param->me);
1621
			$arr = array();
1622
 
1623
			for ($i = 0, $c = count($b); $i < $c; $i++)
1624
			{
1625
				$arr[] = $this->decode_message($param->me['array'][$i]);
1626
			}
1627
 
1628
			return $arr;
1629
		}
1630
		elseif ($kind === 'struct')
1631
		{
1632
			reset($param->me['struct']);
1633
			$arr = array();
1634
 
1635
			while (list($key,$value) = each($param->me['struct']))
1636
			{
1637
				$arr[$key] = $this->decode_message($value);
1638
			}
1639
 
1640
			return $arr;
1641
		}
1642
	}
1643
 
1644
} // END XML_RPC_Message Class
1645
 
1646
/**
1647
 * XML-RPC Values class
1648
 *
1649
 * @category	XML-RPC
1650
 * @author		EllisLab Dev Team
1651
 * @link		https://codeigniter.com/user_guide/libraries/xmlrpc.html
1652
 */
1653
class XML_RPC_Values extends CI_Xmlrpc
1654
{
1655
	/**
1656
	 * Value data
1657
	 *
1658
	 * @var	array
1659
	 */
1660
	public $me	= array();
1661
 
1662
	/**
1663
	 * Value type
1664
	 *
1665
	 * @var	int
1666
	 */
1667
	public $mytype	= 0;
1668
 
1669
	// --------------------------------------------------------------------
1670
 
1671
	/**
1672
	 * Constructor
1673
	 *
1674
	 * @param	mixed	$val
1675
	 * @param	string	$type
1676
	 * @return	void
1677
	 */
1678
	public function __construct($val = -1, $type = '')
1679
	{
1680
		parent::__construct();
1681
 
1682
		if ($val !== -1 OR $type !== '')
1683
		{
1684
			$type = $type === '' ? 'string' : $type;
1685
 
1686
			if ($this->xmlrpcTypes[$type] == 1)
1687
			{
1688
				$this->addScalar($val, $type);
1689
			}
1690
			elseif ($this->xmlrpcTypes[$type] == 2)
1691
			{
1692
				$this->addArray($val);
1693
			}
1694
			elseif ($this->xmlrpcTypes[$type] == 3)
1695
			{
1696
				$this->addStruct($val);
1697
			}
1698
		}
1699
	}
1700
 
1701
	// --------------------------------------------------------------------
1702
 
1703
	/**
1704
	 * Add scalar value
1705
	 *
1706
	 * @param	scalar
1707
	 * @param	string
1708
	 * @return	int
1709
	 */
1710
	public function addScalar($val, $type = 'string')
1711
	{
1712
		$typeof = $this->xmlrpcTypes[$type];
1713
 
1714
		if ($this->mytype === 1)
1715
		{
1716
			echo '<strong>XML_RPC_Values</strong>: scalar can have only one value<br />';
1717
			return 0;
1718
		}
1719
 
1720
		if ($typeof != 1)
1721
		{
1722
			echo '<strong>XML_RPC_Values</strong>: not a scalar type (${typeof})<br />';
1723
			return 0;
1724
		}
1725
 
1726
		if ($type === $this->xmlrpcBoolean)
1727
		{
1728
			$val = (int) (strcasecmp($val, 'true') === 0 OR $val === 1 OR ($val === TRUE && strcasecmp($val, 'false')));
1729
		}
1730
 
1731
		if ($this->mytype === 2)
1732
		{
1733
			// adding to an array here
1734
			$ar = $this->me['array'];
1735
			$ar[] = new XML_RPC_Values($val, $type);
1736
			$this->me['array'] = $ar;
1737
		}
1738
		else
1739
		{
1740
			// a scalar, so set the value and remember we're scalar
1741
			$this->me[$type] = $val;
1742
			$this->mytype = $typeof;
1743
		}
1744
 
1745
		return 1;
1746
	}
1747
 
1748
	// --------------------------------------------------------------------
1749
 
1750
	/**
1751
	 * Add array value
1752
	 *
1753
	 * @param	array
1754
	 * @return	int
1755
	 */
1756
	public function addArray($vals)
1757
	{
1758
		if ($this->mytype !== 0)
1759
		{
1760
			echo '<strong>XML_RPC_Values</strong>: already initialized as a ['.$this->kindOf().']<br />';
1761
			return 0;
1762
		}
1763
 
1764
		$this->mytype = $this->xmlrpcTypes['array'];
1765
		$this->me['array'] = $vals;
1766
		return 1;
1767
	}
1768
 
1769
	// --------------------------------------------------------------------
1770
 
1771
	/**
1772
	 * Add struct value
1773
	 *
1774
	 * @param	object
1775
	 * @return	int
1776
	 */
1777
	public function addStruct($vals)
1778
	{
1779
		if ($this->mytype !== 0)
1780
		{
1781
			echo '<strong>XML_RPC_Values</strong>: already initialized as a ['.$this->kindOf().']<br />';
1782
			return 0;
1783
		}
1784
		$this->mytype = $this->xmlrpcTypes['struct'];
1785
		$this->me['struct'] = $vals;
1786
		return 1;
1787
	}
1788
 
1789
	// --------------------------------------------------------------------
1790
 
1791
	/**
1792
	 * Get value type
1793
	 *
1794
	 * @return	string
1795
	 */
1796
	public function kindOf()
1797
	{
1798
		switch ($this->mytype)
1799
		{
1800
			case 3: return 'struct';
1801
			case 2: return 'array';
1802
			case 1: return 'scalar';
1803
			default: return 'undef';
1804
		}
1805
	}
1806
 
1807
	// --------------------------------------------------------------------
1808
 
1809
	/**
1810
	 * Serialize data
1811
	 *
1812
	 * @param	string
1813
	 * @param	mixed
1814
	 * @return	string
1815
	 */
1816
	public function serializedata($typ, $val)
1817
	{
1818
		$rs = '';
1819
 
1820
		switch ($this->xmlrpcTypes[$typ])
1821
		{
1822
			case 3:
1823
				// struct
1824
				$rs .= "<struct>\n";
1825
				reset($val);
1826
				while (list($key2, $val2) = each($val))
1827
				{
1828
					$rs .= "<member>\n<name>{$key2}</name>\n".$this->serializeval($val2)."</member>\n";
1829
				}
1830
				$rs .= '</struct>';
1831
				break;
1832
			case 2:
1833
				// array
1834
				$rs .= "<array>\n<data>\n";
1835
				for ($i = 0, $c = count($val); $i < $c; $i++)
1836
				{
1837
					$rs .= $this->serializeval($val[$i]);
1838
				}
1839
				$rs .= "</data>\n</array>\n";
1840
				break;
1841
			case 1:
1842
				// others
1843
				switch ($typ)
1844
				{
1845
					case $this->xmlrpcBase64:
1846
						$rs .= '<'.$typ.'>'.base64_encode( (string) $val).'</'.$typ.">\n";
1847
						break;
1848
					case $this->xmlrpcBoolean:
1849
						$rs .= '<'.$typ.'>'.( (bool) $val ? '1' : '0').'</'.$typ.">\n";
1850
						break;
1851
					case $this->xmlrpcString:
1852
						$rs .= '<'.$typ.'>'.htmlspecialchars( (string) $val).'</'.$typ.">\n";
1853
						break;
1854
					default:
1855
						$rs .= '<'.$typ.'>'.$val.'</'.$typ.">\n";
1856
						break;
1857
				}
1858
			default:
1859
				break;
1860
		}
1861
 
1862
		return $rs;
1863
	}
1864
 
1865
	// --------------------------------------------------------------------
1866
 
1867
	/**
1868
	 * Serialize class
1869
	 *
1870
	 * @return	string
1871
	 */
1872
	public function serialize_class()
1873
	{
1874
		return $this->serializeval($this);
1875
	}
1876
 
1877
	// --------------------------------------------------------------------
1878
 
1879
	/**
1880
	 * Serialize value
1881
	 *
1882
	 * @param	object
1883
	 * @return	string
1884
	 */
1885
	public function serializeval($o)
1886
	{
1887
		$ar = $o->me;
1888
		reset($ar);
1889
 
1890
		list($typ, $val) = each($ar);
1891
		return "<value>\n".$this->serializedata($typ, $val)."</value>\n";
1892
	}
1893
 
1894
	// --------------------------------------------------------------------
1895
 
1896
	/**
1897
	 * Scalar value
1898
	 *
1899
	 * @return	mixed
1900
	 */
1901
	public function scalarval()
1902
	{
1903
		reset($this->me);
1904
		return current($this->me);
1905
	}
1906
 
1907
	// --------------------------------------------------------------------
1908
 
1909
	/**
1910
	 * Encode time in ISO-8601 form.
1911
	 * Useful for sending time in XML-RPC
1912
	 *
1913
	 * @param	int	unix timestamp
1914
	 * @param	bool
1915
	 * @return	string
1916
	*/
1917
	public function iso8601_encode($time, $utc = FALSE)
1918
	{
1919
		return ($utc) ? strftime('%Y%m%dT%H:%i:%s', $time) : gmstrftime('%Y%m%dT%H:%i:%s', $time);
1920
	}
1921
 
1922
} // END XML_RPC_Values Class