]>
Commit | Line | Data |
---|---|---|
59c06b17 CS |
1 | <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); |
2 | /** | |
3 | * CodeIgniter | |
4 | * | |
5 | * An open source application development framework for PHP 5.1.6 or newer | |
6 | * | |
7 | * @package CodeIgniter | |
8 | * @author ExpressionEngine Dev Team | |
9 | * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. | |
10 | * @license http://codeigniter.com/user_guide/license.html | |
11 | * @link http://codeigniter.com | |
12 | * @since Version 1.0 | |
13 | * @filesource | |
14 | */ | |
15 | ||
16 | if ( ! function_exists('xml_parser_create')) | |
17 | { | |
18 | show_error('Your PHP installation does not support XML'); | |
19 | } | |
20 | ||
21 | ||
22 | // ------------------------------------------------------------------------ | |
23 | ||
24 | /** | |
25 | * XML-RPC request handler class | |
26 | * | |
27 | * @package CodeIgniter | |
28 | * @subpackage Libraries | |
29 | * @category XML-RPC | |
30 | * @author ExpressionEngine Dev Team | |
31 | * @link http://codeigniter.com/user_guide/libraries/xmlrpc.html | |
32 | */ | |
33 | class CI_Xmlrpc { | |
34 | ||
35 | var $debug = FALSE; // Debugging on or off | |
36 | var $xmlrpcI4 = 'i4'; | |
37 | var $xmlrpcInt = 'int'; | |
38 | var $xmlrpcBoolean = 'boolean'; | |
39 | var $xmlrpcDouble = 'double'; | |
40 | var $xmlrpcString = 'string'; | |
41 | var $xmlrpcDateTime = 'dateTime.iso8601'; | |
42 | var $xmlrpcBase64 = 'base64'; | |
43 | var $xmlrpcArray = 'array'; | |
44 | var $xmlrpcStruct = 'struct'; | |
45 | ||
46 | var $xmlrpcTypes = array(); | |
47 | var $valid_parents = array(); | |
48 | var $xmlrpcerr = array(); // Response numbers | |
49 | var $xmlrpcstr = array(); // Response strings | |
50 | ||
51 | var $xmlrpc_defencoding = 'UTF-8'; | |
52 | var $xmlrpcName = 'XML-RPC for CodeIgniter'; | |
53 | var $xmlrpcVersion = '1.1'; | |
54 | var $xmlrpcerruser = 800; // Start of user errors | |
55 | var $xmlrpcerrxml = 100; // Start of XML Parse errors | |
56 | var $xmlrpc_backslash = ''; // formulate backslashes for escaping regexp | |
57 | ||
58 | var $client; | |
59 | var $method; | |
60 | var $data; | |
61 | var $message = ''; | |
62 | var $error = ''; // Error string for request | |
63 | var $result; | |
64 | var $response = array(); // Response from remote server | |
65 | ||
66 | var $xss_clean = TRUE; | |
67 | ||
68 | //------------------------------------- | |
69 | // VALUES THAT MULTIPLE CLASSES NEED | |
70 | //------------------------------------- | |
71 | ||
72 | public function __construct($config = array()) | |
73 | { | |
74 | $this->xmlrpcName = $this->xmlrpcName; | |
75 | $this->xmlrpc_backslash = chr(92).chr(92); | |
76 | ||
77 | // Types for info sent back and forth | |
78 | $this->xmlrpcTypes = array( | |
79 | $this->xmlrpcI4 => '1', | |
80 | $this->xmlrpcInt => '1', | |
81 | $this->xmlrpcBoolean => '1', | |
82 | $this->xmlrpcString => '1', | |
83 | $this->xmlrpcDouble => '1', | |
84 | $this->xmlrpcDateTime => '1', | |
85 | $this->xmlrpcBase64 => '1', | |
86 | $this->xmlrpcArray => '2', | |
87 | $this->xmlrpcStruct => '3' | |
88 | ); | |
89 | ||
90 | // Array of Valid Parents for Various XML-RPC elements | |
91 | $this->valid_parents = array('BOOLEAN' => array('VALUE'), | |
92 | 'I4' => array('VALUE'), | |
93 | 'INT' => array('VALUE'), | |
94 | 'STRING' => array('VALUE'), | |
95 | 'DOUBLE' => array('VALUE'), | |
96 | 'DATETIME.ISO8601' => array('VALUE'), | |
97 | 'BASE64' => array('VALUE'), | |
98 | 'ARRAY' => array('VALUE'), | |
99 | 'STRUCT' => array('VALUE'), | |
100 | 'PARAM' => array('PARAMS'), | |
101 | 'METHODNAME' => array('METHODCALL'), | |
102 | 'PARAMS' => array('METHODCALL', 'METHODRESPONSE'), | |
103 | 'MEMBER' => array('STRUCT'), | |
104 | 'NAME' => array('MEMBER'), | |
105 | 'DATA' => array('ARRAY'), | |
106 | 'FAULT' => array('METHODRESPONSE'), | |
107 | 'VALUE' => array('MEMBER', 'DATA', 'PARAM', 'FAULT') | |
108 | ); | |
109 | ||
110 | ||
111 | // XML-RPC Responses | |
112 | $this->xmlrpcerr['unknown_method'] = '1'; | |
113 | $this->xmlrpcstr['unknown_method'] = 'This is not a known method for this XML-RPC Server'; | |
114 | $this->xmlrpcerr['invalid_return'] = '2'; | |
115 | $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.'; | |
116 | $this->xmlrpcerr['incorrect_params'] = '3'; | |
117 | $this->xmlrpcstr['incorrect_params'] = 'Incorrect parameters were passed to method'; | |
118 | $this->xmlrpcerr['introspect_unknown'] = '4'; | |
119 | $this->xmlrpcstr['introspect_unknown'] = "Cannot inspect signature for request: method unknown"; | |
120 | $this->xmlrpcerr['http_error'] = '5'; | |
121 | $this->xmlrpcstr['http_error'] = "Did not receive a '200 OK' response from remote server."; | |
122 | $this->xmlrpcerr['no_data'] = '6'; | |
123 | $this->xmlrpcstr['no_data'] ='No data received from server.'; | |
124 | ||
125 | $this->initialize($config); | |
126 | ||
127 | log_message('debug', "XML-RPC Class Initialized"); | |
128 | } | |
129 | ||
130 | ||
131 | //------------------------------------- | |
132 | // Initialize Prefs | |
133 | //------------------------------------- | |
134 | ||
135 | function initialize($config = array()) | |
136 | { | |
137 | if (count($config) > 0) | |
138 | { | |
139 | foreach ($config as $key => $val) | |
140 | { | |
141 | if (isset($this->$key)) | |
142 | { | |
143 | $this->$key = $val; | |
144 | } | |
145 | } | |
146 | } | |
147 | } | |
148 | // END | |
149 | ||
150 | //------------------------------------- | |
151 | // Take URL and parse it | |
152 | //------------------------------------- | |
153 | ||
154 | function server($url, $port=80) | |
155 | { | |
156 | if (substr($url, 0, 4) != "http") | |
157 | { | |
158 | $url = "http://".$url; | |
159 | } | |
160 | ||
161 | $parts = parse_url($url); | |
162 | ||
163 | $path = ( ! isset($parts['path'])) ? '/' : $parts['path']; | |
164 | ||
165 | if (isset($parts['query']) && $parts['query'] != '') | |
166 | { | |
167 | $path .= '?'.$parts['query']; | |
168 | } | |
169 | ||
170 | $this->client = new XML_RPC_Client($path, $parts['host'], $port); | |
171 | } | |
172 | // END | |
173 | ||
174 | //------------------------------------- | |
175 | // Set Timeout | |
176 | //------------------------------------- | |
177 | ||
178 | function timeout($seconds=5) | |
179 | { | |
180 | if ( ! is_null($this->client) && is_int($seconds)) | |
181 | { | |
182 | $this->client->timeout = $seconds; | |
183 | } | |
184 | } | |
185 | // END | |
186 | ||
187 | //------------------------------------- | |
188 | // Set Methods | |
189 | //------------------------------------- | |
190 | ||
191 | function method($function) | |
192 | { | |
193 | $this->method = $function; | |
194 | } | |
195 | // END | |
196 | ||
197 | //------------------------------------- | |
198 | // Take Array of Data and Create Objects | |
199 | //------------------------------------- | |
200 | ||
201 | function request($incoming) | |
202 | { | |
203 | if ( ! is_array($incoming)) | |
204 | { | |
205 | // Send Error | |
206 | } | |
207 | ||
208 | $this->data = array(); | |
209 | ||
210 | foreach ($incoming as $key => $value) | |
211 | { | |
212 | $this->data[$key] = $this->values_parsing($value); | |
213 | } | |
214 | } | |
215 | // END | |
216 | ||
217 | ||
218 | //------------------------------------- | |
219 | // Set Debug | |
220 | //------------------------------------- | |
221 | ||
222 | function set_debug($flag = TRUE) | |
223 | { | |
224 | $this->debug = ($flag == TRUE) ? TRUE : FALSE; | |
225 | } | |
226 | ||
227 | //------------------------------------- | |
228 | // Values Parsing | |
229 | //------------------------------------- | |
230 | ||
231 | function values_parsing($value, $return = FALSE) | |
232 | { | |
233 | if (is_array($value) && array_key_exists(0, $value)) | |
234 | { | |
235 | if ( ! isset($value['1']) OR ( ! isset($this->xmlrpcTypes[$value['1']]))) | |
236 | { | |
237 | if (is_array($value[0])) | |
238 | { | |
239 | $temp = new XML_RPC_Values($value['0'], 'array'); | |
240 | } | |
241 | else | |
242 | { | |
243 | $temp = new XML_RPC_Values($value['0'], 'string'); | |
244 | } | |
245 | } | |
246 | elseif (is_array($value['0']) && ($value['1'] == 'struct' OR $value['1'] == 'array')) | |
247 | { | |
248 | while (list($k) = each($value['0'])) | |
249 | { | |
250 | $value['0'][$k] = $this->values_parsing($value['0'][$k], TRUE); | |
251 | } | |
252 | ||
253 | $temp = new XML_RPC_Values($value['0'], $value['1']); | |
254 | } | |
255 | else | |
256 | { | |
257 | $temp = new XML_RPC_Values($value['0'], $value['1']); | |
258 | } | |
259 | } | |
260 | else | |
261 | { | |
262 | $temp = new XML_RPC_Values($value, 'string'); | |
263 | } | |
264 | ||
265 | return $temp; | |
266 | } | |
267 | // END | |
268 | ||
269 | ||
270 | //------------------------------------- | |
271 | // Sends XML-RPC Request | |
272 | //------------------------------------- | |
273 | ||
274 | function send_request() | |
275 | { | |
276 | $this->message = new XML_RPC_Message($this->method,$this->data); | |
277 | $this->message->debug = $this->debug; | |
278 | ||
279 | if ( ! $this->result = $this->client->send($this->message)) | |
280 | { | |
281 | $this->error = $this->result->errstr; | |
282 | return FALSE; | |
283 | } | |
284 | elseif ( ! is_object($this->result->val)) | |
285 | { | |
286 | $this->error = $this->result->errstr; | |
287 | return FALSE; | |
288 | } | |
289 | ||
290 | $this->response = $this->result->decode(); | |
291 | ||
292 | return TRUE; | |
293 | } | |
294 | // END | |
295 | ||
296 | //------------------------------------- | |
297 | // Returns Error | |
298 | //------------------------------------- | |
299 | ||
300 | function display_error() | |
301 | { | |
302 | return $this->error; | |
303 | } | |
304 | // END | |
305 | ||
306 | //------------------------------------- | |
307 | // Returns Remote Server Response | |
308 | //------------------------------------- | |
309 | ||
310 | function display_response() | |
311 | { | |
312 | return $this->response; | |
313 | } | |
314 | // END | |
315 | ||
316 | //------------------------------------- | |
317 | // Sends an Error Message for Server Request | |
318 | //------------------------------------- | |
319 | ||
320 | function send_error_message($number, $message) | |
321 | { | |
322 | return new XML_RPC_Response('0',$number, $message); | |
323 | } | |
324 | // END | |
325 | ||
326 | ||
327 | //------------------------------------- | |
328 | // Send Response for Server Request | |
329 | //------------------------------------- | |
330 | ||
331 | function send_response($response) | |
332 | { | |
333 | // $response should be array of values, which will be parsed | |
334 | // based on their data and type into a valid group of XML-RPC values | |
335 | ||
336 | $response = $this->values_parsing($response); | |
337 | ||
338 | return new XML_RPC_Response($response); | |
339 | } | |
340 | // END | |
341 | ||
342 | } // END XML_RPC Class | |
343 | ||
344 | ||
345 | ||
346 | /** | |
347 | * XML-RPC Client class | |
348 | * | |
349 | * @category XML-RPC | |
350 | * @author ExpressionEngine Dev Team | |
351 | * @link http://codeigniter.com/user_guide/libraries/xmlrpc.html | |
352 | */ | |
353 | class XML_RPC_Client extends CI_Xmlrpc | |
354 | { | |
355 | var $path = ''; | |
356 | var $server = ''; | |
357 | var $port = 80; | |
358 | var $errno = ''; | |
359 | var $errstring = ''; | |
360 | var $timeout = 5; | |
361 | var $no_multicall = FALSE; | |
362 | ||
363 | public function __construct($path, $server, $port=80) | |
364 | { | |
365 | parent::__construct(); | |
366 | ||
367 | $this->port = $port; | |
368 | $this->server = $server; | |
369 | $this->path = $path; | |
370 | } | |
371 | ||
372 | function send($msg) | |
373 | { | |
374 | if (is_array($msg)) | |
375 | { | |
376 | // Multi-call disabled | |
377 | $r = new XML_RPC_Response(0, $this->xmlrpcerr['multicall_recursion'],$this->xmlrpcstr['multicall_recursion']); | |
378 | return $r; | |
379 | } | |
380 | ||
381 | return $this->sendPayload($msg); | |
382 | } | |
383 | ||
384 | function sendPayload($msg) | |
385 | { | |
386 | $fp = @fsockopen($this->server, $this->port,$this->errno, $this->errstr, $this->timeout); | |
387 | ||
388 | if ( ! is_resource($fp)) | |
389 | { | |
390 | error_log($this->xmlrpcstr['http_error']); | |
391 | $r = new XML_RPC_Response(0, $this->xmlrpcerr['http_error'],$this->xmlrpcstr['http_error']); | |
392 | return $r; | |
393 | } | |
394 | ||
395 | if (empty($msg->payload)) | |
396 | { | |
397 | // $msg = XML_RPC_Messages | |
398 | $msg->createPayload(); | |
399 | } | |
400 | ||
401 | $r = "\r\n"; | |
402 | $op = "POST {$this->path} HTTP/1.0$r"; | |
403 | $op .= "Host: {$this->server}$r"; | |
404 | $op .= "Content-Type: text/xml$r"; | |
405 | $op .= "User-Agent: {$this->xmlrpcName}$r"; | |
406 | $op .= "Content-Length: ".strlen($msg->payload). "$r$r"; | |
407 | $op .= $msg->payload; | |
408 | ||
409 | ||
410 | if ( ! fputs($fp, $op, strlen($op))) | |
411 | { | |
412 | error_log($this->xmlrpcstr['http_error']); | |
413 | $r = new XML_RPC_Response(0, $this->xmlrpcerr['http_error'], $this->xmlrpcstr['http_error']); | |
414 | return $r; | |
415 | } | |
416 | $resp = $msg->parseResponse($fp); | |
417 | fclose($fp); | |
418 | return $resp; | |
419 | } | |
420 | ||
421 | } // end class XML_RPC_Client | |
422 | ||
423 | ||
424 | /** | |
425 | * XML-RPC Response class | |
426 | * | |
427 | * @category XML-RPC | |
428 | * @author ExpressionEngine Dev Team | |
429 | * @link http://codeigniter.com/user_guide/libraries/xmlrpc.html | |
430 | */ | |
431 | class XML_RPC_Response | |
432 | { | |
433 | var $val = 0; | |
434 | var $errno = 0; | |
435 | var $errstr = ''; | |
436 | var $headers = array(); | |
437 | var $xss_clean = TRUE; | |
438 | ||
439 | public function __construct($val, $code = 0, $fstr = '') | |
440 | { | |
441 | if ($code != 0) | |
442 | { | |
443 | // error | |
444 | $this->errno = $code; | |
445 | $this->errstr = htmlentities($fstr); | |
446 | } | |
447 | else if ( ! is_object($val)) | |
448 | { | |
449 | // programmer error, not an object | |
450 | error_log("Invalid type '" . gettype($val) . "' (value: $val) passed to XML_RPC_Response. Defaulting to empty value."); | |
451 | $this->val = new XML_RPC_Values(); | |
452 | } | |
453 | else | |
454 | { | |
455 | $this->val = $val; | |
456 | } | |
457 | } | |
458 | ||
459 | function faultCode() | |
460 | { | |
461 | return $this->errno; | |
462 | } | |
463 | ||
464 | function faultString() | |
465 | { | |
466 | return $this->errstr; | |
467 | } | |
468 | ||
469 | function value() | |
470 | { | |
471 | return $this->val; | |
472 | } | |
473 | ||
474 | function prepare_response() | |
475 | { | |
476 | $result = "<methodResponse>\n"; | |
477 | if ($this->errno) | |
478 | { | |
479 | $result .= '<fault> | |
480 | <value> | |
481 | <struct> | |
482 | <member> | |
483 | <name>faultCode</name> | |
484 | <value><int>' . $this->errno . '</int></value> | |
485 | </member> | |
486 | <member> | |
487 | <name>faultString</name> | |
488 | <value><string>' . $this->errstr . '</string></value> | |
489 | </member> | |
490 | </struct> | |
491 | </value> | |
492 | </fault>'; | |
493 | } | |
494 | else | |
495 | { | |
496 | $result .= "<params>\n<param>\n" . | |
497 | $this->val->serialize_class() . | |
498 | "</param>\n</params>"; | |
499 | } | |
500 | $result .= "\n</methodResponse>"; | |
501 | return $result; | |
502 | } | |
503 | ||
504 | function decode($array=FALSE) | |
505 | { | |
506 | $CI =& get_instance(); | |
507 | ||
508 | if ($array !== FALSE && is_array($array)) | |
509 | { | |
510 | while (list($key) = each($array)) | |
511 | { | |
512 | if (is_array($array[$key])) | |
513 | { | |
514 | $array[$key] = $this->decode($array[$key]); | |
515 | } | |
516 | else | |
517 | { | |
518 | $array[$key] = ($this->xss_clean) ? $CI->security->xss_clean($array[$key]) : $array[$key]; | |
519 | } | |
520 | } | |
521 | ||
522 | $result = $array; | |
523 | } | |
524 | else | |
525 | { | |
526 | $result = $this->xmlrpc_decoder($this->val); | |
527 | ||
528 | if (is_array($result)) | |
529 | { | |
530 | $result = $this->decode($result); | |
531 | } | |
532 | else | |
533 | { | |
534 | $result = ($this->xss_clean) ? $CI->security->xss_clean($result) : $result; | |
535 | } | |
536 | } | |
537 | ||
538 | return $result; | |
539 | } | |
540 | ||
541 | ||
542 | ||
543 | //------------------------------------- | |
544 | // XML-RPC Object to PHP Types | |
545 | //------------------------------------- | |
546 | ||
547 | function xmlrpc_decoder($xmlrpc_val) | |
548 | { | |
549 | $kind = $xmlrpc_val->kindOf(); | |
550 | ||
551 | if ($kind == 'scalar') | |
552 | { | |
553 | return $xmlrpc_val->scalarval(); | |
554 | } | |
555 | elseif ($kind == 'array') | |
556 | { | |
557 | reset($xmlrpc_val->me); | |
558 | list($a,$b) = each($xmlrpc_val->me); | |
559 | $size = count($b); | |
560 | ||
561 | $arr = array(); | |
562 | ||
563 | for ($i = 0; $i < $size; $i++) | |
564 | { | |
565 | $arr[] = $this->xmlrpc_decoder($xmlrpc_val->me['array'][$i]); | |
566 | } | |
567 | return $arr; | |
568 | } | |
569 | elseif ($kind == 'struct') | |
570 | { | |
571 | reset($xmlrpc_val->me['struct']); | |
572 | $arr = array(); | |
573 | ||
574 | while (list($key,$value) = each($xmlrpc_val->me['struct'])) | |
575 | { | |
576 | $arr[$key] = $this->xmlrpc_decoder($value); | |
577 | } | |
578 | return $arr; | |
579 | } | |
580 | } | |
581 | ||
582 | ||
583 | //------------------------------------- | |
584 | // ISO-8601 time to server or UTC time | |
585 | //------------------------------------- | |
586 | ||
587 | function iso8601_decode($time, $utc=0) | |
588 | { | |
589 | // return a timet in the localtime, or UTC | |
590 | $t = 0; | |
591 | if (preg_match('/([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})/', $time, $regs)) | |
592 | { | |
593 | $fnc = ($utc == 1) ? 'gmmktime' : 'mktime'; | |
594 | $t = $fnc($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); | |
595 | } | |
596 | return $t; | |
597 | } | |
598 | ||
599 | } // End Response Class | |
600 | ||
601 | ||
602 | ||
603 | /** | |
604 | * XML-RPC Message class | |
605 | * | |
606 | * @category XML-RPC | |
607 | * @author ExpressionEngine Dev Team | |
608 | * @link http://codeigniter.com/user_guide/libraries/xmlrpc.html | |
609 | */ | |
610 | class XML_RPC_Message extends CI_Xmlrpc | |
611 | { | |
612 | var $payload; | |
613 | var $method_name; | |
614 | var $params = array(); | |
615 | var $xh = array(); | |
616 | ||
617 | public function __construct($method, $pars=0) | |
618 | { | |
619 | parent::__construct(); | |
620 | ||
621 | $this->method_name = $method; | |
622 | if (is_array($pars) && count($pars) > 0) | |
623 | { | |
624 | for ($i=0; $i<count($pars); $i++) | |
625 | { | |
626 | // $pars[$i] = XML_RPC_Values | |
627 | $this->params[] = $pars[$i]; | |
628 | } | |
629 | } | |
630 | } | |
631 | ||
632 | //------------------------------------- | |
633 | // Create Payload to Send | |
634 | //------------------------------------- | |
635 | ||
636 | function createPayload() | |
637 | { | |
638 | $this->payload = "<?xml version=\"1.0\"?".">\r\n<methodCall>\r\n"; | |
639 | $this->payload .= '<methodName>' . $this->method_name . "</methodName>\r\n"; | |
640 | $this->payload .= "<params>\r\n"; | |
641 | ||
642 | for ($i=0; $i<count($this->params); $i++) | |
643 | { | |
644 | // $p = XML_RPC_Values | |
645 | $p = $this->params[$i]; | |
646 | $this->payload .= "<param>\r\n".$p->serialize_class()."</param>\r\n"; | |
647 | } | |
648 | ||
649 | $this->payload .= "</params>\r\n</methodCall>\r\n"; | |
650 | } | |
651 | ||
652 | //------------------------------------- | |
653 | // Parse External XML-RPC Server's Response | |
654 | //------------------------------------- | |
655 | ||
656 | function parseResponse($fp) | |
657 | { | |
658 | $data = ''; | |
659 | ||
660 | while ($datum = fread($fp, 4096)) | |
661 | { | |
662 | $data .= $datum; | |
663 | } | |
664 | ||
665 | //------------------------------------- | |
666 | // DISPLAY HTTP CONTENT for DEBUGGING | |
667 | //------------------------------------- | |
668 | ||
669 | if ($this->debug === TRUE) | |
670 | { | |
671 | echo "<pre>"; | |
672 | echo "---DATA---\n" . htmlspecialchars($data) . "\n---END DATA---\n\n"; | |
673 | echo "</pre>"; | |
674 | } | |
675 | ||
676 | //------------------------------------- | |
677 | // Check for data | |
678 | //------------------------------------- | |
679 | ||
680 | if ($data == "") | |
681 | { | |
682 | error_log($this->xmlrpcstr['no_data']); | |
683 | $r = new XML_RPC_Response(0, $this->xmlrpcerr['no_data'], $this->xmlrpcstr['no_data']); | |
684 | return $r; | |
685 | } | |
686 | ||
687 | ||
688 | //------------------------------------- | |
689 | // Check for HTTP 200 Response | |
690 | //------------------------------------- | |
691 | ||
692 | if (strncmp($data, 'HTTP', 4) == 0 && ! preg_match('/^HTTP\/[0-9\.]+ 200 /', $data)) | |
693 | { | |
694 | $errstr= substr($data, 0, strpos($data, "\n")-1); | |
695 | $r = new XML_RPC_Response(0, $this->xmlrpcerr['http_error'], $this->xmlrpcstr['http_error']. ' (' . $errstr . ')'); | |
696 | return $r; | |
697 | } | |
698 | ||
699 | //------------------------------------- | |
700 | // Create and Set Up XML Parser | |
701 | //------------------------------------- | |
702 | ||
703 | $parser = xml_parser_create($this->xmlrpc_defencoding); | |
704 | ||
705 | $this->xh[$parser] = array(); | |
706 | $this->xh[$parser]['isf'] = 0; | |
707 | $this->xh[$parser]['ac'] = ''; | |
708 | $this->xh[$parser]['headers'] = array(); | |
709 | $this->xh[$parser]['stack'] = array(); | |
710 | $this->xh[$parser]['valuestack'] = array(); | |
711 | $this->xh[$parser]['isf_reason'] = 0; | |
712 | ||
713 | xml_set_object($parser, $this); | |
714 | xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true); | |
715 | xml_set_element_handler($parser, 'open_tag', 'closing_tag'); | |
716 | xml_set_character_data_handler($parser, 'character_data'); | |
717 | //xml_set_default_handler($parser, 'default_handler'); | |
718 | ||
719 | ||
720 | //------------------------------------- | |
721 | // GET HEADERS | |
722 | //------------------------------------- | |
723 | ||
724 | $lines = explode("\r\n", $data); | |
725 | while (($line = array_shift($lines))) | |
726 | { | |
727 | if (strlen($line) < 1) | |
728 | { | |
729 | break; | |
730 | } | |
731 | $this->xh[$parser]['headers'][] = $line; | |
732 | } | |
733 | $data = implode("\r\n", $lines); | |
734 | ||
735 | ||
736 | //------------------------------------- | |
737 | // PARSE XML DATA | |
738 | //------------------------------------- | |
739 | ||
740 | if ( ! xml_parse($parser, $data, count($data))) | |
741 | { | |
742 | $errstr = sprintf('XML error: %s at line %d', | |
743 | xml_error_string(xml_get_error_code($parser)), | |
744 | xml_get_current_line_number($parser)); | |
745 | //error_log($errstr); | |
746 | $r = new XML_RPC_Response(0, $this->xmlrpcerr['invalid_return'], $this->xmlrpcstr['invalid_return']); | |
747 | xml_parser_free($parser); | |
748 | return $r; | |
749 | } | |
750 | xml_parser_free($parser); | |
751 | ||
752 | // --------------------------------------- | |
753 | // Got Ourselves Some Badness, It Seems | |
754 | // --------------------------------------- | |
755 | ||
756 | if ($this->xh[$parser]['isf'] > 1) | |
757 | { | |
758 | if ($this->debug === TRUE) | |
759 | { | |
760 | echo "---Invalid Return---\n"; | |
761 | echo $this->xh[$parser]['isf_reason']; | |
762 | echo "---Invalid Return---\n\n"; | |
763 | } | |
764 | ||
765 | $r = new XML_RPC_Response(0, $this->xmlrpcerr['invalid_return'],$this->xmlrpcstr['invalid_return'].' '.$this->xh[$parser]['isf_reason']); | |
766 | return $r; | |
767 | } | |
768 | elseif ( ! is_object($this->xh[$parser]['value'])) | |
769 | { | |
770 | $r = new XML_RPC_Response(0, $this->xmlrpcerr['invalid_return'],$this->xmlrpcstr['invalid_return'].' '.$this->xh[$parser]['isf_reason']); | |
771 | return $r; | |
772 | } | |
773 | ||
774 | //------------------------------------- | |
775 | // DISPLAY XML CONTENT for DEBUGGING | |
776 | //------------------------------------- | |
777 | ||
778 | if ($this->debug === TRUE) | |
779 | { | |
780 | echo "<pre>"; | |
781 | ||
782 | if (count($this->xh[$parser]['headers'] > 0)) | |
783 | { | |
784 | echo "---HEADERS---\n"; | |
785 | foreach ($this->xh[$parser]['headers'] as $header) | |
786 | { | |
787 | echo "$header\n"; | |
788 | } | |
789 | echo "---END HEADERS---\n\n"; | |
790 | } | |
791 | ||
792 | echo "---DATA---\n" . htmlspecialchars($data) . "\n---END DATA---\n\n"; | |
793 | ||
794 | echo "---PARSED---\n" ; | |
795 | var_dump($this->xh[$parser]['value']); | |
796 | echo "\n---END PARSED---</pre>"; | |
797 | } | |
798 | ||
799 | //------------------------------------- | |
800 | // SEND RESPONSE | |
801 | //------------------------------------- | |
802 | ||
803 | $v = $this->xh[$parser]['value']; | |
804 | ||
805 | if ($this->xh[$parser]['isf']) | |
806 | { | |
807 | $errno_v = $v->me['struct']['faultCode']; | |
808 | $errstr_v = $v->me['struct']['faultString']; | |
809 | $errno = $errno_v->scalarval(); | |
810 | ||
811 | if ($errno == 0) | |
812 | { | |
813 | // FAULT returned, errno needs to reflect that | |
814 | $errno = -1; | |
815 | } | |
816 | ||
817 | $r = new XML_RPC_Response($v, $errno, $errstr_v->scalarval()); | |
818 | } | |
819 | else | |
820 | { | |
821 | $r = new XML_RPC_Response($v); | |
822 | } | |
823 | ||
824 | $r->headers = $this->xh[$parser]['headers']; | |
825 | return $r; | |
826 | } | |
827 | ||
828 | // ------------------------------------ | |
829 | // Begin Return Message Parsing section | |
830 | // ------------------------------------ | |
831 | ||
832 | // quick explanation of components: | |
833 | // ac - used to accumulate values | |
834 | // isf - used to indicate a fault | |
835 | // lv - used to indicate "looking for a value": implements | |
836 | // the logic to allow values with no types to be strings | |
837 | // params - used to store parameters in method calls | |
838 | // method - used to store method name | |
839 | // stack - array with parent tree of the xml element, | |
840 | // used to validate the nesting of elements | |
841 | ||
842 | //------------------------------------- | |
843 | // Start Element Handler | |
844 | //------------------------------------- | |
845 | ||
846 | function open_tag($the_parser, $name, $attrs) | |
847 | { | |
848 | // If invalid nesting, then return | |
849 | if ($this->xh[$the_parser]['isf'] > 1) return; | |
850 | ||
851 | // Evaluate and check for correct nesting of XML elements | |
852 | ||
853 | if (count($this->xh[$the_parser]['stack']) == 0) | |
854 | { | |
855 | if ($name != 'METHODRESPONSE' && $name != 'METHODCALL') | |
856 | { | |
857 | $this->xh[$the_parser]['isf'] = 2; | |
858 | $this->xh[$the_parser]['isf_reason'] = 'Top level XML-RPC element is missing'; | |
859 | return; | |
860 | } | |
861 | } | |
862 | else | |
863 | { | |
864 | // not top level element: see if parent is OK | |
865 | if ( ! in_array($this->xh[$the_parser]['stack'][0], $this->valid_parents[$name], TRUE)) | |
866 | { | |
867 | $this->xh[$the_parser]['isf'] = 2; | |
868 | $this->xh[$the_parser]['isf_reason'] = "XML-RPC element $name cannot be child of ".$this->xh[$the_parser]['stack'][0]; | |
869 | return; | |
870 | } | |
871 | } | |
872 | ||
873 | switch($name) | |
874 | { | |
875 | case 'STRUCT': | |
876 | case 'ARRAY': | |
877 | // Creates array for child elements | |
878 | ||
879 | $cur_val = array('value' => array(), | |
880 | 'type' => $name); | |
881 | ||
882 | array_unshift($this->xh[$the_parser]['valuestack'], $cur_val); | |
883 | break; | |
884 | case 'METHODNAME': | |
885 | case 'NAME': | |
886 | $this->xh[$the_parser]['ac'] = ''; | |
887 | break; | |
888 | case 'FAULT': | |
889 | $this->xh[$the_parser]['isf'] = 1; | |
890 | break; | |
891 | case 'PARAM': | |
892 | $this->xh[$the_parser]['value'] = NULL; | |
893 | break; | |
894 | case 'VALUE': | |
895 | $this->xh[$the_parser]['vt'] = 'value'; | |
896 | $this->xh[$the_parser]['ac'] = ''; | |
897 | $this->xh[$the_parser]['lv'] = 1; | |
898 | break; | |
899 | case 'I4': | |
900 | case 'INT': | |
901 | case 'STRING': | |
902 | case 'BOOLEAN': | |
903 | case 'DOUBLE': | |
904 | case 'DATETIME.ISO8601': | |
905 | case 'BASE64': | |
906 | if ($this->xh[$the_parser]['vt'] != 'value') | |
907 | { | |
908 | //two data elements inside a value: an error occurred! | |
909 | $this->xh[$the_parser]['isf'] = 2; | |
910 | $this->xh[$the_parser]['isf_reason'] = "'Twas a $name element following a ".$this->xh[$the_parser]['vt']." element inside a single value"; | |
911 | return; | |
912 | } | |
913 | ||
914 | $this->xh[$the_parser]['ac'] = ''; | |
915 | break; | |
916 | case 'MEMBER': | |
917 | // Set name of <member> to nothing to prevent errors later if no <name> is found | |
918 | $this->xh[$the_parser]['valuestack'][0]['name'] = ''; | |
919 | ||
920 | // Set NULL value to check to see if value passed for this param/member | |
921 | $this->xh[$the_parser]['value'] = NULL; | |
922 | break; | |
923 | case 'DATA': | |
924 | case 'METHODCALL': | |
925 | case 'METHODRESPONSE': | |
926 | case 'PARAMS': | |
927 | // valid elements that add little to processing | |
928 | break; | |
929 | default: | |
930 | /// An Invalid Element is Found, so we have trouble | |
931 | $this->xh[$the_parser]['isf'] = 2; | |
932 | $this->xh[$the_parser]['isf_reason'] = "Invalid XML-RPC element found: $name"; | |
933 | break; | |
934 | } | |
935 | ||
936 | // Add current element name to stack, to allow validation of nesting | |
937 | array_unshift($this->xh[$the_parser]['stack'], $name); | |
938 | ||
939 | if ($name != 'VALUE') $this->xh[$the_parser]['lv'] = 0; | |
940 | } | |
941 | // END | |
942 | ||
943 | ||
944 | //------------------------------------- | |
945 | // End Element Handler | |
946 | //------------------------------------- | |
947 | ||
948 | function closing_tag($the_parser, $name) | |
949 | { | |
950 | if ($this->xh[$the_parser]['isf'] > 1) return; | |
951 | ||
952 | // Remove current element from stack and set variable | |
953 | // NOTE: If the XML validates, then we do not have to worry about | |
954 | // the opening and closing of elements. Nesting is checked on the opening | |
955 | // tag so we be safe there as well. | |
956 | ||
957 | $curr_elem = array_shift($this->xh[$the_parser]['stack']); | |
958 | ||
959 | switch($name) | |
960 | { | |
961 | case 'STRUCT': | |
962 | case 'ARRAY': | |
963 | $cur_val = array_shift($this->xh[$the_parser]['valuestack']); | |
964 | $this->xh[$the_parser]['value'] = ( ! isset($cur_val['values'])) ? array() : $cur_val['values']; | |
965 | $this->xh[$the_parser]['vt'] = strtolower($name); | |
966 | break; | |
967 | case 'NAME': | |
968 | $this->xh[$the_parser]['valuestack'][0]['name'] = $this->xh[$the_parser]['ac']; | |
969 | break; | |
970 | case 'BOOLEAN': | |
971 | case 'I4': | |
972 | case 'INT': | |
973 | case 'STRING': | |
974 | case 'DOUBLE': | |
975 | case 'DATETIME.ISO8601': | |
976 | case 'BASE64': | |
977 | $this->xh[$the_parser]['vt'] = strtolower($name); | |
978 | ||
979 | if ($name == 'STRING') | |
980 | { | |
981 | $this->xh[$the_parser]['value'] = $this->xh[$the_parser]['ac']; | |
982 | } | |
983 | elseif ($name=='DATETIME.ISO8601') | |
984 | { | |
985 | $this->xh[$the_parser]['vt'] = $this->xmlrpcDateTime; | |
986 | $this->xh[$the_parser]['value'] = $this->xh[$the_parser]['ac']; | |
987 | } | |
988 | elseif ($name=='BASE64') | |
989 | { | |
990 | $this->xh[$the_parser]['value'] = base64_decode($this->xh[$the_parser]['ac']); | |
991 | } | |
992 | elseif ($name=='BOOLEAN') | |
993 | { | |
994 | // Translated BOOLEAN values to TRUE AND FALSE | |
995 | if ($this->xh[$the_parser]['ac'] == '1') | |
996 | { | |
997 | $this->xh[$the_parser]['value'] = TRUE; | |
998 | } | |
999 | else | |
1000 | { | |
1001 | $this->xh[$the_parser]['value'] = FALSE; | |
1002 | } | |
1003 | } | |
1004 | elseif ($name=='DOUBLE') | |
1005 | { | |
1006 | // we have a DOUBLE | |
1007 | // we must check that only 0123456789-.<space> are characters here | |
1008 | if ( ! preg_match('/^[+-]?[eE0-9\t \.]+$/', $this->xh[$the_parser]['ac'])) | |
1009 | { | |
1010 | $this->xh[$the_parser]['value'] = 'ERROR_NON_NUMERIC_FOUND'; | |
1011 | } | |
1012 | else | |
1013 | { | |
1014 | $this->xh[$the_parser]['value'] = (double)$this->xh[$the_parser]['ac']; | |
1015 | } | |
1016 | } | |
1017 | else | |
1018 | { | |
1019 | // we have an I4/INT | |
1020 | // we must check that only 0123456789-<space> are characters here | |
1021 | if ( ! preg_match('/^[+-]?[0-9\t ]+$/', $this->xh[$the_parser]['ac'])) | |
1022 | { | |
1023 | $this->xh[$the_parser]['value'] = 'ERROR_NON_NUMERIC_FOUND'; | |
1024 | } | |
1025 | else | |
1026 | { | |
1027 | $this->xh[$the_parser]['value'] = (int)$this->xh[$the_parser]['ac']; | |
1028 | } | |
1029 | } | |
1030 | $this->xh[$the_parser]['ac'] = ''; | |
1031 | $this->xh[$the_parser]['lv'] = 3; // indicate we've found a value | |
1032 | break; | |
1033 | case 'VALUE': | |
1034 | // This if() detects if no scalar was inside <VALUE></VALUE> | |
1035 | if ($this->xh[$the_parser]['vt']=='value') | |
1036 | { | |
1037 | $this->xh[$the_parser]['value'] = $this->xh[$the_parser]['ac']; | |
1038 | $this->xh[$the_parser]['vt'] = $this->xmlrpcString; | |
1039 | } | |
1040 | ||
1041 | // build the XML-RPC value out of the data received, and substitute it | |
1042 | $temp = new XML_RPC_Values($this->xh[$the_parser]['value'], $this->xh[$the_parser]['vt']); | |
1043 | ||
1044 | if (count($this->xh[$the_parser]['valuestack']) && $this->xh[$the_parser]['valuestack'][0]['type'] == 'ARRAY') | |
1045 | { | |
1046 | // Array | |
1047 | $this->xh[$the_parser]['valuestack'][0]['values'][] = $temp; | |
1048 | } | |
1049 | else | |
1050 | { | |
1051 | // Struct | |
1052 | $this->xh[$the_parser]['value'] = $temp; | |
1053 | } | |
1054 | break; | |
1055 | case 'MEMBER': | |
1056 | $this->xh[$the_parser]['ac']=''; | |
1057 | ||
1058 | // If value add to array in the stack for the last element built | |
1059 | if ($this->xh[$the_parser]['value']) | |
1060 | { | |
1061 | $this->xh[$the_parser]['valuestack'][0]['values'][$this->xh[$the_parser]['valuestack'][0]['name']] = $this->xh[$the_parser]['value']; | |
1062 | } | |
1063 | break; | |
1064 | case 'DATA': | |
1065 | $this->xh[$the_parser]['ac']=''; | |
1066 | break; | |
1067 | case 'PARAM': | |
1068 | if ($this->xh[$the_parser]['value']) | |
1069 | { | |
1070 | $this->xh[$the_parser]['params'][] = $this->xh[$the_parser]['value']; | |
1071 | } | |
1072 | break; | |
1073 | case 'METHODNAME': | |
1074 | $this->xh[$the_parser]['method'] = ltrim($this->xh[$the_parser]['ac']); | |
1075 | break; | |
1076 | case 'PARAMS': | |
1077 | case 'FAULT': | |
1078 | case 'METHODCALL': | |
1079 | case 'METHORESPONSE': | |
1080 | // We're all good kids with nuthin' to do | |
1081 | break; | |
1082 | default: | |
1083 | // End of an Invalid Element. Taken care of during the opening tag though | |
1084 | break; | |
1085 | } | |
1086 | } | |
1087 | ||
1088 | //------------------------------------- | |
1089 | // Parses Character Data | |
1090 | //------------------------------------- | |
1091 | ||
1092 | function character_data($the_parser, $data) | |
1093 | { | |
1094 | if ($this->xh[$the_parser]['isf'] > 1) return; // XML Fault found already | |
1095 | ||
1096 | // If a value has not been found | |
1097 | if ($this->xh[$the_parser]['lv'] != 3) | |
1098 | { | |
1099 | if ($this->xh[$the_parser]['lv'] == 1) | |
1100 | { | |
1101 | $this->xh[$the_parser]['lv'] = 2; // Found a value | |
1102 | } | |
1103 | ||
1104 | if ( ! @isset($this->xh[$the_parser]['ac'])) | |
1105 | { | |
1106 | $this->xh[$the_parser]['ac'] = ''; | |
1107 | } | |
1108 | ||
1109 | $this->xh[$the_parser]['ac'] .= $data; | |
1110 | } | |
1111 | } | |
1112 | ||
1113 | ||
1114 | function addParam($par) { $this->params[]=$par; } | |
1115 | ||
1116 | function output_parameters($array=FALSE) | |
1117 | { | |
1118 | $CI =& get_instance(); | |
1119 | ||
1120 | if ($array !== FALSE && is_array($array)) | |
1121 | { | |
1122 | while (list($key) = each($array)) | |
1123 | { | |
1124 | if (is_array($array[$key])) | |
1125 | { | |
1126 | $array[$key] = $this->output_parameters($array[$key]); | |
1127 | } | |
1128 | else | |
1129 | { | |
1130 | // 'bits' is for the MetaWeblog API image bits | |
1131 | // @todo - this needs to be made more general purpose | |
1132 | $array[$key] = ($key == 'bits' OR $this->xss_clean == FALSE) ? $array[$key] : $CI->security->xss_clean($array[$key]); | |
1133 | } | |
1134 | } | |
1135 | ||
1136 | $parameters = $array; | |
1137 | } | |
1138 | else | |
1139 | { | |
1140 | $parameters = array(); | |
1141 | ||
1142 | for ($i = 0; $i < count($this->params); $i++) | |
1143 | { | |
1144 | $a_param = $this->decode_message($this->params[$i]); | |
1145 | ||
1146 | if (is_array($a_param)) | |
1147 | { | |
1148 | $parameters[] = $this->output_parameters($a_param); | |
1149 | } | |
1150 | else | |
1151 | { | |
1152 | $parameters[] = ($this->xss_clean) ? $CI->security->xss_clean($a_param) : $a_param; | |
1153 | } | |
1154 | } | |
1155 | } | |
1156 | ||
1157 | return $parameters; | |
1158 | } | |
1159 | ||
1160 | ||
1161 | function decode_message($param) | |
1162 | { | |
1163 | $kind = $param->kindOf(); | |
1164 | ||
1165 | if ($kind == 'scalar') | |
1166 | { | |
1167 | return $param->scalarval(); | |
1168 | } | |
1169 | elseif ($kind == 'array') | |
1170 | { | |
1171 | reset($param->me); | |
1172 | list($a,$b) = each($param->me); | |
1173 | ||
1174 | $arr = array(); | |
1175 | ||
1176 | for($i = 0; $i < count($b); $i++) | |
1177 | { | |
1178 | $arr[] = $this->decode_message($param->me['array'][$i]); | |
1179 | } | |
1180 | ||
1181 | return $arr; | |
1182 | } | |
1183 | elseif ($kind == 'struct') | |
1184 | { | |
1185 | reset($param->me['struct']); | |
1186 | ||
1187 | $arr = array(); | |
1188 | ||
1189 | while (list($key,$value) = each($param->me['struct'])) | |
1190 | { | |
1191 | $arr[$key] = $this->decode_message($value); | |
1192 | } | |
1193 | ||
1194 | return $arr; | |
1195 | } | |
1196 | } | |
1197 | ||
1198 | } // End XML_RPC_Messages class | |
1199 | ||
1200 | ||
1201 | ||
1202 | /** | |
1203 | * XML-RPC Values class | |
1204 | * | |
1205 | * @category XML-RPC | |
1206 | * @author ExpressionEngine Dev Team | |
1207 | * @link http://codeigniter.com/user_guide/libraries/xmlrpc.html | |
1208 | */ | |
1209 | class XML_RPC_Values extends CI_Xmlrpc | |
1210 | { | |
1211 | var $me = array(); | |
1212 | var $mytype = 0; | |
1213 | ||
1214 | public function __construct($val=-1, $type='') | |
1215 | { | |
1216 | parent::__construct(); | |
1217 | ||
1218 | if ($val != -1 OR $type != '') | |
1219 | { | |
1220 | $type = $type == '' ? 'string' : $type; | |
1221 | ||
1222 | if ($this->xmlrpcTypes[$type] == 1) | |
1223 | { | |
1224 | $this->addScalar($val,$type); | |
1225 | } | |
1226 | elseif ($this->xmlrpcTypes[$type] == 2) | |
1227 | { | |
1228 | $this->addArray($val); | |
1229 | } | |
1230 | elseif ($this->xmlrpcTypes[$type] == 3) | |
1231 | { | |
1232 | $this->addStruct($val); | |
1233 | } | |
1234 | } | |
1235 | } | |
1236 | ||
1237 | function addScalar($val, $type='string') | |
1238 | { | |
1239 | $typeof = $this->xmlrpcTypes[$type]; | |
1240 | ||
1241 | if ($this->mytype==1) | |
1242 | { | |
1243 | echo '<strong>XML_RPC_Values</strong>: scalar can have only one value<br />'; | |
1244 | return 0; | |
1245 | } | |
1246 | ||
1247 | if ($typeof != 1) | |
1248 | { | |
1249 | echo '<strong>XML_RPC_Values</strong>: not a scalar type (${typeof})<br />'; | |
1250 | return 0; | |
1251 | } | |
1252 | ||
1253 | if ($type == $this->xmlrpcBoolean) | |
1254 | { | |
1255 | if (strcasecmp($val,'true')==0 OR $val==1 OR ($val==true && strcasecmp($val,'false'))) | |
1256 | { | |
1257 | $val = 1; | |
1258 | } | |
1259 | else | |
1260 | { | |
1261 | $val=0; | |
1262 | } | |
1263 | } | |
1264 | ||
1265 | if ($this->mytype == 2) | |
1266 | { | |
1267 | // adding to an array here | |
1268 | $ar = $this->me['array']; | |
1269 | $ar[] = new XML_RPC_Values($val, $type); | |
1270 | $this->me['array'] = $ar; | |
1271 | } | |
1272 | else | |
1273 | { | |
1274 | // a scalar, so set the value and remember we're scalar | |
1275 | $this->me[$type] = $val; | |
1276 | $this->mytype = $typeof; | |
1277 | } | |
1278 | return 1; | |
1279 | } | |
1280 | ||
1281 | function addArray($vals) | |
1282 | { | |
1283 | if ($this->mytype != 0) | |
1284 | { | |
1285 | echo '<strong>XML_RPC_Values</strong>: already initialized as a [' . $this->kindOf() . ']<br />'; | |
1286 | return 0; | |
1287 | } | |
1288 | ||
1289 | $this->mytype = $this->xmlrpcTypes['array']; | |
1290 | $this->me['array'] = $vals; | |
1291 | return 1; | |
1292 | } | |
1293 | ||
1294 | function addStruct($vals) | |
1295 | { | |
1296 | if ($this->mytype != 0) | |
1297 | { | |
1298 | echo '<strong>XML_RPC_Values</strong>: already initialized as a [' . $this->kindOf() . ']<br />'; | |
1299 | return 0; | |
1300 | } | |
1301 | $this->mytype = $this->xmlrpcTypes['struct']; | |
1302 | $this->me['struct'] = $vals; | |
1303 | return 1; | |
1304 | } | |
1305 | ||
1306 | function kindOf() | |
1307 | { | |
1308 | switch($this->mytype) | |
1309 | { | |
1310 | case 3: | |
1311 | return 'struct'; | |
1312 | break; | |
1313 | case 2: | |
1314 | return 'array'; | |
1315 | break; | |
1316 | case 1: | |
1317 | return 'scalar'; | |
1318 | break; | |
1319 | default: | |
1320 | return 'undef'; | |
1321 | } | |
1322 | } | |
1323 | ||
1324 | function serializedata($typ, $val) | |
1325 | { | |
1326 | $rs = ''; | |
1327 | ||
1328 | switch($this->xmlrpcTypes[$typ]) | |
1329 | { | |
1330 | case 3: | |
1331 | // struct | |
1332 | $rs .= "<struct>\n"; | |
1333 | reset($val); | |
1334 | while (list($key2, $val2) = each($val)) | |
1335 | { | |
1336 | $rs .= "<member>\n<name>{$key2}</name>\n"; | |
1337 | $rs .= $this->serializeval($val2); | |
1338 | $rs .= "</member>\n"; | |
1339 | } | |
1340 | $rs .= '</struct>'; | |
1341 | break; | |
1342 | case 2: | |
1343 | // array | |
1344 | $rs .= "<array>\n<data>\n"; | |
1345 | for($i=0; $i < count($val); $i++) | |
1346 | { | |
1347 | $rs .= $this->serializeval($val[$i]); | |
1348 | } | |
1349 | $rs.="</data>\n</array>\n"; | |
1350 | break; | |
1351 | case 1: | |
1352 | // others | |
1353 | switch ($typ) | |
1354 | { | |
1355 | case $this->xmlrpcBase64: | |
1356 | $rs .= "<{$typ}>" . base64_encode((string)$val) . "</{$typ}>\n"; | |
1357 | break; | |
1358 | case $this->xmlrpcBoolean: | |
1359 | $rs .= "<{$typ}>" . ((bool)$val ? '1' : '0') . "</{$typ}>\n"; | |
1360 | break; | |
1361 | case $this->xmlrpcString: | |
1362 | $rs .= "<{$typ}>" . htmlspecialchars((string)$val). "</{$typ}>\n"; | |
1363 | break; | |
1364 | default: | |
1365 | $rs .= "<{$typ}>{$val}</{$typ}>\n"; | |
1366 | break; | |
1367 | } | |
1368 | default: | |
1369 | break; | |
1370 | } | |
1371 | return $rs; | |
1372 | } | |
1373 | ||
1374 | function serialize_class() | |
1375 | { | |
1376 | return $this->serializeval($this); | |
1377 | } | |
1378 | ||
1379 | function serializeval($o) | |
1380 | { | |
1381 | $ar = $o->me; | |
1382 | reset($ar); | |
1383 | ||
1384 | list($typ, $val) = each($ar); | |
1385 | $rs = "<value>\n".$this->serializedata($typ, $val)."</value>\n"; | |
1386 | return $rs; | |
1387 | } | |
1388 | ||
1389 | function scalarval() | |
1390 | { | |
1391 | reset($this->me); | |
1392 | list($a,$b) = each($this->me); | |
1393 | return $b; | |
1394 | } | |
1395 | ||
1396 | ||
1397 | //------------------------------------- | |
1398 | // Encode time in ISO-8601 form. | |
1399 | //------------------------------------- | |
1400 | ||
1401 | // Useful for sending time in XML-RPC | |
1402 | ||
1403 | function iso8601_encode($time, $utc=0) | |
1404 | { | |
1405 | if ($utc == 1) | |
1406 | { | |
1407 | $t = strftime("%Y%m%dT%H:%i:%s", $time); | |
1408 | } | |
1409 | else | |
1410 | { | |
1411 | if (function_exists('gmstrftime')) | |
1412 | $t = gmstrftime("%Y%m%dT%H:%i:%s", $time); | |
1413 | else | |
1414 | $t = strftime("%Y%m%dT%H:%i:%s", $time - date('Z')); | |
1415 | } | |
1416 | return $t; | |
1417 | } | |
1418 | ||
1419 | } | |
1420 | // END XML_RPC_Values Class | |
1421 | ||
1422 | /* End of file Xmlrpc.php */ | |
1423 | /* Location: ./system/libraries/Xmlrpc.php */ |