OSDN Git Service

01cf1aa8275833abd5371e77676d82951dfcf02f
[nucleus-jp/nucleus-jp-ancient.git] / utf8 / nucleus / libs / xmlrpc.inc.php
1 <?php                                   // -*-c++-*-\r
2 // by Edd Dumbill (C) 1999-2001\r
3 // <edd@usefulinc.com>\r
4 // $Id: xmlrpc.inc.php,v 1.3 2005-03-04 08:20:47 kimitake Exp $\r
5 \r
6 /*\r
7         Modifications made for use with Nucleus:\r
8         \r
9         renamed methods:\r
10         xmlrpc_encode -> _xmlrpc_encode\r
11         xmlrpc_decode -> _xmlrpc_decode\r
12 */\r
13 \r
14 \r
15 // Copyright (c) 1999,2000,2001 Edd Dumbill.\r
16 // All rights reserved.\r
17 //\r
18 // Redistribution and use in source and binary forms, with or without\r
19 // modification, are permitted provided that the following conditions\r
20 // are met:\r
21 //\r
22 //    * Redistributions of source code must retain the above copyright\r
23 //      notice, this list of conditions and the following disclaimer.\r
24 //\r
25 //    * Redistributions in binary form must reproduce the above\r
26 //      copyright notice, this list of conditions and the following\r
27 //      disclaimer in the documentation and/or other materials provided\r
28 //      with the distribution.\r
29 //\r
30 //    * Neither the name of the "XML-RPC for PHP" nor the names of its\r
31 //      contributors may be used to endorse or promote products derived\r
32 //      from this software without specific prior written permission.\r
33 //\r
34 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
35 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
36 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\r
37 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\r
38 // REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
39 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
40 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\r
41 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r
42 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\r
43 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r
44 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\r
45 // OF THE POSSIBILITY OF SUCH DAMAGE.\r
46 \r
47 if (!function_exists('xml_parser_create')) {\r
48 // Win 32 fix. From: "Leo West" <lwest@imaginet.fr>\r
49         if($WINDIR) {\r
50                 dl("php3_xml.dll");\r
51         } else {\r
52                 dl("xml.so");\r
53         }\r
54 }\r
55 \r
56 $xmlrpcI4="i4";\r
57 $xmlrpcInt="int";\r
58 $xmlrpcBoolean="boolean";\r
59 $xmlrpcDouble="double";\r
60 $xmlrpcString="string";\r
61 $xmlrpcDateTime="dateTime.iso8601";\r
62 $xmlrpcBase64="base64";\r
63 $xmlrpcArray="array";\r
64 $xmlrpcStruct="struct";\r
65 \r
66 \r
67 $xmlrpcTypes=array($xmlrpcI4 => 1,\r
68                                    $xmlrpcInt => 1,\r
69                                    $xmlrpcBoolean => 1,\r
70                                    $xmlrpcString => 1,\r
71                                    $xmlrpcDouble => 1,\r
72                                    $xmlrpcDateTime => 1,\r
73                                    $xmlrpcBase64 => 1,\r
74                                    $xmlrpcArray => 2,\r
75                                    $xmlrpcStruct => 3);\r
76 \r
77 $xmlEntities=array(      "amp" => "&",\r
78                                                                          "quot" => '"',\r
79                                                                          "lt" => "<",\r
80                                                                          "gt" => ">",\r
81                                                                          "apos" => "'");\r
82 \r
83 $xmlrpcerr["unknown_method"]=1;\r
84 $xmlrpcstr["unknown_method"]="Unknown method";\r
85 $xmlrpcerr["invalid_return"]=2;\r
86 $xmlrpcstr["invalid_return"]="Invalid return payload: enabling debugging to examine incoming payload";\r
87 $xmlrpcerr["incorrect_params"]=3;\r
88 $xmlrpcstr["incorrect_params"]="Incorrect parameters passed to method";\r
89 $xmlrpcerr["introspect_unknown"]=4;\r
90 $xmlrpcstr["introspect_unknown"]="Can't introspect: method unknown";\r
91 $xmlrpcerr["http_error"]=5;\r
92 $xmlrpcstr["http_error"]="Didn't receive 200 OK from remote server.";\r
93 $xmlrpcerr["no_data"]=6;\r
94 $xmlrpcstr["no_data"]="No data received from server.";\r
95 $xmlrpcerr["no_ssl"]=7;\r
96 $xmlrpcstr["no_ssl"]="No SSL support compiled in.";\r
97 $xmlrpcerr["curl_fail"]=8;\r
98 $xmlrpcstr["curl_fail"]="CURL error";\r
99 \r
100 $xmlrpc_defencoding="UTF-8";\r
101 \r
102 $xmlrpcName="XML-RPC for PHP";\r
103 $xmlrpcVersion="1.02";\r
104 \r
105 // let user errors start at 800\r
106 $xmlrpcerruser=800; \r
107 // let XML parse errors start at 100\r
108 $xmlrpcerrxml=100;\r
109 \r
110 // formulate backslashes for escaping regexp\r
111 $xmlrpc_backslash=chr(92).chr(92);\r
112 \r
113 // used to store state during parsing\r
114 // quick explanation of components:\r
115 //   st - used to build up a string for evaluation\r
116 //   ac - used to accumulate values\r
117 //   qt - used to decide if quotes are needed for evaluation\r
118 //   cm - used to denote struct or array (comma needed)\r
119 //   isf - used to indicate a fault\r
120 //   lv - used to indicate "looking for a value": implements\r
121 //        the logic to allow values with no types to be strings\r
122 //   params - used to store parameters in method calls\r
123 //   method - used to store method name\r
124 \r
125 $_xh=array();\r
126 \r
127 function xmlrpc_entity_decode($string) {\r
128   $top=split("&", $string);\r
129   $op="";\r
130   $i=0; \r
131   while($i<sizeof($top)) {\r
132         if (ereg("^([#a-zA-Z0-9]+);", $top[$i], $regs)) {\r
133           $op.=ereg_replace("^[#a-zA-Z0-9]+;",\r
134                                                 xmlrpc_lookup_entity($regs[1]),\r
135                                                                                         $top[$i]);\r
136         } else {\r
137           if ($i==0) \r
138                 $op=$top[$i]; \r
139           else\r
140                 $op.="&" . $top[$i];\r
141         }\r
142         $i++;\r
143   }\r
144   return $op;\r
145 }\r
146 \r
147 function xmlrpc_lookup_entity($ent) {\r
148   global $xmlEntities;\r
149   \r
150   if (isset($xmlEntities[strtolower($ent)]))\r
151         return $xmlEntities[strtolower($ent)];\r
152   if (ereg("^#([0-9]+)$", $ent, $regs))\r
153         return chr($regs[1]);\r
154   return "?";\r
155 }\r
156 \r
157 function xmlrpc_se($parser, $name, $attrs) {\r
158         global $_xh, $xmlrpcDateTime, $xmlrpcString;\r
159         \r
160         switch($name) {\r
161         case "STRUCT":\r
162         case "ARRAY":\r
163           $_xh[$parser]['st'].="array(";\r
164           $_xh[$parser]['cm']++;\r
165                 // this last line turns quoting off\r
166                 // this means if we get an empty array we'll \r
167                 // simply get a bit of whitespace in the eval\r
168                 $_xh[$parser]['qt']=0;\r
169           break;\r
170         case "NAME":\r
171           $_xh[$parser]['st'].="'"; $_xh[$parser]['ac']="";\r
172           break;\r
173         case "FAULT":\r
174           $_xh[$parser]['isf']=1;\r
175           break;\r
176         case "PARAM":\r
177           $_xh[$parser]['st']="";\r
178           break;\r
179         case "VALUE":\r
180           $_xh[$parser]['st'].="new xmlrpcval("; \r
181                 $_xh[$parser]['vt']=$xmlrpcString;\r
182                 $_xh[$parser]['ac']="";\r
183                 $_xh[$parser]['qt']=0;\r
184           $_xh[$parser]['lv']=1;\r
185           // look for a value: if this is still 1 by the\r
186           // time we reach the first data segment then the type is string\r
187           // by implication and we need to add in a quote\r
188                 break;\r
189 \r
190         case "I4":\r
191         case "INT":\r
192         case "STRING":\r
193         case "BOOLEAN":\r
194         case "DOUBLE":\r
195         case "DATETIME.ISO8601":\r
196         case "BASE64":\r
197           $_xh[$parser]['ac']=""; // reset the accumulator\r
198 \r
199           if ($name=="DATETIME.ISO8601" || $name=="STRING") {\r
200                         $_xh[$parser]['qt']=1; \r
201                         if ($name=="DATETIME.ISO8601")\r
202                                 $_xh[$parser]['vt']=$xmlrpcDateTime;\r
203           } else if ($name=="BASE64") {\r
204                         $_xh[$parser]['qt']=2;\r
205                 } else {\r
206                         // No quoting is required here -- but\r
207                         // at the end of the element we must check\r
208                         // for data format errors.\r
209                         $_xh[$parser]['qt']=0;\r
210           }\r
211                 break;\r
212         case "MEMBER":\r
213                 $_xh[$parser]['ac']="";\r
214           break;\r
215         default:\r
216                 break;\r
217         }\r
218 \r
219         if ($name!="VALUE") $_xh[$parser]['lv']=0;\r
220 }\r
221 \r
222 function xmlrpc_ee($parser, $name) {\r
223         global $_xh,$xmlrpcTypes,$xmlrpcString;\r
224 \r
225         switch($name) {\r
226         case "STRUCT":\r
227         case "ARRAY":\r
228           if ($_xh[$parser]['cm'] && substr($_xh[$parser]['st'], -1) ==',') {\r
229                 $_xh[$parser]['st']=substr($_xh[$parser]['st'],0,-1);\r
230           }\r
231           $_xh[$parser]['st'].=")";     \r
232           $_xh[$parser]['vt']=strtolower($name);\r
233           $_xh[$parser]['cm']--;\r
234           break;\r
235         case "NAME":\r
236           $_xh[$parser]['st'].= $_xh[$parser]['ac'] . "' => ";\r
237           break;\r
238         case "BOOLEAN":\r
239                 // special case here: we translate boolean 1 or 0 into PHP\r
240                 // constants true or false\r
241                 if ($_xh[$parser]['ac']=='1') \r
242                         $_xh[$parser]['ac']="true";\r
243                 else \r
244                         $_xh[$parser]['ac']="false";\r
245                 $_xh[$parser]['vt']=strtolower($name);\r
246                 // Drop through intentionally.\r
247         case "I4":\r
248         case "INT":\r
249         case "STRING":\r
250         case "DOUBLE":\r
251         case "DATETIME.ISO8601":\r
252         case "BASE64":\r
253           if ($_xh[$parser]['qt']==1) {\r
254                         // we use double quotes rather than single so backslashification works OK\r
255                         $_xh[$parser]['st'].="\"". $_xh[$parser]['ac'] . "\""; \r
256                 } else if ($_xh[$parser]['qt']==2) {\r
257                         $_xh[$parser]['st'].="base64_decode('". $_xh[$parser]['ac'] . "')"; \r
258                 } else if ($name=="BOOLEAN") {\r
259                         $_xh[$parser]['st'].=$_xh[$parser]['ac'];\r
260                 } else {\r
261                         // we have an I4, INT or a DOUBLE\r
262                         // we must check that only 0123456789-.<space> are characters here\r
263                         if (!ereg("^\-?[0123456789 \t\.]+$", $_xh[$parser]['ac'])) {\r
264                                 // TODO: find a better way of throwing an error\r
265                                 // than this!\r
266                                 error_log("XML-RPC: non numeric value received in INT or DOUBLE");\r
267                                 $_xh[$parser]['st'].="ERROR_NON_NUMERIC_FOUND";\r
268                         } else {\r
269                                 // it's ok, add it on\r
270                                 $_xh[$parser]['st'].=$_xh[$parser]['ac'];\r
271                         }\r
272                 }\r
273                 $_xh[$parser]['ac']=""; $_xh[$parser]['qt']=0;\r
274                 $_xh[$parser]['lv']=3; // indicate we've found a value\r
275           break;\r
276         case "VALUE":\r
277                 // deal with a string value\r
278                 if (strlen($_xh[$parser]['ac'])>0 &&\r
279                                 $_xh[$parser]['vt']==$xmlrpcString) {\r
280                         $_xh[$parser]['st'].="\"". $_xh[$parser]['ac'] . "\""; \r
281                 }\r
282                 // This if() detects if no scalar was inside <VALUE></VALUE>\r
283                 // and pads an empty "".\r
284                 if($_xh[$parser]['st'][strlen($_xh[$parser]['st'])-1] == '(') {\r
285                         $_xh[$parser]['st'].= '""';\r
286                 }\r
287                 $_xh[$parser]['st'].=", '" . $_xh[$parser]['vt'] . "')";\r
288                 if ($_xh[$parser]['cm']) $_xh[$parser]['st'].=",";\r
289                 break;\r
290         case "MEMBER":\r
291           $_xh[$parser]['ac']=""; $_xh[$parser]['qt']=0;\r
292          break;\r
293         case "DATA":\r
294           $_xh[$parser]['ac']=""; $_xh[$parser]['qt']=0;\r
295           break;\r
296         case "PARAM":\r
297           $_xh[$parser]['params'][]=$_xh[$parser]['st'];\r
298           break;\r
299         case "METHODNAME":\r
300           $_xh[$parser]['method']=ereg_replace("^[\n\r\t ]+", "", \r
301                                                                                                                                                                  $_xh[$parser]['ac']);\r
302                 break;\r
303         case "BOOLEAN":\r
304                 // special case here: we translate boolean 1 or 0 into PHP\r
305                 // constants true or false\r
306                 if ($_xh[$parser]['ac']=='1') \r
307                         $_xh[$parser]['ac']="true";\r
308                 else \r
309                         $_xh[$parser]['ac']="false";\r
310                 $_xh[$parser]['vt']=strtolower($name);\r
311                 break;\r
312         default:\r
313                 break;\r
314         }\r
315         // if it's a valid type name, set the type\r
316         if (isset($xmlrpcTypes[strtolower($name)])) {\r
317                 $_xh[$parser]['vt']=strtolower($name);\r
318         }\r
319         \r
320 }\r
321 \r
322 function xmlrpc_cd($parser, $data)\r
323 {       \r
324   global $_xh, $xmlrpc_backslash;\r
325 \r
326   //if (ereg("^[\n\r \t]+$", $data)) return;\r
327   // print "adding [${data}]\n";\r
328 \r
329         if ($_xh[$parser]['lv']!=3) {\r
330                 // "lookforvalue==3" means that we've found an entire value\r
331                 // and should discard any further character data\r
332                 if ($_xh[$parser]['lv']==1) {  \r
333                         // if we've found text and we're just in a <value> then\r
334                         // turn quoting on, as this will be a string\r
335                         $_xh[$parser]['qt']=1; \r
336                         // and say we've found a value\r
337                         $_xh[$parser]['lv']=2; \r
338                 }\r
339         // replace characters that eval would\r
340         // do special things with\r
341         $_xh[$parser]['ac'].=str_replace('$', '\$',\r
342                 str_replace('"', '\"', str_replace(chr(92),\r
343                         $xmlrpc_backslash, $data)));\r
344         }\r
345 }\r
346 \r
347 function xmlrpc_dh($parser, $data)\r
348 {\r
349   global $_xh;\r
350   if (substr($data, 0, 1) == "&" && substr($data, -1, 1) == ";") {\r
351                 if ($_xh[$parser]['lv']==1) {  \r
352                         $_xh[$parser]['qt']=1; \r
353                         $_xh[$parser]['lv']=2; \r
354                 }\r
355                 $_xh[$parser]['ac'].=str_replace('$', '\$',\r
356                                 str_replace('"', '\"', str_replace(chr(92),\r
357                                         $xmlrpc_backslash, $data)));\r
358   }\r
359 }\r
360 \r
361 class xmlrpc_client {\r
362   var $path;\r
363   var $server;\r
364   var $port;\r
365   var $errno;\r
366   var $errstring;\r
367   var $debug=0;\r
368   var $username="";\r
369   var $password="";\r
370   var $cert="";\r
371   var $certpass="";\r
372   \r
373   function xmlrpc_client($path, $server, $port=0) {\r
374     $this->port=$port; $this->server=$server; $this->path=$path;\r
375   }\r
376 \r
377   function setDebug($in) {\r
378                 if ($in) { \r
379                         $this->debug=1;\r
380                 } else {\r
381                         $this->debug=0;\r
382                 }\r
383   }\r
384 \r
385   function setCredentials($u, $p) {\r
386     $this->username=$u;\r
387     $this->password=$p;\r
388   }\r
389 \r
390   function setCertificate($cert, $certpass) {\r
391     $this->cert = $cert;\r
392     $this->certpass = $certpass;\r
393   }\r
394 \r
395   function send($msg, $timeout=0, $method='http') {\r
396     // where msg is an xmlrpcmsg\r
397     $msg->debug=$this->debug;\r
398  \r
399     if ($method == 'https') {\r
400       return $this->sendPayloadHTTPS($msg,\r
401                                      $this->server,\r
402                                      $this->port, $timeout,\r
403                                      $this->username, $this->password,\r
404                                      $this->cert,\r
405                                      $this->certpass);\r
406     } else {\r
407       return $this->sendPayloadHTTP10($msg, $this->server, $this->port,\r
408                                       $timeout, $this->username, \r
409                                       $this->password);\r
410     }\r
411   }\r
412 \r
413   function sendPayloadHTTP10($msg, $server, $port, $timeout=0,\r
414                              $username="", $password="") {\r
415     if ($port==0) $port=80;\r
416     if($timeout>0)\r
417       $fp=@fsockopen($server, $port,\r
418                     $this->errno, $this->errstr, $timeout);\r
419     else\r
420       $fp=@fsockopen($server, $port,\r
421                     $this->errno, $this->errstr);\r
422     if (!$fp) {   \r
423       return 0;\r
424     }\r
425     // Only create the payload if it was not created previously\r
426     if(empty($msg->payload)) $msg->createPayload();\r
427     \r
428     // thanks to Grant Rauscher <grant7@firstworld.net>\r
429     // for this\r
430     $credentials="";\r
431     if ($username!="") {\r
432       $credentials="Authorization: Basic " .\r
433         base64_encode($username . ":" . $password) . "\r\n";\r
434     }\r
435     \r
436     $op= "POST " . $this->path. " HTTP/1.0\r\nUser-Agent: PHP XMLRPC 1.0\r\n" .\r
437       "Host: ". $this->server  . "\r\n" .\r
438       $credentials . \r
439       "Content-Type: text/xml\r\nContent-Length: " .\r
440       strlen($msg->payload) . "\r\n\r\n" .\r
441       $msg->payload;\r
442     \r
443     if (!fputs($fp, $op, strlen($op))) {\r
444       $this->errstr="Write error";\r
445       return 0;\r
446     }\r
447     $resp=$msg->parseResponseFile($fp);\r
448     fclose($fp);\r
449     return $resp;\r
450   }\r
451 \r
452   // contributed by Justin Miller <justin@voxel.net>\r
453   // requires curl to be built into PHP\r
454   function sendPayloadHTTPS($msg, $server, $port, $timeout=0,\r
455                             $username="", $password="", $cert="",\r
456                             $certpass="") {\r
457     global $xmlrpcerr, $xmlrpcstr;\r
458     if ($port == 0) $port = 443;\r
459     \r
460     // Only create the payload if it was not created previously\r
461     if(empty($msg->payload)) $msg->createPayload();\r
462     \r
463     if (!function_exists("curl_init")) {\r
464       $r=new xmlrpcresp(0, $xmlrpcerr["no_ssl"],\r
465                         $xmlrpcstr["no_ssl"]);\r
466       return $r;\r
467     }\r
468 \r
469     $curl = curl_init("https://" . $server . ':' . $port .\r
470                       $this->path);\r
471     \r
472     curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);\r
473     // results into variable\r
474     if ($this->debug) {\r
475       curl_setopt($curl, CURLOPT_VERBOSE, 1);\r
476     }\r
477     curl_setopt($curl, CURLOPT_USERAGENT, 'PHP XMLRPC 1.0');\r
478     // required for XMLRPC\r
479     curl_setopt($curl, CURLOPT_POST, 1);\r
480     // post the data\r
481     curl_setopt($curl, CURLOPT_POSTFIELDS, $msg->payload);\r
482     // the data\r
483     curl_setopt($curl, CURLOPT_HEADER, 1);\r
484     // return the header too\r
485     curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Type: text/xml'));\r
486     // required for XMLRPC\r
487     if ($timeout) curl_setopt($curl, CURLOPT_TIMEOUT, $timeout == 1 ? 1 :\r
488                               $timeout - 1);\r
489     // timeout is borked\r
490     if ($username && $password) curl_setopt($curl, CURLOPT_USERPWD,\r
491                                             "$username:$password"); \r
492     // set auth stuff\r
493     if ($cert) curl_setopt($curl, CURLOPT_SSLCERT, $cert);\r
494     // set cert file\r
495     if ($certpass) curl_setopt($curl, CURLOPT_SSLCERTPASSWD,\r
496                        $certpass);                    \r
497     // set cert password\r
498     \r
499     $result = curl_exec($curl);\r
500     \r
501     if (!$result) {\r
502       $resp=new xmlrpcresp(0, \r
503                            $xmlrpcerr["curl_fail"],\r
504                            $xmlrpcstr["curl_fail"]. ": ". \r
505                            curl_error($curl));\r
506     } else {\r
507       $resp = $msg->parseResponse($result);\r
508     }\r
509     curl_close($curl);\r
510     return $resp;\r
511   }\r
512 \r
513 } // end class xmlrpc_client\r
514 \r
515 class xmlrpcresp {\r
516   var $xv;\r
517   var $fn;\r
518   var $fs;\r
519   var $hdrs;\r
520 \r
521   function xmlrpcresp($val, $fcode=0, $fstr="") {\r
522     if ($fcode!=0) {\r
523       $this->xv=0;\r
524       $this->fn=$fcode;\r
525       $this->fs=htmlspecialchars($fstr);\r
526     } else {\r
527       $this->xv=$val;\r
528       $this->fn=0;\r
529     }\r
530   }\r
531 \r
532   function faultCode() { \r
533                 if (isset($this->fn)) \r
534                         return $this->fn;\r
535                 else\r
536                         return 0; \r
537         }\r
538 \r
539   function faultString() { return $this->fs; }\r
540   function value() { return $this->xv; }\r
541 \r
542   function serialize() { \r
543         $rs="<methodResponse>\n";\r
544         if ($this->fn) {\r
545           $rs.="<fault>\r
546   <value>\r
547     <struct>\r
548       <member>\r
549         <name>faultCode</name>\r
550         <value><int>" . $this->fn . "</int></value>\r
551       </member>\r
552       <member>\r
553         <name>faultString</name>\r
554         <value><string>" . $this->fs . "</string></value>\r
555       </member>\r
556     </struct>\r
557   </value>\r
558 </fault>";\r
559         } else {\r
560           $rs.="<params>\n<param>\n" . $this->xv->serialize() . \r
561                 "</param>\n</params>";\r
562         }\r
563         $rs.="\n</methodResponse>";\r
564         return $rs;\r
565   }\r
566 }\r
567 \r
568 class xmlrpcmsg {\r
569   var $payload;\r
570   var $methodname;\r
571   var $params=array();\r
572   var $debug=0;\r
573 \r
574   function xmlrpcmsg($meth, $pars=0) {\r
575                 $this->methodname=$meth;\r
576                 if (is_array($pars) && sizeof($pars)>0) {\r
577                         for($i=0; $i<sizeof($pars); $i++) \r
578                                 $this->addParam($pars[$i]);\r
579                 }\r
580   }\r
581 \r
582   function xml_header() {\r
583         return "<" . "?xml version=\"1.0\"?".">\n<methodCall>\n";\r
584   }\r
585 \r
586   function xml_footer() {\r
587         return "</methodCall>\n";\r
588   }\r
589 \r
590   function createPayload() {\r
591         $this->payload=$this->xml_header();\r
592         $this->payload.="<methodName>" . $this->methodname . "</methodName>\n";\r
593         //      if (sizeof($this->params)) {\r
594           $this->payload.="<params>\n";\r
595           for($i=0; $i<sizeof($this->params); $i++) {\r
596                 $p=$this->params[$i];\r
597                 $this->payload.="<param>\n" . $p->serialize() .\r
598                   "</param>\n";\r
599           }\r
600           $this->payload.="</params>\n";\r
601         // }\r
602         $this->payload.=$this->xml_footer();\r
603         $this->payload=str_replace("\n", "\r\n", $this->payload);\r
604   }\r
605 \r
606   function method($meth="") {\r
607         if ($meth!="") {\r
608           $this->methodname=$meth;\r
609         }\r
610         return $this->methodname;\r
611   }\r
612 \r
613   function serialize() {\r
614                 $this->createPayload();\r
615                 return $this->payload;\r
616   }\r
617 \r
618   function addParam($par) { $this->params[]=$par; }\r
619   function getParam($i) { return $this->params[$i]; }\r
620   function getNumParams() { return sizeof($this->params); }\r
621 \r
622   function parseResponseFile($fp) {\r
623         $ipd="";\r
624 \r
625         while($data=fread($fp, 32768)) {\r
626           $ipd.=$data;\r
627         }\r
628         return $this->parseResponse($ipd);\r
629   }\r
630 \r
631   function parseResponse($data="") {\r
632         global $_xh,$xmlrpcerr,$xmlrpcstr;\r
633         global $xmlrpc_defencoding;\r
634 \r
635         \r
636         $parser = xml_parser_create($xmlrpc_defencoding);\r
637 \r
638         $_xh[$parser]=array();\r
639 \r
640         $_xh[$parser]['st']=""; \r
641         $_xh[$parser]['cm']=0; \r
642         $_xh[$parser]['isf']=0; \r
643         $_xh[$parser]['ac']="";\r
644         $_xh[$parser]['qt']="";\r
645         $_xh[$parser]['ha']="";\r
646         $_xh[$parser]['ac']="";\r
647 \r
648         xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true);\r
649         xml_set_element_handler($parser, "xmlrpc_se", "xmlrpc_ee");\r
650         xml_set_character_data_handler($parser, "xmlrpc_cd");\r
651         xml_set_default_handler($parser, "xmlrpc_dh");\r
652         $xmlrpc_value=new xmlrpcval;\r
653 \r
654         if ($this->debug)\r
655           print "<PRE>---GOT---\n" . htmlspecialchars($data) . \r
656                 "\n---END---\n</PRE>";\r
657         if ($data=="") {\r
658           error_log("No response received from server.");\r
659           $r=new xmlrpcresp(0, $xmlrpcerr["no_data"],\r
660                             $xmlrpcstr["no_data"]);\r
661           xml_parser_free($parser);\r
662           return $r;\r
663         }\r
664         // see if we got an HTTP 200 OK, else bomb\r
665         // but only do this if we're using the HTTP protocol.\r
666         if (ereg("^HTTP",$data) && \r
667                         !ereg("^HTTP/[0-9\.]+ 200 ", $data)) {\r
668                 $errstr= substr($data, 0, strpos($data, "\n")-1);\r
669                 error_log("HTTP error, got response: " .$errstr);\r
670                 $r=new xmlrpcresp(0, $xmlrpcerr["http_error"],\r
671                                   $xmlrpcstr["http_error"]. " (" . $errstr . ")");\r
672                 xml_parser_free($parser);\r
673                 return $r;\r
674         }\r
675 \r
676         // if using HTTP, then gotta get rid of HTTP headers here\r
677         // and we store them in the 'ha' bit of our data array\r
678         if (ereg("^HTTP", $data)) {\r
679                 $ar=explode("\r\n", $data);\r
680                 $newdata="";\r
681                 $hdrfnd=0;\r
682                 for ($i=0; $i<sizeof($ar); $i++) {\r
683                         if (!$hdrfnd) {\r
684                                 if (strlen($ar[$i])>0) {\r
685                                         $_xh[$parser]['ha'].=$ar[$i]. "\r\n";\r
686                                 } else {\r
687                                         $hdrfnd=1; \r
688                                 }\r
689                         } else {\r
690                                 $newdata.=$ar[$i] . "\r\n";\r
691                         }\r
692                 }\r
693                 $data=$newdata;\r
694         }\r
695         \r
696         if (!xml_parse($parser, $data, sizeof($data))) {\r
697                 // thanks to Peter Kocks <peter.kocks@baygate.com>\r
698                 if((xml_get_current_line_number($parser)) == 1)   \r
699                         $errstr = "XML error at line 1, check URL";\r
700                 else\r
701                         $errstr = sprintf("XML error: %s at line %d",\r
702                                                                                                 xml_error_string(xml_get_error_code($parser)),\r
703                                                                                                 xml_get_current_line_number($parser));\r
704                 error_log($errstr);\r
705                 $r=new xmlrpcresp(0, $xmlrpcerr["invalid_return"],\r
706                                                                                         $xmlrpcstr["invalid_return"]);\r
707                 xml_parser_free($parser);\r
708                 return $r;\r
709         }\r
710         xml_parser_free($parser);\r
711         if ($this->debug) {\r
712           print "<PRE>---EVALING---[" . \r
713                 strlen($_xh[$parser]['st']) . " chars]---\n" . \r
714                 htmlspecialchars($_xh[$parser]['st']) . ";\n---END---</PRE>";\r
715         }\r
716         if (strlen($_xh[$parser]['st'])==0) {\r
717           // then something odd has happened\r
718           // and it's time to generate a client side error\r
719           // indicating something odd went on\r
720           $r=new xmlrpcresp(0, $xmlrpcerr["invalid_return"],\r
721                                                 $xmlrpcstr["invalid_return"]);\r
722         } else {\r
723           eval('$v=' . $_xh[$parser]['st'] . '; $allOK=1;');\r
724           if ($_xh[$parser]['isf']) {\r
725                 $f=$v->structmem("faultCode");\r
726                 $fs=$v->structmem("faultString");\r
727                 $r=new xmlrpcresp($v, $f->scalarval(), \r
728                                                   $fs->scalarval());\r
729           } else {\r
730                 $r=new xmlrpcresp($v);\r
731           }\r
732         }\r
733         $r->hdrs=split("\r?\n", $_xh[$parser]['ha']);\r
734         return $r;\r
735   }\r
736 \r
737 }\r
738 \r
739 class xmlrpcval {\r
740   var $me=array();\r
741   var $mytype=0;\r
742 \r
743   function xmlrpcval($val=-1, $type="") {\r
744                 global $xmlrpcTypes;\r
745                 $this->me=array();\r
746                 $this->mytype=0;\r
747                 if ($val!=-1 || $type!="") {\r
748                         if ($type=="") $type="string";\r
749                         if ($xmlrpcTypes[$type]==1) {\r
750                                 $this->addScalar($val,$type);\r
751                         }\r
752           else if ($xmlrpcTypes[$type]==2)\r
753                         $this->addArray($val);\r
754                         else if ($xmlrpcTypes[$type]==3)\r
755                                 $this->addStruct($val);\r
756                 }\r
757   }\r
758 \r
759   function addScalar($val, $type="string") {\r
760                 global $xmlrpcTypes, $xmlrpcBoolean;\r
761 \r
762                 if ($this->mytype==1) {\r
763                         echo "<B>xmlrpcval</B>: scalar can have only one value<BR>";\r
764                         return 0;\r
765                 }\r
766                 $typeof=$xmlrpcTypes[$type];\r
767                 if ($typeof!=1) {\r
768                         echo "<B>xmlrpcval</B>: not a scalar type (${typeof})<BR>";\r
769                         return 0;\r
770                 }\r
771                 \r
772                 if ($type==$xmlrpcBoolean) {\r
773                         if (strcasecmp($val,"true")==0 || \r
774                                         $val==1 || ($val==true &&\r
775                                                                                         strcasecmp($val,"false"))) {\r
776                                 $val=1;\r
777                         } else {\r
778                                 $val=0;\r
779                         }\r
780                 }\r
781                 \r
782                 if ($this->mytype==2) {\r
783                         // we're adding to an array here\r
784                         $ar=$this->me["array"];\r
785                         $ar[]=new xmlrpcval($val, $type);\r
786                         $this->me["array"]=$ar;\r
787                 } else {\r
788                         // a scalar, so set the value and remember we're scalar\r
789                         $this->me[$type]=$val;\r
790                         $this->mytype=$typeof;\r
791                 }\r
792                 return 1;\r
793   }\r
794 \r
795   function addArray($vals) {\r
796                 global $xmlrpcTypes;\r
797                 if ($this->mytype!=0) {\r
798                         echo "<B>xmlrpcval</B>: already initialized as a [" . \r
799                                 $this->kindOf() . "]<BR>";\r
800                         return 0;\r
801                 }\r
802 \r
803                 $this->mytype=$xmlrpcTypes["array"];\r
804                 $this->me["array"]=$vals;\r
805                 return 1;\r
806   }\r
807 \r
808   function addStruct($vals) {\r
809         global $xmlrpcTypes;\r
810         if ($this->mytype!=0) {\r
811           echo "<B>xmlrpcval</B>: already initialized as a [" . \r
812                 $this->kindOf() . "]<BR>";\r
813           return 0;\r
814         }\r
815         $this->mytype=$xmlrpcTypes["struct"];\r
816         $this->me["struct"]=$vals;\r
817         return 1;\r
818   }\r
819 \r
820   function dump($ar) {\r
821         reset($ar);\r
822         while ( list( $key, $val ) = each( $ar ) ) {\r
823           echo "$key => $val<br>";\r
824           if ($key == 'array')\r
825                 while ( list( $key2, $val2 ) = each( $val ) ) {\r
826                   echo "-- $key2 => $val2<br>";\r
827                 }\r
828         }\r
829   }\r
830 \r
831   function kindOf() {\r
832         switch($this->mytype) {\r
833         case 3:\r
834           return "struct";\r
835           break;\r
836         case 2:\r
837           return "array";\r
838           break;\r
839         case 1:\r
840           return "scalar";\r
841           break;\r
842         default:\r
843           return "undef";\r
844         }\r
845   }\r
846 \r
847   function serializedata($typ, $val) {\r
848                 $rs="";\r
849                 global $xmlrpcTypes, $xmlrpcBase64, $xmlrpcString,\r
850                         $xmlrpcBoolean;\r
851                 switch($xmlrpcTypes[$typ]) {\r
852                 case 3:\r
853                         // struct\r
854                         $rs.="<struct>\n";\r
855                         reset($val);\r
856                         while(list($key2, $val2)=each($val)) {\r
857                                 $rs.="<member><name>${key2}</name>\n";\r
858                                 $rs.=$this->serializeval($val2);\r
859                                 $rs.="</member>\n";\r
860                         }\r
861                         $rs.="</struct>";\r
862                         break;\r
863                 case 2:\r
864                         // array\r
865                         $rs.="<array>\n<data>\n";\r
866                         for($i=0; $i<sizeof($val); $i++) {\r
867                                 $rs.=$this->serializeval($val[$i]);\r
868                         }\r
869                         $rs.="</data>\n</array>";\r
870                         break;\r
871                 case 1:\r
872                         switch ($typ) {\r
873                         case $xmlrpcBase64:\r
874                                 $rs.="<${typ}>" . base64_encode($val) . "</${typ}>";\r
875                                 break;\r
876                         case $xmlrpcBoolean:\r
877                                 $rs.="<${typ}>" . ($val ? "1" : "0") . "</${typ}>";\r
878                                         break;\r
879                         case $xmlrpcString:\r
880                                 $rs.="<${typ}>" . htmlspecialchars($val). "</${typ}>";\r
881                                 break;\r
882                         default:\r
883                                 $rs.="<${typ}>${val}</${typ}>";\r
884                         }\r
885                         break;\r
886                 default:\r
887                         break;\r
888                 }\r
889                 return $rs;\r
890   }\r
891 \r
892   function serialize() {\r
893         return $this->serializeval($this);\r
894   }\r
895 \r
896   function serializeval($o) {\r
897                 global $xmlrpcTypes;\r
898                 $rs="";\r
899                 $ar=$o->me;\r
900                 reset($ar);\r
901                 list($typ, $val) = each($ar);\r
902                 $rs.="<value>";\r
903                 $rs.=$this->serializedata($typ, $val);\r
904                 $rs.="</value>\n";\r
905                 return $rs;\r
906   }\r
907 \r
908   function structmem($m) {\r
909                 $nv=$this->me["struct"][$m];\r
910                 return $nv;\r
911   }\r
912 \r
913         function structreset() {\r
914                 reset($this->me["struct"]);\r
915         }\r
916         \r
917         function structeach() {\r
918                 return each($this->me["struct"]);\r
919         }\r
920 \r
921   function getval() {\r
922                 // UNSTABLE\r
923                 global $xmlrpcBoolean, $xmlrpcBase64;\r
924                 reset($this->me);\r
925                 list($a,$b)=each($this->me);\r
926                 // contributed by I Sofer, 2001-03-24\r
927                 // add support for nested arrays to scalarval\r
928                 // i've created a new method here, so as to\r
929                 // preserve back compatibility\r
930 \r
931                 if (is_array($b))    {\r
932                         foreach ($b as $id => $cont) {\r
933                                 $b[$id] = $cont->scalarval();\r
934                         }\r
935                 }\r
936 \r
937                 // add support for structures directly encoding php objects\r
938                 if (is_object($b))  {\r
939                         $t = get_object_vars($b);\r
940                         foreach ($t as $id => $cont) {\r
941                                 $t[$id] = $cont->scalarval();\r
942                         }\r
943                         foreach ($t as $id => $cont) {\r
944                                 eval('$b->'.$id.' = $cont;');\r
945                         }\r
946                 }\r
947                 // end contrib\r
948                 return $b;\r
949   }\r
950 \r
951   function scalarval() {\r
952                 global $xmlrpcBoolean, $xmlrpcBase64;\r
953                 reset($this->me);\r
954                 list($a,$b)=each($this->me);\r
955                 return $b;\r
956   }\r
957 \r
958   function scalartyp() {\r
959                 global $xmlrpcI4, $xmlrpcInt;\r
960                 reset($this->me);\r
961                 list($a,$b)=each($this->me);\r
962                 if ($a==$xmlrpcI4) \r
963                         $a=$xmlrpcInt;\r
964                 return $a;\r
965   }\r
966 \r
967   function arraymem($m) {\r
968                 $nv=$this->me["array"][$m];\r
969                 return $nv;\r
970   }\r
971 \r
972   function arraysize() {\r
973                 reset($this->me);\r
974                 list($a,$b)=each($this->me);\r
975                 return sizeof($b);\r
976   }\r
977 }\r
978 \r
979 // date helpers\r
980 function iso8601_encode($timet, $utc=0) {\r
981         // return an ISO8601 encoded string\r
982         // really, timezones ought to be supported\r
983         // but the XML-RPC spec says:\r
984         //\r
985         // "Don't assume a timezone. It should be specified by the server in its\r
986   // documentation what assumptions it makes about timezones."\r
987         // \r
988         // these routines always assume localtime unless \r
989         // $utc is set to 1, in which case UTC is assumed\r
990         // and an adjustment for locale is made when encoding\r
991         if (!$utc) {\r
992                 $t=strftime("%Y%m%dT%H:%M:%S", $timet);\r
993         } else {\r
994                 if (function_exists("gmstrftime")) \r
995                         // gmstrftime doesn't exist in some versions\r
996                         // of PHP\r
997                         $t=gmstrftime("%Y%m%dT%H:%M:%S", $timet);\r
998                 else {\r
999                         $t=strftime("%Y%m%dT%H:%M:%S", $timet-date("Z"));\r
1000                 }\r
1001         }\r
1002         return $t;\r
1003 }\r
1004 \r
1005 function iso8601_decode($idate, $utc=0) {\r
1006         // return a timet in the localtime, or UTC\r
1007         $t=0;\r
1008         if (ereg("([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})",\r
1009                                          $idate, $regs)) {\r
1010                 if ($utc) {\r
1011                         $t=gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);\r
1012                 } else {\r
1013                         $t=mktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);\r
1014                 }\r
1015         } \r
1016         return $t;\r
1017 }\r
1018 \r
1019 /****************************************************************\r
1020 * xmlrpc_decode takes a message in PHP xmlrpc object format and *\r
1021 * tranlates it into native PHP types.                           *\r
1022 *                                                               *\r
1023 * author: Dan Libby (dan@libby.com)                             *\r
1024 ****************************************************************/\r
1025 function _xmlrpc_decode($xmlrpc_val) {\r
1026    $kind = $xmlrpc_val->kindOf();\r
1027 \r
1028    if($kind == "scalar") {\r
1029       return $xmlrpc_val->scalarval();\r
1030    }\r
1031    else if($kind == "array") {\r
1032       $size = $xmlrpc_val->arraysize();\r
1033       $arr = array();\r
1034 \r
1035       for($i = 0; $i < $size; $i++) {\r
1036          $arr[]=_xmlrpc_decode($xmlrpc_val->arraymem($i));\r
1037       }\r
1038       return $arr; \r
1039    }\r
1040    else if($kind == "struct") {\r
1041       $xmlrpc_val->structreset();\r
1042       $arr = array();\r
1043 \r
1044       while(list($key,$value)=$xmlrpc_val->structeach()) {\r
1045          $arr[$key] = _xmlrpc_decode($value);\r
1046       }\r
1047       return $arr;\r
1048    }\r
1049 }\r
1050 \r
1051 /****************************************************************\r
1052 * xmlrpc_encode takes native php types and encodes them into    *\r
1053 * xmlrpc PHP object format.                                     *\r
1054 * BUG: All sequential arrays are turned into structs.  I don't  *\r
1055 * know of a good way to determine if an array is sequential     *\r
1056 * only.                                                         *\r
1057 *                                                               *\r
1058 * feature creep -- could support more types via optional type   *\r
1059 * argument.                                                     *\r
1060 *                                                               *\r
1061 * author: Dan Libby (dan@libby.com)                             *\r
1062 ****************************************************************/\r
1063 function _xmlrpc_encode($php_val) {\r
1064    global $xmlrpcInt;\r
1065    global $xmlrpcDouble;\r
1066    global $xmlrpcString;\r
1067    global $xmlrpcArray;\r
1068    global $xmlrpcStruct;\r
1069    global $xmlrpcBoolean;\r
1070 \r
1071    $type = gettype($php_val);\r
1072    $xmlrpc_val = new xmlrpcval;\r
1073 \r
1074    switch($type) {\r
1075       case "array":\r
1076       case "object":\r
1077          $arr = array();\r
1078          while (list($k,$v) = each($php_val)) {\r
1079             $arr[$k] = _xmlrpc_encode($v);\r
1080          }\r
1081          $xmlrpc_val->addStruct($arr);\r
1082          break;\r
1083       case "integer":\r
1084          $xmlrpc_val->addScalar($php_val, $xmlrpcInt);\r
1085          break;\r
1086       case "double":\r
1087          $xmlrpc_val->addScalar($php_val, $xmlrpcDouble);\r
1088          break;\r
1089       case "string":\r
1090          $xmlrpc_val->addScalar($php_val, $xmlrpcString);\r
1091          break;\r
1092 // <G_Giunta_2001-02-29>\r
1093 // Add support for encoding/decoding of booleans, since they are supported in PHP\r
1094       case "boolean":\r
1095          $xmlrpc_val->addScalar($php_val, $xmlrpcBoolean);\r
1096          break;\r
1097 // </G_Giunta_2001-02-29>\r
1098       case "unknown type":\r
1099       default:\r
1100         // giancarlo pinerolo <ping@alt.it>\r
1101         // it has to return \r
1102         // an empty object in case (which is already\r
1103         // at this point), not a boolean. \r
1104         break;\r
1105    }\r
1106    return $xmlrpc_val;\r
1107 }\r
1108 \r
1109 ?>\r