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