OSDN Git Service

df3dce7b74cb8ebb9bd507a85357149033e334a3
[nucleus-jp/nucleus-jp-ancient.git] / utf8 / nucleus / libs / xmlrpc.inc.php
1 <?php                                   // -*-c++-*-\r
2 // by Edd Dumbill (C) 1999-2002\r
3 // <edd@usefulinc.com>\r
4 // $Id: xmlrpc.inc.php,v 1.4.4.2 2005-08-16 05:26:18 kimitake Exp $\r
5 // $NucleusJP: xmlrpc.inc.php,v 1.4.2.2 2005/07/03 05:16:44 kimitake Exp $\r
6 \r
7 // Copyright (c) 1999,2000,2002 Edd Dumbill.\r
8 // All rights reserved.\r
9 //\r
10 // Redistribution and use in source and binary forms, with or without\r
11 // modification, are permitted provided that the following conditions\r
12 // are met:\r
13 //\r
14 //    * Redistributions of source code must retain the above copyright\r
15 //      notice, this list of conditions and the following disclaimer.\r
16 //\r
17 //    * Redistributions in binary form must reproduce the above\r
18 //      copyright notice, this list of conditions and the following\r
19 //      disclaimer in the documentation and/or other materials provided\r
20 //      with the distribution.\r
21 //\r
22 //    * Neither the name of the "XML-RPC for PHP" nor the names of its\r
23 //      contributors may be used to endorse or promote products derived\r
24 //      from this software without specific prior written permission.\r
25 //\r
26 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
27 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
28 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\r
29 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\r
30 // REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
31 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
32 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\r
33 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r
34 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\r
35 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r
36 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\r
37 // OF THE POSSIBILITY OF SUCH DAMAGE.\r
38 \r
39         if (!function_exists('xml_parser_create'))\r
40         {\r
41                 // Win 32 fix. From: 'Leo West' <lwest@imaginet.fr>\r
42                 if($WINDIR)\r
43                 {\r
44                         dl('php3_xml.dll');\r
45                 }\r
46                 else\r
47                 {\r
48                         dl('xml.so');\r
49                 }\r
50         }\r
51 \r
52         // G. Giunta 2005/01/29: declare global these variables,\r
53         // so that xmlrpc.inc will work even if included from within a function\r
54         // NB: it will give warnings in PHP3, so we comment it out\r
55         // Milosch: Next round, maybe we should explicitly request these via $GLOBALS where used.\r
56         if (phpversion() >= '4')\r
57         {\r
58                 global $xmlrpcI4;\r
59                 global $xmlrpcInt;\r
60                 global $xmlrpcDouble;\r
61                 global $xmlrpcBoolean;\r
62                 global $xmlrpcString;\r
63                 global $xmlrpcDateTime;\r
64                 global $xmlrpcBase64;\r
65                 global $xmlrpcArray;\r
66                 global $xmlrpcStruct;\r
67 \r
68                 global $xmlrpcTypes;\r
69                 global $xmlEntities;\r
70                 global $xmlrpcerr;\r
71                 global $xmlrpcstr;\r
72                 global $xmlrpc_defencoding;\r
73                 global $xmlrpc_internalencoding;\r
74                 global $xmlrpcName;\r
75                 global $xmlrpcVersion;\r
76                 global $xmlrpcerruser;\r
77                 global $xmlrpcerrxml;\r
78                 global $xmlrpc_backslash;\r
79                 global $_xh;\r
80         }\r
81         $xmlrpcI4='i4';\r
82         $xmlrpcInt='int';\r
83         $xmlrpcBoolean='boolean';\r
84         $xmlrpcDouble='double';\r
85         $xmlrpcString='string';\r
86         $xmlrpcDateTime='dateTime.iso8601';\r
87         $xmlrpcBase64='base64';\r
88         $xmlrpcArray='array';\r
89         $xmlrpcStruct='struct';\r
90 \r
91         $xmlrpcTypes=array(\r
92                 $xmlrpcI4       => 1,\r
93                 $xmlrpcInt      => 1,\r
94                 $xmlrpcBoolean  => 1,\r
95                 $xmlrpcString   => 1,\r
96                 $xmlrpcDouble   => 1,\r
97                 $xmlrpcDateTime => 1,\r
98                 $xmlrpcBase64   => 1,\r
99                 $xmlrpcArray    => 2,\r
100                 $xmlrpcStruct   => 3\r
101         );\r
102 \r
103         $xmlrpc_valid_parents = array(\r
104                 'BOOLEAN' => array('VALUE'),\r
105                 'I4' => array('VALUE'),\r
106                 'INT' => array('VALUE'),\r
107                 'STRING' => array('VALUE'),\r
108                 'DOUBLE' => array('VALUE'),\r
109                 'DATETIME.ISO8601' => array('VALUE'),\r
110                 'BASE64' => array('VALUE'),\r
111                 'ARRAY' => array('VALUE'),\r
112                 'STRUCT' => array('VALUE'),\r
113                 'PARAM' => array('PARAMS'),\r
114                 'METHODNAME' => array('METHODCALL'),            \r
115                 'PARAMS' => array('METHODCALL', 'METHODRESPONSE'),\r
116                 'MEMBER' => array('STRUCT'),\r
117                 'NAME' => array('MEMBER'),\r
118                 'DATA' => array('ARRAY'),\r
119                 'FAULT' => array('METHODRESPONSE'),\r
120                 'VALUE' => array('MEMBER', 'DATA', 'PARAM', 'FAULT'),\r
121         );\r
122 \r
123         $xmlEntities=array(\r
124                 'amp'  => '&',\r
125                 'quot' => '"',\r
126                 'lt'   => '<',\r
127                 'gt'   => '>',\r
128                 'apos' => "'"\r
129         );\r
130 \r
131         $xmlrpcerr['unknown_method']=1;\r
132         $xmlrpcstr['unknown_method']='Unknown method';\r
133         $xmlrpcerr['invalid_return']=2;\r
134         $xmlrpcstr['invalid_return']='Invalid return payload: enable debugging to examine incoming payload';\r
135         $xmlrpcerr['incorrect_params']=3;\r
136         $xmlrpcstr['incorrect_params']='Incorrect parameters passed to method';\r
137         $xmlrpcerr['introspect_unknown']=4;\r
138         $xmlrpcstr['introspect_unknown']="Can't introspect: method unknown";\r
139         $xmlrpcerr['http_error']=5;\r
140         $xmlrpcstr['http_error']="Didn't receive 200 OK from remote server.";\r
141         $xmlrpcerr['no_data']=6;\r
142         $xmlrpcstr['no_data']='No data received from server.';\r
143         $xmlrpcerr['no_ssl']=7;\r
144         $xmlrpcstr['no_ssl']='No SSL support compiled in.';\r
145         $xmlrpcerr['curl_fail']=8;\r
146         $xmlrpcstr['curl_fail']='CURL error';\r
147         $xmlrpcerr['invalid_request']=15;\r
148         $xmlrpcstr['invalid_request']='Invalid request payload';\r
149 \r
150         $xmlrpcerr['multicall_notstruct'] = 9;\r
151         $xmlrpcstr['multicall_notstruct'] = 'system.multicall expected struct';\r
152         $xmlrpcerr['multicall_nomethod']  = 10;\r
153         $xmlrpcstr['multicall_nomethod']  = 'missing methodName';\r
154         $xmlrpcerr['multicall_notstring'] = 11;\r
155         $xmlrpcstr['multicall_notstring'] = 'methodName is not a string';\r
156         $xmlrpcerr['multicall_recursion'] = 12;\r
157         $xmlrpcstr['multicall_recursion'] = 'recursive system.multicall forbidden';\r
158         $xmlrpcerr['multicall_noparams']  = 13;\r
159         $xmlrpcstr['multicall_noparams']  = 'missing params';\r
160         $xmlrpcerr['multicall_notarray']  = 14;\r
161         $xmlrpcstr['multicall_notarray']  = 'params is not an array';\r
162 \r
163         // The charset encoding expected by the server for received messages and\r
164         // by the client for received responses\r
165         $xmlrpc_defencoding='UTF-8';\r
166         // The encoding used by PHP.\r
167         // String values received will be converted to this.\r
168         $xmlrpc_internalencoding='ISO-8859-1';\r
169 \r
170         $xmlrpcName='XML-RPC for PHP';\r
171         $xmlrpcVersion='1.2';\r
172 \r
173         // let user errors start at 800\r
174         $xmlrpcerruser=800;\r
175         // let XML parse errors start at 100\r
176         $xmlrpcerrxml=100;\r
177 \r
178         // formulate backslashes for escaping regexp\r
179         $xmlrpc_backslash=chr(92).chr(92);\r
180 \r
181         // used to store state during parsing\r
182         // quick explanation of components:\r
183         //   ac - used to accumulate values\r
184         //   isf - used to indicate a fault\r
185         //   lv - used to indicate "looking for a value": implements\r
186         //        the logic to allow values with no types to be strings\r
187         //   params - used to store parameters in method calls\r
188         //   method - used to store method name\r
189         //   stack - array with genealogy of xml elements names:\r
190         //           used to validate nesting of xmlrpc elements\r
191 \r
192         $_xh=array();\r
193 \r
194         /**\r
195         * To help correct communication of non-ascii chars inside strings, regardless\r
196         * of the charset used when sending requests, parsing them, sending responses\r
197         * and parsing responses, convert all non-ascii chars present in the message\r
198         * into their equivalent 'charset entity'. Charset entities enumerated this way\r
199         * are independent of the charset encoding used to transmit them, and all XML\r
200         * parsers are bound to understand them.\r
201         */\r
202         function xmlrpc_entity_decode($string)\r
203         {\r
204                 $top=split('&', $string);\r
205                 $op='';\r
206                 $i=0;\r
207                 while($i<sizeof($top))\r
208                 {\r
209                         if (ereg("^([#a-zA-Z0-9]+);", $top[$i], $regs))\r
210                         {\r
211                                 $op.=ereg_replace("^[#a-zA-Z0-9]+;",\r
212                                 xmlrpc_lookup_entity($regs[1]),\r
213                                 $top[$i]);\r
214                         }\r
215                         else\r
216                         {\r
217                                 if ($i==0)\r
218                                 {\r
219                                         $op=$top[$i];\r
220                                 }\r
221                                 else\r
222                                 {\r
223                                         $op.='&' . $top[$i];\r
224                                 }\r
225                         }\r
226                         $i++;\r
227                 }\r
228                 return $op;\r
229         }\r
230 \r
231         function xmlrpc_lookup_entity($ent)\r
232         {\r
233                 global $xmlEntities;\r
234 \r
235                 if (isset($xmlEntities[strtolower($ent)]))\r
236                 {\r
237                         return $xmlEntities[strtolower($ent)];\r
238                 }\r
239                 if (ereg("^#([0-9]+)$", $ent, $regs))\r
240                 {\r
241                         return chr($regs[1]);\r
242                 }\r
243                 return '?';\r
244         }\r
245 \r
246         /**\r
247          * These entities originate from HTML specs (1.1, proposed 2.0, etc),\r
248          * and are taken directly from php-4.3.1/ext/mbstring/html_entities.c.\r
249          * Until php provides functionality to translate these entities in its\r
250          * core library, use this function.\r
251          */\r
252         function xmlrpc_html_entity_xlate($data = '')\r
253         {\r
254                 $entities = array(\r
255                         "&nbsp;" => "&#160;",\r
256                         "&iexcl;" => "&#161;",\r
257                         "&cent;" => "&#162;",\r
258                         "&pound;" => "&#163;",\r
259                         "&curren;" => "&#164;",\r
260                         "&yen;" => "&#165;",\r
261                         "&brvbar;" => "&#166;",\r
262                         "&sect;" => "&#167;",\r
263                         "&uml;" => "&#168;",\r
264                         "&copy;" => "&#169;",\r
265                         "&ordf;" => "&#170;",\r
266                         "&laquo;" => "&#171;",\r
267                         "&not;" => "&#172;",\r
268                         "&shy;" => "&#173;",\r
269                         "&reg;" => "&#174;",\r
270                         "&macr;" => "&#175;",\r
271                         "&deg;" => "&#176;",\r
272                         "&plusmn;" => "&#177;",\r
273                         "&sup2;" => "&#178;",\r
274                         "&sup3;" => "&#179;",\r
275                         "&acute;" => "&#180;",\r
276                         "&micro;" => "&#181;",\r
277                         "&para;" => "&#182;",\r
278                         "&middot;" => "&#183;",\r
279                         "&cedil;" => "&#184;",\r
280                         "&sup1;" => "&#185;",\r
281                         "&ordm;" => "&#186;",\r
282                         "&raquo;" => "&#187;",\r
283                         "&frac14;" => "&#188;",\r
284                         "&frac12;" => "&#189;",\r
285                         "&frac34;" => "&#190;",\r
286                         "&iquest;" => "&#191;",\r
287                         "&Agrave;" => "&#192;",\r
288                         "&Aacute;" => "&#193;",\r
289                         "&Acirc;" => "&#194;",\r
290                         "&Atilde;" => "&#195;",\r
291                         "&Auml;" => "&#196;",\r
292                         "&Aring;" => "&#197;",\r
293                         "&AElig;" => "&#198;",\r
294                         "&Ccedil;" => "&#199;",\r
295                         "&Egrave;" => "&#200;",\r
296                         "&Eacute;" => "&#201;",\r
297                         "&Ecirc;" => "&#202;",\r
298                         "&Euml;" => "&#203;",\r
299                         "&Igrave;" => "&#204;",\r
300                         "&Iacute;" => "&#205;",\r
301                         "&Icirc;" => "&#206;",\r
302                         "&Iuml;" => "&#207;",\r
303                         "&ETH;" => "&#208;",\r
304                         "&Ntilde;" => "&#209;",\r
305                         "&Ograve;" => "&#210;",\r
306                         "&Oacute;" => "&#211;",\r
307                         "&Ocirc;" => "&#212;",\r
308                         "&Otilde;" => "&#213;",\r
309                         "&Ouml;" => "&#214;",\r
310                         "&times;" => "&#215;",\r
311                         "&Oslash;" => "&#216;",\r
312                         "&Ugrave;" => "&#217;",\r
313                         "&Uacute;" => "&#218;",\r
314                         "&Ucirc;" => "&#219;",\r
315                         "&Uuml;" => "&#220;",\r
316                         "&Yacute;" => "&#221;",\r
317                         "&THORN;" => "&#222;",\r
318                         "&szlig;" => "&#223;",\r
319                         "&agrave;" => "&#224;",\r
320                         "&aacute;" => "&#225;",\r
321                         "&acirc;" => "&#226;",\r
322                         "&atilde;" => "&#227;",\r
323                         "&auml;" => "&#228;",\r
324                         "&aring;" => "&#229;",\r
325                         "&aelig;" => "&#230;",\r
326                         "&ccedil;" => "&#231;",\r
327                         "&egrave;" => "&#232;",\r
328                         "&eacute;" => "&#233;",\r
329                         "&ecirc;" => "&#234;",\r
330                         "&euml;" => "&#235;",\r
331                         "&igrave;" => "&#236;",\r
332                         "&iacute;" => "&#237;",\r
333                         "&icirc;" => "&#238;",\r
334                         "&iuml;" => "&#239;",\r
335                         "&eth;" => "&#240;",\r
336                         "&ntilde;" => "&#241;",\r
337                         "&ograve;" => "&#242;",\r
338                         "&oacute;" => "&#243;",\r
339                         "&ocirc;" => "&#244;",\r
340                         "&otilde;" => "&#245;",\r
341                         "&ouml;" => "&#246;",\r
342                         "&divide;" => "&#247;",\r
343                         "&oslash;" => "&#248;",\r
344                         "&ugrave;" => "&#249;",\r
345                         "&uacute;" => "&#250;",\r
346                         "&ucirc;" => "&#251;",\r
347                         "&uuml;" => "&#252;",\r
348                         "&yacute;" => "&#253;",\r
349                         "&thorn;" => "&#254;",\r
350                         "&yuml;" => "&#255;",\r
351                         "&OElig;" => "&#338;",\r
352                         "&oelig;" => "&#339;",\r
353                         "&Scaron;" => "&#352;",\r
354                         "&scaron;" => "&#353;",\r
355                         "&Yuml;" => "&#376;",\r
356                         "&fnof;" => "&#402;",\r
357                         "&circ;" => "&#710;",\r
358                         "&tilde;" => "&#732;",\r
359                         "&Alpha;" => "&#913;",\r
360                         "&Beta;" => "&#914;",\r
361                         "&Gamma;" => "&#915;",\r
362                         "&Delta;" => "&#916;",\r
363                         "&Epsilon;" => "&#917;",\r
364                         "&Zeta;" => "&#918;",\r
365                         "&Eta;" => "&#919;",\r
366                         "&Theta;" => "&#920;",\r
367                         "&Iota;" => "&#921;",\r
368                         "&Kappa;" => "&#922;",\r
369                         "&Lambda;" => "&#923;",\r
370                         "&Mu;" => "&#924;",\r
371                         "&Nu;" => "&#925;",\r
372                         "&Xi;" => "&#926;",\r
373                         "&Omicron;" => "&#927;",\r
374                         "&Pi;" => "&#928;",\r
375                         "&Rho;" => "&#929;",\r
376                         "&Sigma;" => "&#931;",\r
377                         "&Tau;" => "&#932;",\r
378                         "&Upsilon;" => "&#933;",\r
379                         "&Phi;" => "&#934;",\r
380                         "&Chi;" => "&#935;",\r
381                         "&Psi;" => "&#936;",\r
382                         "&Omega;" => "&#937;",\r
383                         "&beta;" => "&#946;",\r
384                         "&gamma;" => "&#947;",\r
385                         "&delta;" => "&#948;",\r
386                         "&epsilon;" => "&#949;",\r
387                         "&zeta;" => "&#950;",\r
388                         "&eta;" => "&#951;",\r
389                         "&theta;" => "&#952;",\r
390                         "&iota;" => "&#953;",\r
391                         "&kappa;" => "&#954;",\r
392                         "&lambda;" => "&#955;",\r
393                         "&mu;" => "&#956;",\r
394                         "&nu;" => "&#957;",\r
395                         "&xi;" => "&#958;",\r
396                         "&omicron;" => "&#959;",\r
397                         "&pi;" => "&#960;",\r
398                         "&rho;" => "&#961;",\r
399                         "&sigmaf;" => "&#962;",\r
400                         "&sigma;" => "&#963;",\r
401                         "&tau;" => "&#964;",\r
402                         "&upsilon;" => "&#965;",\r
403                         "&phi;" => "&#966;",\r
404                         "&chi;" => "&#967;",\r
405                         "&psi;" => "&#968;",\r
406                         "&omega;" => "&#969;",\r
407                         "&thetasym;" => "&#977;",\r
408                         "&upsih;" => "&#978;",\r
409                         "&piv;" => "&#982;",\r
410                         "&ensp;" => "&#8194;",\r
411                         "&emsp;" => "&#8195;",\r
412                         "&thinsp;" => "&#8201;",\r
413                         "&zwnj;" => "&#8204;",\r
414                         "&zwj;" => "&#8205;",\r
415                         "&lrm;" => "&#8206;",\r
416                         "&rlm;" => "&#8207;",\r
417                         "&ndash;" => "&#8211;",\r
418                         "&mdash;" => "&#8212;",\r
419                         "&lsquo;" => "&#8216;",\r
420                         "&rsquo;" => "&#8217;",\r
421                         "&sbquo;" => "&#8218;",\r
422                         "&ldquo;" => "&#8220;",\r
423                         "&rdquo;" => "&#8221;",\r
424                         "&bdquo;" => "&#8222;",\r
425                         "&dagger;" => "&#8224;",\r
426                         "&Dagger;" => "&#8225;",\r
427                         "&bull;" => "&#8226;",\r
428                         "&hellip;" => "&#8230;",\r
429                         "&permil;" => "&#8240;",\r
430                         "&prime;" => "&#8242;",\r
431                         "&Prime;" => "&#8243;",\r
432                         "&lsaquo;" => "&#8249;",\r
433                         "&rsaquo;" => "&#8250;",\r
434                         "&oline;" => "&#8254;",\r
435                         "&frasl;" => "&#8260;",\r
436                         "&euro;" => "&#8364;",\r
437                         "&weierp;" => "&#8472;",\r
438                         "&image;" => "&#8465;",\r
439                         "&real;" => "&#8476;",\r
440                         "&trade;" => "&#8482;",\r
441                         "&alefsym;" => "&#8501;",\r
442                         "&larr;" => "&#8592;",\r
443                         "&uarr;" => "&#8593;",\r
444                         "&rarr;" => "&#8594;",\r
445                         "&darr;" => "&#8595;",\r
446                         "&harr;" => "&#8596;",\r
447                         "&crarr;" => "&#8629;",\r
448                         "&lArr;" => "&#8656;",\r
449                         "&uArr;" => "&#8657;",\r
450                         "&rArr;" => "&#8658;",\r
451                         "&dArr;" => "&#8659;",\r
452                         "&hArr;" => "&#8660;",\r
453                         "&forall;" => "&#8704;",\r
454                         "&part;" => "&#8706;",\r
455                         "&exist;" => "&#8707;",\r
456                         "&empty;" => "&#8709;",\r
457                         "&nabla;" => "&#8711;",\r
458                         "&isin;" => "&#8712;",\r
459                         "&notin;" => "&#8713;",\r
460                         "&ni;" => "&#8715;",\r
461                         "&prod;" => "&#8719;",\r
462                         "&sum;" => "&#8721;",\r
463                         "&minus;" => "&#8722;",\r
464                         "&lowast;" => "&#8727;",\r
465                         "&radic;" => "&#8730;",\r
466                         "&prop;" => "&#8733;",\r
467                         "&infin;" => "&#8734;",\r
468                         "&ang;" => "&#8736;",\r
469                         "&and;" => "&#8743;",\r
470                         "&or;" => "&#8744;",\r
471                         "&cap;" => "&#8745;",\r
472                         "&cup;" => "&#8746;",\r
473                         "&int;" => "&#8747;",\r
474                         "&there4;" => "&#8756;",\r
475                         "&sim;" => "&#8764;",\r
476                         "&cong;" => "&#8773;",\r
477                         "&asymp;" => "&#8776;",\r
478                         "&ne;" => "&#8800;",\r
479                         "&equiv;" => "&#8801;",\r
480                         "&le;" => "&#8804;",\r
481                         "&ge;" => "&#8805;",\r
482                         "&sub;" => "&#8834;",\r
483                         "&sup;" => "&#8835;",\r
484                         "&nsub;" => "&#8836;",\r
485                         "&sube;" => "&#8838;",\r
486                         "&supe;" => "&#8839;",\r
487                         "&oplus;" => "&#8853;",\r
488                         "&otimes;" => "&#8855;",\r
489                         "&perp;" => "&#8869;",\r
490                         "&sdot;" => "&#8901;",\r
491                         "&lceil;" => "&#8968;",\r
492                         "&rceil;" => "&#8969;",\r
493                         "&lfloor;" => "&#8970;",\r
494                         "&rfloor;" => "&#8971;",\r
495                         "&lang;" => "&#9001;",\r
496                         "&rang;" => "&#9002;",\r
497                         "&loz;" => "&#9674;",\r
498                         "&spades;" => "&#9824;",\r
499                         "&clubs;" => "&#9827;",\r
500                         "&hearts;" => "&#9829;",\r
501                         "&diams;" => "&#9830;");\r
502                 return strtr($data, $entities);\r
503         }\r
504 \r
505         function xmlrpc_encode_entitites($data) \r
506         {\r
507                 $length = strlen($data);\r
508                 $escapeddata = "";\r
509                 for($position = 0; $position < $length; $position++)\r
510                 {\r
511                         $character = substr($data, $position, 1);\r
512                         $code = Ord($character);\r
513                         switch($code) {\r
514                                 case 34:\r
515                                 $character = "&quot;";\r
516                                 break;\r
517                                 case 38:\r
518                                 $character = "&amp;";\r
519                                 break;\r
520                                 case 39:\r
521                                 $character = "&apos;";\r
522                                 break;\r
523                                 case 60:\r
524                                 $character = "&lt;";\r
525                                 break;\r
526                                 case 62:\r
527                                 $character = "&gt;";\r
528                                 break;\r
529                                 default:\r
530                                 if ($code < 32 || $code > 159)\r
531                                         $character = ("&#".strval($code).";");\r
532                                 break;\r
533                         }\r
534                         $escapeddata .= $character;\r
535                 }\r
536                 return $escapeddata;\r
537         }\r
538 \r
539         function xmlrpc_se($parser, $name, $attrs)\r
540         {\r
541                 global $_xh, $xmlrpcDateTime, $xmlrpcString, $xmlrpc_valid_parents;\r
542 \r
543                 // if invalid xmlrpc already detected, skip all processing\r
544                 if ($_xh[$parser]['isf'] < 2)\r
545                 {\r
546 \r
547                 // check for correct element nesting\r
548                 // top level element can only be of 2 types\r
549                 if (count($_xh[$parser]['stack']) == 0)\r
550                 {\r
551                         if ($name != 'METHODRESPONSE' && $name != 'METHODCALL')\r
552                         {\r
553                                 $_xh[$parser]['isf'] = 2;\r
554                                 $_xh[$parser]['isf_reason'] = 'missing top level xmlrpc element';\r
555                                 return;\r
556                         }\r
557                 }\r
558                 else\r
559                 {\r
560                         // not top level element: see if parent is OK\r
561                         if (!in_array($_xh[$parser]['stack'][0], $xmlrpc_valid_parents[$name]))\r
562                         {\r
563                                 $_xh[$parser]['isf'] = 2;\r
564                                 $_xh[$parser]['isf_reason'] = "xmlrpc element $name cannot be child of {$_xh[$parser]['stack'][0]}";\r
565                                 return;\r
566                         }\r
567                 }\r
568 \r
569                 switch($name)\r
570                 {\r
571                         case 'STRUCT':\r
572                         case 'ARRAY':\r
573                                 //$_xh[$parser]['st'].='array(';\r
574                                 //$_xh[$parser]['cm']++;\r
575                                 // this last line turns quoting off\r
576                                 // this means if we get an empty array we'll\r
577                                 // simply get a bit of whitespace in the eval\r
578                                 //$_xh[$parser]['qt']=0;\r
579 \r
580                                 // create an empty array to hold child values, and push it onto appropriate stack\r
581                                 $cur_val = array();\r
582                                 $cur_val['values'] = array();\r
583                                 $cur_val['type'] = $name;\r
584                                 array_unshift($_xh[$parser]['valuestack'], $cur_val);\r
585                                 break;\r
586                         case 'METHODNAME':\r
587                         case 'NAME':\r
588                                 //$_xh[$parser]['st'].='"';\r
589                                 $_xh[$parser]['ac']='';\r
590                                 break;\r
591                         case 'FAULT':\r
592                                 $_xh[$parser]['isf']=1;\r
593                                 break;\r
594                         case 'PARAM':\r
595                                 //$_xh[$parser]['st']='';\r
596                                 // clear value, so we can check later if no value will passed for this param/member\r
597                                 $_xh[$parser]['value']=null;\r
598                                 break;\r
599                         case 'VALUE':\r
600                                 //$_xh[$parser]['st'].='new xmlrpcval(';\r
601                                 // look for a value: if this is still true by the\r
602                                 // time we reach the end tag for value then the type is string\r
603                                 // by implication\r
604                                 $_xh[$parser]['vt']='value';\r
605                                 $_xh[$parser]['ac']='';\r
606                                 //$_xh[$parser]['qt']=0;\r
607                                 $_xh[$parser]['lv']=1;\r
608                                 break;\r
609                         case 'I4':\r
610                         case 'INT':\r
611                         case 'STRING':\r
612                         case 'BOOLEAN':\r
613                         case 'DOUBLE':\r
614                         case 'DATETIME.ISO8601':\r
615                         case 'BASE64':\r
616                                 if ($_xh[$parser]['vt']!='value')\r
617                                 {\r
618                                         //two data elements inside a value: an error occurred!\r
619                                         $_xh[$parser]['isf'] = 2;\r
620                                         $_xh[$parser]['isf_reason'] = "$name element following a {$_xh[$parser]['vt']} element inside a single value";\r
621                                         return;\r
622                                 }\r
623 \r
624                                 // reset the accumulator\r
625                                 $_xh[$parser]['ac']='';\r
626 \r
627                                 /*if ($name=='DATETIME.ISO8601' || $name=='STRING')\r
628                                 {\r
629                                         $_xh[$parser]['qt']=1;\r
630                                         if ($name=='DATETIME.ISO8601')\r
631                                         {\r
632                                                 $_xh[$parser]['vt']=$xmlrpcDateTime;\r
633                                         }\r
634                                 }\r
635                                 elseif ($name=='BASE64')\r
636                                 {\r
637                                         $_xh[$parser]['qt']=2;\r
638                                 }\r
639                                 else\r
640                                 {\r
641                                         // No quoting is required here -- but\r
642                                         // at the end of the element we must check\r
643                                         // for data format errors.\r
644                                         $_xh[$parser]['qt']=0;\r
645                                 }*/\r
646                                 break;\r
647                         case 'MEMBER':\r
648                                 //$_xh[$parser]['ac']='';\r
649                                 // avoid warnings later on if no NAME is found before VALUE inside\r
650                                 // a struct member predefining member name as NULL\r
651                                 $_xh[$parser]['valuestack'][0]['name'] = '';\r
652                                 // clear value, so we can check later if no value will passed for this param/member\r
653                                 $_xh[$parser]['value']=null;\r
654                                 break;\r
655                         case 'DATA':\r
656                         case 'METHODCALL':\r
657                         case 'METHODRESPONSE':\r
658                         case 'PARAMS':\r
659                                 // valid elements that add little to processing\r
660                                 break;\r
661                         default:\r
662                                 /// INVALID ELEMENT: RAISE ISF so that it is later recognized!!!\r
663                                 $_xh[$parser]['isf'] = 2;\r
664                                 $_xh[$parser]['isf_reason'] = "found not-xmlrpc xml element $name";\r
665                                 break;\r
666                 }\r
667 \r
668                 // Save current element name to stack, to validate nesting\r
669                 array_unshift($_xh[$parser]['stack'], $name);\r
670 \r
671                 if ($name!='VALUE')\r
672                 {\r
673                         $_xh[$parser]['lv']=0;\r
674                 }\r
675         }\r
676         }\r
677 \r
678         function xmlrpc_ee($parser, $name)\r
679         {\r
680                 global $_xh,$xmlrpcTypes,$xmlrpcString,$xmlrpcDateTime;\r
681 \r
682                 if ($_xh[$parser]['isf'] < 2)\r
683                 {\r
684 \r
685                 // push this element name from stack\r
686                 // NB: if XML validates, correct opening/closing is guaranteed and\r
687                 // we do not have to check for $name == $curr_elem.\r
688                 // we also checked for proper nesting at start of elements...\r
689                 $curr_elem = array_shift($_xh[$parser]['stack']);               \r
690 \r
691                 switch($name)\r
692                 {\r
693                         case 'STRUCT':\r
694                         case 'ARRAY':\r
695                                 //if ($_xh[$parser]['cm'] && substr($_xh[$parser]['st'], -1) ==',')\r
696                                 //{\r
697                                 //      $_xh[$parser]['st']=substr($_xh[$parser]['st'],0,-1);\r
698                                 //}\r
699                                 //$_xh[$parser]['st'].=')';\r
700 \r
701                                 // fetch out of stack array of values, and promote it to current value\r
702                                 $cur_val = array_shift($_xh[$parser]['valuestack']);\r
703                                 $_xh[$parser]['value'] = $cur_val['values'];\r
704 \r
705                                 $_xh[$parser]['vt']=strtolower($name);\r
706                                 //$_xh[$parser]['cm']--;\r
707                                 break;\r
708                         case 'NAME':\r
709                                 //$_xh[$parser]['st'].= $_xh[$parser]['ac'] . '" => ';\r
710                                 $_xh[$parser]['valuestack'][0]['name'] = $_xh[$parser]['ac'];\r
711                                 break;\r
712                         case 'BOOLEAN':\r
713                         case 'I4':\r
714                         case 'INT':\r
715                         case 'STRING':\r
716                         case 'DOUBLE':\r
717                         case 'DATETIME.ISO8601':\r
718                         case 'BASE64':\r
719                                 $_xh[$parser]['vt']=strtolower($name);\r
720                                 //if ($_xh[$parser]['qt']==1)                   \r
721                                 if ($name=='STRING')\r
722                                 {\r
723                                         // we use double quotes rather than single so backslashification works OK\r
724                                         //$_xh[$parser]['st'].='"'. $_xh[$parser]['ac'] . '"';\r
725                                         $_xh[$parser]['value']=$_xh[$parser]['ac'];\r
726                                 }\r
727                                 elseif ($name=='DATETIME.ISO8601')\r
728                                 {\r
729                                         $_xh[$parser]['vt']=$xmlrpcDateTime;\r
730                                         $_xh[$parser]['value']=$_xh[$parser]['ac'];\r
731                                 }\r
732                                 elseif ($name=='BASE64')\r
733                                 {\r
734                                         //$_xh[$parser]['st'].='base64_decode("'. $_xh[$parser]['ac'] . '")';\r
735 \r
736                                         ///@todo check for failure of base64 decoding / catch warnings\r
737                                         $_xh[$parser]['value']=base64_decode($_xh[$parser]['ac']);\r
738                                 }\r
739                                 elseif ($name=='BOOLEAN')\r
740                                 {\r
741                                         // special case here: we translate boolean 1 or 0 into PHP\r
742                                         // constants true or false\r
743                                         // NB: this simple checks helps a lot sanitizing input, ie no\r
744                                         // security problems around here\r
745                                         if ($_xh[$parser]['ac']=='1')\r
746                                         {\r
747                                                 //$_xh[$parser]['ac']='true';   \r
748                                                 $_xh[$parser]['value']=true;\r
749                                         }\r
750                                         else\r
751                                         {\r
752                                                 //$_xh[$parser]['ac']='false';\r
753                                                 // log if receiveing something strange, even though we set the value to false anyway\r
754                                                 if ($_xh[$parser]['ac']!='0')\r
755                                                         error_log('XML-RPC: invalid value received in BOOLEAN: '.$_xh[$parser]['ac']);\r
756                                                 $_xh[$parser]['value']=false;\r
757                                         }\r
758                                         //$_xh[$parser]['st'].=$_xh[$parser]['ac'];\r
759                                 }\r
760                                 elseif ($name=='DOUBLE')\r
761                                 {\r
762                                         // we have a DOUBLE\r
763                                         // we must check that only 0123456789-.<space> are characters here\r
764                                         if (!ereg("^[+-]?[eE0123456789 \\t\\.]+$", $_xh[$parser]['ac']))\r
765                                         {\r
766                                                 // TODO: find a better way of throwing an error\r
767                                                 // than this!\r
768                                                 error_log('XML-RPC: non numeric value received in DOUBLE: '.$_xh[$parser]['ac']);\r
769                                                 //$_xh[$parser]['st'].="'ERROR_NON_NUMERIC_FOUND'";\r
770                                                 $_xh[$parser]['value']='ERROR_NON_NUMERIC_FOUND';\r
771                                         }\r
772                                         else\r
773                                         {\r
774                                                 // it's ok, add it on\r
775                                                 //$_xh[$parser]['st'].=(double)$_xh[$parser]['ac'];\r
776                                                 $_xh[$parser]['value']=(double)$_xh[$parser]['ac'];\r
777                                         }\r
778                                 }\r
779                                 else\r
780                                 {\r
781                                         // we have an I4/INT\r
782                                         // we must check that only 0123456789-<space> are characters here\r
783                                         if (!ereg("^[+-]?[0123456789 \\t]+$", $_xh[$parser]['ac']))\r
784                                         {\r
785                                                 // TODO: find a better way of throwing an error\r
786                                                 // than this!\r
787                                                 error_log('XML-RPC: non numeric value received in INT: '.$_xh[$parser]['ac']);\r
788                                                 //$_xh[$parser]['st'].="'ERROR_NON_NUMERIC_FOUND'";\r
789                                                 $_xh[$parser]['value']='ERROR_NON_NUMERIC_FOUND';\r
790                                         }\r
791                                         else\r
792                                         {\r
793                                                 // it's ok, add it on\r
794                                                 //$_xh[$parser]['st'].=(int)$_xh[$parser]['ac'];\r
795                                                 $_xh[$parser]['value']=(int)$_xh[$parser]['ac'];\r
796                                         }\r
797                                 }\r
798                                 $_xh[$parser]['ac']='';\r
799                                 //$_xh[$parser]['qt']=0;\r
800                                 $_xh[$parser]['lv']=3; // indicate we've found a value\r
801                                 break;\r
802                         case 'VALUE':\r
803                                 // This if() detects if no scalar was inside <VALUE></VALUE>\r
804                                 if ($_xh[$parser]['vt']=='value')\r
805                                 {\r
806                                         $_xh[$parser]['value']=$_xh[$parser]['ac'];\r
807                                         $_xh[$parser]['vt']=$xmlrpcString;\r
808                                 }\r
809                                 /*if (strlen($_xh[$parser]['ac'])>0 &&\r
810                                         $_xh[$parser]['vt']==$xmlrpcString)\r
811                                 {\r
812                                         $_xh[$parser]['st'].='"'. $_xh[$parser]['ac'] . '"';\r
813                                 }\r
814                                 // This if() detects if no scalar was inside <VALUE></VALUE>\r
815                                 // and pads an empty ''.\r
816                                 if($_xh[$parser]['st'][strlen($_xh[$parser]['st'])-1] == '(')\r
817                                 {\r
818                                         $_xh[$parser]['st'].= '""';\r
819                                 }\r
820                                 // G. Giunta 2005/03/12 save some chars in the reconstruction of string vals...\r
821                                 if ($_xh[$parser]['vt'] != $xmlrpcString)\r
822                                         $_xh[$parser]['st'].=", '" . $_xh[$parser]['vt'] . "')";\r
823                                 else\r
824                                         $_xh[$parser]['st'].=")";\r
825                                 if ($_xh[$parser]['cm'])\r
826                                 {\r
827                                         $_xh[$parser]['st'].=',';\r
828                                 }*/\r
829 \r
830                                 // build the xmlrpc val out of the data received, and substitute it\r
831                                 $temp = new xmlrpcval($_xh[$parser]['value'], $_xh[$parser]['vt']);\r
832                                 // check if we are inside an array or struct:\r
833                                 // if value just built is inside an array, let's move it into array on the stack\r
834                                 if (count($_xh[$parser]['valuestack']) && $_xh[$parser]['valuestack'][0]['type']=='ARRAY')\r
835                                 {\r
836                                         $_xh[$parser]['valuestack'][0]['values'][] = $temp;\r
837                                 }\r
838                                 else\r
839                                 {\r
840                                 $_xh[$parser]['value'] = $temp;\r
841                                 }\r
842                                 break;\r
843                         case 'MEMBER':\r
844                                 $_xh[$parser]['ac']='';\r
845                                 //$_xh[$parser]['qt']=0;\r
846                                 // add to array in the stack the last element built\r
847                                 // unless no VALUE was found\r
848                                 if ($_xh[$parser]['value'])\r
849                                         $_xh[$parser]['valuestack'][0]['values'][$_xh[$parser]['valuestack'][0]['name']] = $_xh[$parser]['value'];\r
850                                 else\r
851                                         error_log('XML-RPC: missing VALUE inside STRUCT in received xml');\r
852                                 break;\r
853                         case 'DATA':\r
854                                 $_xh[$parser]['ac']='';\r
855                                 //$_xh[$parser]['qt']=0;\r
856                                 break;\r
857                         case 'PARAM':\r
858                                 //$_xh[$parser]['params'][]=$_xh[$parser]['st'];\r
859                                 if ($_xh[$parser]['value'])\r
860                                         $_xh[$parser]['params'][]=$_xh[$parser]['value'];\r
861                                 else\r
862                                         error_log('XML-RPC: missing VALUE inside PARAM in received xml');\r
863                                 break;\r
864                         case 'METHODNAME':\r
865                                 $_xh[$parser]['method']=ereg_replace("^[\n\r\t ]+", '', $_xh[$parser]['ac']);\r
866                                 break;\r
867                         case 'PARAMS':\r
868                         case 'FAULT':\r
869                         case 'METHODCALL':\r
870                         case 'METHORESPONSE':\r
871                                 break;\r
872                         default:\r
873                                 // End of INVALID ELEMENT!\r
874                                 // shall we add an assert here for unreachable code???\r
875                                 break;\r
876                 }\r
877                 // if it's a valid type name, set the type\r
878                 /*if (isset($xmlrpcTypes[strtolower($name)]))\r
879                 {\r
880                         $_xh[$parser]['vt']=strtolower($name);\r
881                 }*/\r
882 \r
883                 }\r
884         }\r
885 \r
886         function xmlrpc_cd($parser, $data)\r
887         {\r
888                 global $_xh, $xmlrpc_backslash;\r
889 \r
890                 //if (ereg("^[\n\r \t]+$", $data)) return;\r
891                 // print "adding [${data}]\n";\r
892 \r
893                 // skip processing if xml fault already detected\r
894                 if ($_xh[$parser]['isf'] < 2)\r
895                 {\r
896                 if ($_xh[$parser]['lv']!=3)\r
897                 {\r
898                         // "lookforvalue==3" means that we've found an entire value\r
899                         // and should discard any further character data\r
900                         if ($_xh[$parser]['lv']==1)\r
901                         {\r
902                                 // if we've found text and we're just in a <value> then\r
903                                 // turn quoting on, as this will be a string\r
904                                         //$_xh[$parser]['qt']=1;\r
905                                 // and say we've found a value\r
906                                 $_xh[$parser]['lv']=2;\r
907                         }\r
908                         if(!@isset($_xh[$parser]['ac']))\r
909                         {\r
910                                 $_xh[$parser]['ac'] = '';\r
911                         }\r
912                                 //$_xh[$parser]['ac'].=str_replace('$', '\$', str_replace('"', '\"', str_replace(chr(92),$xmlrpc_backslash, $data)));\r
913                                 $_xh[$parser]['ac'].=$data;\r
914                         }\r
915                 }\r
916         }\r
917 \r
918         function xmlrpc_dh($parser, $data)\r
919         {\r
920                 global $_xh, $xmlrpc_backslash;\r
921 \r
922                 // skip processing if xml fault already detected\r
923                 if ($parser[$_xh]['isf'] < 2)\r
924                 {\r
925                 if (substr($data, 0, 1) == '&' && substr($data, -1, 1) == ';')\r
926                 {\r
927                         if ($_xh[$parser]['lv']==1)\r
928                         {\r
929                                         //$_xh[$parser]['qt']=1;\r
930                                 $_xh[$parser]['lv']=2;\r
931                         }\r
932                                 //$_xh[$parser]['ac'].=str_replace('$', '\$', str_replace('"', '\"', str_replace(chr(92),$xmlrpc_backslash, $data)));\r
933                                 $_xh[$parser]['ac'].=$data;\r
934                         }\r
935                 }\r
936         }\r
937 \r
938         class xmlrpc_client\r
939         {\r
940                 var $path;\r
941                 var $server;\r
942                 var $port;\r
943                 var $errno;\r
944                 var $errstr;\r
945                 var $debug=0;\r
946                 var $username='';\r
947                 var $password='';\r
948                 var $cert='';\r
949                 var $certpass='';\r
950                 var $verifypeer=1;\r
951                 var $verifyhost=1;\r
952                 var $no_multicall=false;\r
953 \r
954                 function xmlrpc_client($path, $server, $port=0)\r
955                 {\r
956                         $this->port=$port; $this->server=$server; $this->path=$path;\r
957                 }\r
958 \r
959                 function setDebug($in)\r
960                 {\r
961                         if ($in)\r
962                         {\r
963                                 $this->debug=1;\r
964                         }\r
965                         else\r
966                         {\r
967                                 $this->debug=0;\r
968                         }\r
969                 }\r
970 \r
971                 function setCredentials($u, $p)\r
972                 {\r
973                         $this->username=$u;\r
974                         $this->password=$p;\r
975                 }\r
976 \r
977                 function setCertificate($cert, $certpass)\r
978                 {\r
979                         $this->cert = $cert;\r
980                         $this->certpass = $certpass;\r
981                 }\r
982 \r
983                 function setSSLVerifyPeer($i)\r
984                 {\r
985                         $this->verifypeer = $i;\r
986                 }\r
987 \r
988                 function setSSLVerifyHost($i)\r
989                 {\r
990                         $this->verifyhost = $i;\r
991                 }\r
992 \r
993                 function send($msg, $timeout=0, $method='http')\r
994                 {\r
995                         if (is_array($msg))\r
996                         {\r
997                                 // $msg is an array of xmlrpcmsg's\r
998                                 return $this->multicall($msg, $timeout, $method);\r
999                         }\r
1000 \r
1001                         // where msg is an xmlrpcmsg\r
1002                         $msg->debug=$this->debug;\r
1003 \r
1004                         if ($method == 'https')\r
1005                         {\r
1006                                 return $this->sendPayloadHTTPS($msg,\r
1007                                 $this->server,\r
1008                                 $this->port, $timeout,\r
1009                                 $this->username, $this->password,\r
1010                                 $this->cert,\r
1011                                 $this->certpass);\r
1012                         }\r
1013                         else\r
1014                         {\r
1015                                 return $this->sendPayloadHTTP10($msg, $this->server, $this->port,\r
1016                                 $timeout, $this->username, \r
1017                                 $this->password);\r
1018                         }\r
1019                 }\r
1020 \r
1021                 function sendPayloadHTTP10($msg, $server, $port, $timeout=0,$username='', $password='')\r
1022                 {\r
1023                         global $xmlrpcerr, $xmlrpcstr, $xmlrpcName, $xmlrpcVersion, $xmlrpc_defencoding;\r
1024                         if ($port==0)\r
1025                         {\r
1026                                 $port=80;\r
1027                         }\r
1028                         if($timeout>0)\r
1029                         {\r
1030                                 $fp=@fsockopen($server, $port,$this->errno, $this->errstr, $timeout);\r
1031                         }\r
1032                         else\r
1033                         {\r
1034                                 $fp=@fsockopen($server, $port,$this->errno, $this->errstr);\r
1035                         }\r
1036                         if ($fp)\r
1037                         {\r
1038                                 if ($timeout>0 && function_exists('stream_set_timeout'))\r
1039                                         stream_set_timeout($fp, $timeout);\r
1040                         }\r
1041                         else\r
1042                         {\r
1043                                 $this->errstr='Connect error';\r
1044                                 $r=new xmlrpcresp(0, $xmlrpcerr['http_error'],$xmlrpcstr['http_error']);\r
1045                                 return $r;\r
1046                         }\r
1047                         // Only create the payload if it was not created previously\r
1048                         if(empty($msg->payload))\r
1049                         {\r
1050                                 $msg->createPayload();\r
1051                         }\r
1052 \r
1053                         // thanks to Grant Rauscher <grant7@firstworld.net>\r
1054                         // for this\r
1055                         $credentials='';\r
1056                         if ($username!='')\r
1057                         {\r
1058                                 $credentials='Authorization: Basic ' . base64_encode($username . ':' . $password) . "\r\n";\r
1059                         }\r
1060 \r
1061                         $op= "POST " . $this->path. " HTTP/1.0\r\n" .\r
1062                                 "User-Agent: " . $xmlrpcName . " " . $xmlrpcVersion . "\r\n" .\r
1063                                 "Host: ". $server . "\r\n" .\r
1064                                 $credentials . \r
1065                                 "Accept-Charset: " . $xmlrpc_defencoding . "\r\n" .\r
1066                                 "Content-Type: text/xml\r\nContent-Length: " .\r
1067                                 strlen($msg->payload) . "\r\n\r\n" .\r
1068                                 $msg->payload;\r
1069 \r
1070                         if (!fputs($fp, $op, strlen($op)))\r
1071                         {\r
1072                                 $this->errstr='Write error';\r
1073                                 $r=new xmlrpcresp(0, $xmlrpcerr['http_error'], $xmlrpcstr['http_error']);\r
1074                                 return $r;\r
1075                         }\r
1076                         $resp=$msg->parseResponseFile($fp);\r
1077                         fclose($fp);\r
1078                         return $resp;\r
1079                 }\r
1080 \r
1081                 // contributed by Justin Miller <justin@voxel.net>\r
1082                 // requires curl to be built into PHP\r
1083                 function sendPayloadHTTPS($msg, $server, $port, $timeout=0,$username='', $password='', $cert='',$certpass='')\r
1084                 {\r
1085                         global $xmlrpcerr, $xmlrpcstr, $xmlrpcVersion, $xmlrpc_internalencoding;\r
1086                         if ($port == 0)\r
1087                         {\r
1088                                 $port = 443;\r
1089                         }\r
1090 \r
1091                         // Only create the payload if it was not created previously\r
1092                         if(empty($msg->payload))\r
1093                         {\r
1094                                 $msg->createPayload();\r
1095                         }\r
1096 \r
1097                         if (!function_exists('curl_init'))\r
1098                         {\r
1099                                 $this->errstr='SSL unavailable on this install';\r
1100                                 $r=new xmlrpcresp(0, $xmlrpcerr['no_ssl'], $xmlrpcstr['no_ssl']);\r
1101                                 return $r;\r
1102                         }\r
1103 \r
1104                         $curl = curl_init('https://' . $server . ':' . $port . $this->path);\r
1105 \r
1106                         curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);\r
1107                         // results into variable\r
1108                         if ($this->debug)\r
1109                         {\r
1110                                 curl_setopt($curl, CURLOPT_VERBOSE, 1);\r
1111                         }\r
1112                         curl_setopt($curl, CURLOPT_USERAGENT, 'PHP XMLRPC '.$xmlrpcVersion);\r
1113                         // required for XMLRPC\r
1114                         curl_setopt($curl, CURLOPT_POST, 1);\r
1115                         // post the data\r
1116                         curl_setopt($curl, CURLOPT_POSTFIELDS, $msg->payload);\r
1117                         // the data\r
1118                         curl_setopt($curl, CURLOPT_HEADER, 1);\r
1119                         // return the header too\r
1120                         curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Type: text/xml', 'Accept-Charset: '.$xmlrpc_internalencoding));\r
1121                         // whether to verify remote host's cert\r
1122                         curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, $this->verifypeer);\r
1123                         // whether to verify cert's common name (CN); 0 for no, 1 to verify that it exists, and 2 to verify that it matches the hostname used\r
1124                         curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, $this->verifyhost);\r
1125                         // required for XMLRPC\r
1126                         if ($timeout)\r
1127                         {\r
1128                                 curl_setopt($curl, CURLOPT_TIMEOUT, $timeout == 1 ? 1 : $timeout - 1);\r
1129                         }\r
1130                         // timeout is borked\r
1131                         if ($username && $password)\r
1132                         {\r
1133                                 curl_setopt($curl, CURLOPT_USERPWD,"$username:$password");\r
1134                         }\r
1135                         // set auth stuff\r
1136                         if ($cert)\r
1137                         {\r
1138                                 curl_setopt($curl, CURLOPT_SSLCERT, $cert);\r
1139                         }\r
1140                         // set cert file\r
1141                         if ($certpass)\r
1142                         {\r
1143                                 curl_setopt($curl, CURLOPT_SSLCERTPASSWD,$certpass);\r
1144                         }\r
1145                         // set cert password\r
1146 \r
1147                         $result = curl_exec($curl);\r
1148 \r
1149                         if (!$result)\r
1150                         {\r
1151                                 $this->errstr='no response';\r
1152                                 $resp=new xmlrpcresp(0, $xmlrpcerr['curl_fail'], $xmlrpcstr['curl_fail']. ': '. curl_error($curl));\r
1153                                 curl_close($curl);\r
1154                         }\r
1155                         else\r
1156                         {\r
1157                                 curl_close($curl);\r
1158                                 $resp = $msg->parseResponse($result);\r
1159                         }\r
1160                         return $resp;\r
1161                 }\r
1162 \r
1163                 function multicall($msgs, $timeout=0, $method='http')\r
1164                 {\r
1165                         $results = false;\r
1166 \r
1167                         if (! $this->no_multicall)\r
1168                         {\r
1169                                 $results = $this->_try_multicall($msgs, $timeout, $method);\r
1170                                 /* TODO - this is not php3-friendly */\r
1171                                 // if($results !== false)\r
1172                                 if(is_array($results))\r
1173                                 {\r
1174                                         // Either the system.multicall succeeded, or the send\r
1175                                         // failed (e.g. due to HTTP timeout). In either case,\r
1176                                         // we're done for now.\r
1177                                         return $results;\r
1178                                 }\r
1179                                 else\r
1180                                 {\r
1181                                         // system.multicall unsupported by server,\r
1182                                         // don't try it next time...\r
1183                                         $this->no_multicall = true;\r
1184                                 }\r
1185                         }\r
1186 \r
1187                         // system.multicall is unupported by server:\r
1188                         //   Emulate multicall via multiple requests\r
1189                         $results = array();\r
1190                         //foreach($msgs as $msg)\r
1191                         @reset($msgs);\r
1192                         while(list(,$msg) = @each($msgs))\r
1193                         {\r
1194                                 $results[] = $this->send($msg, $timeout, $method);\r
1195                         }\r
1196                         return $results;\r
1197                 }\r
1198 \r
1199                 // Attempt to boxcar $msgs via system.multicall.\r
1200                 function _try_multicall($msgs, $timeout, $method)\r
1201                 {\r
1202                         // Construct multicall message\r
1203                         $calls = array();\r
1204                         //foreach($msgs as $msg)\r
1205                         @reset($msgs);\r
1206                         while(list(,$msg) = @each($msgs))\r
1207                         {\r
1208                                 $call['methodName'] = new xmlrpcval($msg->method(),'string');\r
1209                                 $numParams = $msg->getNumParams();\r
1210                                 $params = array();\r
1211                                 for ($i = 0; $i < $numParams; $i++)\r
1212                                 {\r
1213                                         $params[$i] = $msg->getParam($i);\r
1214                                 }\r
1215                                 $call['params'] = new xmlrpcval($params, 'array');\r
1216                                 $calls[] = new xmlrpcval($call, 'struct');\r
1217                         }\r
1218                         $multicall = new xmlrpcmsg('system.multicall');\r
1219                         $multicall->addParam(new xmlrpcval($calls, 'array'));\r
1220 \r
1221                         // Attempt RPC call\r
1222                         $result = $this->send($multicall, $timeout, $method);\r
1223                         if(!is_object($result))\r
1224                         {\r
1225                                 return ($result || 0); // transport failed\r
1226                         }\r
1227 \r
1228                         if($result->faultCode() != 0)\r
1229                         {\r
1230                                 return false;           // system.multicall failed\r
1231                         }\r
1232 \r
1233                         // Unpack responses.\r
1234                         $rets = $result->value();\r
1235                         if($rets->kindOf() != 'array')\r
1236                         {\r
1237                                 return false;           // bad return type from system.multicall\r
1238                         }\r
1239                         $numRets = $rets->arraysize();\r
1240                         if($numRets != count($msgs))\r
1241                         {\r
1242                                 return false;           // wrong number of return values.\r
1243                         }\r
1244 \r
1245                         $response = array();\r
1246                         for ($i = 0; $i < $numRets; $i++)\r
1247                         {\r
1248                                 $val = $rets->arraymem($i);\r
1249                                 switch ($val->kindOf())\r
1250                                 {\r
1251                                 case 'array':\r
1252                                         if($val->arraysize() != 1)\r
1253                                         {\r
1254                                                 return false;           // Bad value\r
1255                                         }\r
1256                                         // Normal return value\r
1257                                         $response[$i] = new xmlrpcresp($val->arraymem(0));\r
1258                                         break;\r
1259                                 case 'struct':\r
1260                                         $code = $val->structmem('faultCode');\r
1261                                         if($code->kindOf() != 'scalar' || $code->scalartyp() != 'int')\r
1262                                         {\r
1263                                                 return false;\r
1264                                         }\r
1265                                         $str = $val->structmem('faultString');\r
1266                                         if($str->kindOf() != 'scalar' || $str->scalartyp() != 'string')\r
1267                                         {\r
1268                                                 return false;\r
1269                                         }\r
1270                                         $response[$i] = new xmlrpcresp(0, $code->scalarval(), $str->scalarval());\r
1271                                         break;\r
1272                                 default:\r
1273                                         return false;\r
1274                                 }\r
1275                         }\r
1276                         return $response;\r
1277                 }\r
1278         } // end class xmlrpc_client\r
1279 \r
1280         class xmlrpcresp\r
1281         {\r
1282                 var $val = 0;\r
1283                 var $errno = 0;\r
1284                 var $errstr = '';\r
1285                 var $hdrs = array();\r
1286 \r
1287                 function xmlrpcresp($val, $fcode = 0, $fstr = '')\r
1288                 {\r
1289                         if ($fcode != 0)\r
1290                         {\r
1291                                 // error\r
1292                                 $this->errno = $fcode;\r
1293                                 $this->errstr = $fstr;\r
1294                                 //$this->errstr = htmlspecialchars($fstr); // XXX: encoding probably shouldn't be done here; fix later.\r
1295                         }\r
1296                         elseif (!is_object($val))\r
1297                         {\r
1298                                 // programmer error\r
1299                                 error_log("Invalid type '" . gettype($val) . "' (value: $val) passed to xmlrpcresp. Defaulting to empty value.");\r
1300                                 $this->val = new xmlrpcval();\r
1301                         }\r
1302                         else\r
1303                         {\r
1304                                 // success\r
1305                                 $this->val = $val;\r
1306                         }\r
1307                 }\r
1308 \r
1309                 function faultCode()\r
1310                 {\r
1311                         return $this->errno;\r
1312                 }\r
1313 \r
1314                 function faultString()\r
1315                 {\r
1316                         return $this->errstr;\r
1317                 }\r
1318 \r
1319                 function value()\r
1320                 {\r
1321                         return $this->val;\r
1322                 }\r
1323 \r
1324                 function serialize()\r
1325                 {\r
1326                         $result = "<methodResponse>\n";\r
1327                         if ($this->errno)\r
1328                         {\r
1329                                 // G. Giunta 2005/2/13: let non-ASCII response messages be tolerated by clients\r
1330                                 $result .= '<fault>\r
1331 <value>\r
1332 <struct>\r
1333 <member>\r
1334 <name>faultCode</name>\r
1335 <value><int>' . $this->errno . '</int></value>\r
1336 </member>\r
1337 <member>\r
1338 <name>faultString</name>\r
1339 <value><string>' . xmlrpc_encode_entitites($this->errstr) . '</string></value>\r
1340 </member>\r
1341 </struct>\r
1342 </value>\r
1343 </fault>';\r
1344                         }\r
1345                         else\r
1346                         {\r
1347                                 $result .= "<params>\n<param>\n" .\r
1348                                         $this->val->serialize() . \r
1349                                         "</param>\n</params>";\r
1350                         }\r
1351                         $result .= "\n</methodResponse>";\r
1352                         return $result;\r
1353                 }\r
1354         }\r
1355 \r
1356         class xmlrpcmsg\r
1357         {\r
1358                 var $payload;\r
1359                 var $methodname;\r
1360                 var $params=array();\r
1361                 var $debug=0;\r
1362 \r
1363                 function xmlrpcmsg($meth, $pars=0)\r
1364                 {\r
1365                         $this->methodname=$meth;\r
1366                         if (is_array($pars) && sizeof($pars)>0)\r
1367                         {\r
1368                                 for($i=0; $i<sizeof($pars); $i++)\r
1369                                 {\r
1370                                         $this->addParam($pars[$i]);\r
1371                                 }\r
1372                         }\r
1373                 }\r
1374 \r
1375                 function xml_header()\r
1376                 {\r
1377                         return "<?xml version=\"1.0\"?" . ">\n<methodCall>\n";\r
1378                 }\r
1379 \r
1380                 function xml_footer()\r
1381                 {\r
1382                         return "</methodCall>\n";\r
1383                 }\r
1384 \r
1385                 function createPayload()\r
1386                 {\r
1387                         $this->payload=$this->xml_header();\r
1388                         $this->payload.='<methodName>' . $this->methodname . "</methodName>\n";\r
1389                         //      if (sizeof($this->params)) {\r
1390                         $this->payload.="<params>\n";\r
1391                         for($i=0; $i<sizeof($this->params); $i++)\r
1392                         {\r
1393                                 $p=$this->params[$i];\r
1394                                 $this->payload.="<param>\n" . $p->serialize() .\r
1395                                 "</param>\n";\r
1396                         }\r
1397                         $this->payload.="</params>\n";\r
1398                         // }\r
1399                         $this->payload.=$this->xml_footer();\r
1400                         //$this->payload=str_replace("\n", "\r\n", $this->payload);\r
1401                 }\r
1402 \r
1403                 function method($meth='')\r
1404                 {\r
1405                         if ($meth!='')\r
1406                         {\r
1407                                 $this->methodname=$meth;\r
1408                         }\r
1409                         return $this->methodname;\r
1410                 }\r
1411 \r
1412                 function serialize()\r
1413                 {\r
1414                         $this->createPayload();\r
1415                         return $this->payload;\r
1416                 }\r
1417 \r
1418                 function addParam($par) { $this->params[]=$par; }\r
1419                 function getParam($i) { return $this->params[$i]; }\r
1420                 function getNumParams() { return sizeof($this->params); }\r
1421 \r
1422                 function parseResponseFile($fp)\r
1423                 {\r
1424                         $ipd='';\r
1425                         while($data=fread($fp, 32768))\r
1426                         {\r
1427                                 $ipd.=$data;\r
1428                         }\r
1429                         return $this->parseResponse($ipd);\r
1430                 }\r
1431 \r
1432                 function parseResponse($data='')\r
1433                 {\r
1434                         global $_xh,$xmlrpcerr,$xmlrpcstr;\r
1435                         global $xmlrpc_defencoding, $xmlrpc_internalencoding;\r
1436 \r
1437                         $hdrfnd = 0;\r
1438                         if($this->debug)\r
1439                         {\r
1440                                 //by maHo, replaced htmlspecialchars with htmlentities\r
1441                                 print "<PRE>---GOT---\n" . htmlentities($data) . "\n---END---\n</PRE>";\r
1442                         }\r
1443 \r
1444                         if($data == '')\r
1445                         {\r
1446                                 error_log('No response received from server.');\r
1447                                 $r = new xmlrpcresp(0, $xmlrpcerr['no_data'], $xmlrpcstr['no_data']);\r
1448                                 return $r;\r
1449                         }\r
1450                         // see if we got an HTTP 200 OK, else bomb\r
1451                         // but only do this if we're using the HTTP protocol.\r
1452                         if(ereg("^HTTP",$data))\r
1453                         {\r
1454                                 // Strip HTTP 1.1 100 Continue header if present\r
1455                                 while (ereg('^HTTP/1.1 1[0-9]{2}', $data))\r
1456                                 {\r
1457                                         $pos = strpos($data, 'HTTP', 12);\r
1458                                         // server sent a Continue header without any (valid) content following...\r
1459                                         // give the client a chance to know it\r
1460                                         if (!$pos && !is_int($pos)) // works fine in php 3, 4 and 5\r
1461                                                 break;\r
1462                                         $data = substr($data, $pos);\r
1463                                 }\r
1464                                 if (!ereg("^HTTP/[0-9\\.]+ 200 ", $data))\r
1465                                 {\r
1466                                         $errstr= substr($data, 0, strpos($data, "\n")-1);\r
1467                                         error_log('HTTP error, got response: ' .$errstr);\r
1468                                         $r=new xmlrpcresp(0, $xmlrpcerr['http_error'], $xmlrpcstr['http_error']. ' (' . $errstr . ')');\r
1469                                         return $r;\r
1470                                 }\r
1471                         }\r
1472                         $parser = xml_parser_create($xmlrpc_defencoding);\r
1473 \r
1474                         // G. Giunta 2004/04/06\r
1475                         // Clean up the accumulator, or it will grow indefinitely long\r
1476                         // if making xmlrpc calls for a while\r
1477                         $_xh=array();\r
1478                         $_xh[$parser]=array();\r
1479                         $_xh[$parser]['headers'] = array();\r
1480                         $_xh[$parser]['stack'] = array();\r
1481                         $_xh[$parser]['valuestack'] = array();\r
1482 \r
1483                         // separate HTTP headers from data\r
1484                         if (ereg("^HTTP", $data))\r
1485                         {\r
1486                                 // be tolerant to usage of \n instead of \r\n to separate headers and data\r
1487                                 // (even though it is not valid http)\r
1488                                 $pos = strpos($data,"\r\n\r\n");\r
1489                                 if($pos || is_int($pos))\r
1490                                         $bd = $pos+4;\r
1491                                 else\r
1492                                 {\r
1493                                         $pos = strpos($data,"\n\n");\r
1494                                         if($pos || is_int($pos))\r
1495                                                 $bd = $pos+2;\r
1496                                         else\r
1497                                         {\r
1498                                                 // No separation between response headers and body: fault?\r
1499                                                 $bd = 0;\r
1500                                         }\r
1501                                 }\r
1502                                 // be tolerant to line endings, and extra empty lines\r
1503                                 $ar = split("\r?\n", trim(substr($data, 0, $pos)));\r
1504                                 while (list(,$line) = @each($ar))\r
1505                                 {\r
1506                                         // take care of multi-line headers\r
1507                                         $arr = explode(':',$line);\r
1508                                         if(count($arr) > 1)\r
1509                                         {\r
1510                                                 $header_name = trim($arr[0]);\r
1511                                                 // TO DO: some headers (the ones that allow a CSV list of values)\r
1512                                                 // do allow many values to be passed using multiple header lines.\r
1513                                                 // We should add content to $_xh[$parser]['headers'][$header_name]\r
1514                                                 // instead of replacing it for those...\r
1515                                                 $_xh[$parser]['headers'][$header_name] = $arr[1];\r
1516                                                 for ($i = 2; $i < count($arr); $i++)\r
1517                                                 {\r
1518                                                         $_xh[$parser]['headers'][$header_name] .= ':'.$arr[$i];\r
1519                                                 } // while\r
1520                                                 $_xh[$parser]['headers'][$header_name] = trim($_xh[$parser]['headers'][$header_name]);\r
1521                                         } else if (isset($header_name))\r
1522                                         {\r
1523                                                 $_xh[$parser]['headers'][$header_name] .= ' ' . trim($line);\r
1524                                         }\r
1525                                 }\r
1526                                 $data = substr($data, $bd);\r
1527 \r
1528                                 if ($this->debug && count($_xh[$parser]['headers']))\r
1529                                 {\r
1530                                         print '<PRE>';\r
1531                                         //foreach ($_xh[$parser]['headers'] as $header)\r
1532                                         @reset($_xh[$parser]['headers']);\r
1533                                         while(list($header, $value) = @each($_xh[$parser]['headers']))\r
1534                                         {\r
1535                                                 print "HEADER: $header: $value\n";\r
1536                                         }\r
1537                                         print "</PRE>\n";\r
1538                                 }\r
1539                         }\r
1540 \r
1541                         // be tolerant of extra whitespace in response body\r
1542                         $data = trim($data);\r
1543 \r
1544                         // be tolerant of junk after methodResponse (e.g. javascript automatically inserted by free hosts)\r
1545                         // idea from Luca Mariano <luca.mariano@email.it> originally in PEARified version of the lib\r
1546                         $bd = false;\r
1547                         $pos = strpos($data, "</methodResponse>");\r
1548                         while ($pos || is_int($pos))\r
1549                         {\r
1550                                 $bd = $pos+17;\r
1551                                 $pos = strpos($data, "</methodResponse>", $bd);\r
1552                         }\r
1553                         if ($bd)\r
1554                                 $data = substr($data, 0, $bd);\r
1555 \r
1556                         //$_xh[$parser]['st']='';\r
1557                         //$_xh[$parser]['cm']=0;\r
1558                         $_xh[$parser]['isf']=0;\r
1559                         $_xh[$parser]['isf_reason']=0;\r
1560                         $_xh[$parser]['ac']='';\r
1561                         //$_xh[$parser]['qt']='';\r
1562 \r
1563                         xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true);\r
1564                         // G. Giunta 2005/02/13: PHP internally uses ISO-8859-1, so we have to tell\r
1565                         // the xml parser to give us back data in the expected charset\r
1566                         xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $xmlrpc_internalencoding);\r
1567 \r
1568                         xml_set_element_handler($parser, 'xmlrpc_se', 'xmlrpc_ee');\r
1569                         xml_set_character_data_handler($parser, 'xmlrpc_cd');\r
1570                         xml_set_default_handler($parser, 'xmlrpc_dh');\r
1571                         //$xmlrpc_value=new xmlrpcval;\r
1572 \r
1573                         if (!xml_parse($parser, $data, sizeof($data)))\r
1574                         {\r
1575                                 // thanks to Peter Kocks <peter.kocks@baygate.com>\r
1576                                 if((xml_get_current_line_number($parser)) == 1)\r
1577                                 {\r
1578                                         $errstr = 'XML error at line 1, check URL';\r
1579                                 }\r
1580                                 else\r
1581                                 {\r
1582                                         $errstr = sprintf('XML error: %s at line %d',\r
1583                                                 xml_error_string(xml_get_error_code($parser)),\r
1584                                                 xml_get_current_line_number($parser));\r
1585                                 }\r
1586                                 error_log($errstr);\r
1587                                 $r=new xmlrpcresp(0, $xmlrpcerr['invalid_return'], $xmlrpcstr['invalid_return'].' ('.$errstr.')');\r
1588                                 xml_parser_free($parser);\r
1589                                 if ($this->debug)\r
1590                                         echo $errstr;\r
1591                                 $r->hdrs = $_xh[$parser]['headers'];\r
1592                                 return $r;\r
1593                         }\r
1594                         xml_parser_free($parser);\r
1595 \r
1596                         if ($_xh[$parser]['isf'] > 1)\r
1597                         {\r
1598                         if ($this->debug)\r
1599                         {\r
1600                                         ///@todo echo something for user?\r
1601                                 }\r
1602 \r
1603                                 $r = new xmlrpcresp(0, $xmlrpcerr['invalid_return'],\r
1604                                 $xmlrpcstr['invalid_return'] . ' ' . $_xh[$parser]['isf_reason']);\r
1605                         }\r
1606                         //else if (strlen($_xh[$parser]['st'])==0)\r
1607                         else if (!is_object($_xh[$parser]['value']))\r
1608                         {\r
1609                                 // then something odd has happened\r
1610                                 // and it's time to generate a client side error\r
1611                                 // indicating something odd went on\r
1612                                 $r=new xmlrpcresp(0, $xmlrpcerr['invalid_return'],\r
1613                                 $xmlrpcstr['invalid_return']);\r
1614                         }\r
1615                         else\r
1616                         {\r
1617 \r
1618                                 if ($this->debug)\r
1619                                 {\r
1620                                         //print "<PRE>---EVALING---[" .\r
1621                                         //strlen($_xh[$parser]['st']) . " chars]---\n" .\r
1622                                         //htmlspecialchars($_xh[$parser]['st']) . ";\n---END---</PRE>";\r
1623                                         print "<PRE>---PARSED---\n" ;\r
1624                                         var_dump($_xh[$parser]['value']);\r
1625                                         print "\n---END---</PRE>";\r
1626                                 }\r
1627 \r
1628                                 //$allOK=0;\r
1629                                 //@eval('$v=' . $_xh[$parser]['st'] . '; $allOK=1;');\r
1630                                 //if (!$allOK)\r
1631                                 //{\r
1632                                 //      $r = new xmlrpcresp(0, $xmlrpcerr['invalid_return'], $xmlrpcstr['invalid_return']);\r
1633                                 //}\r
1634                                 //else\r
1635                                 $v = $_xh[$parser]['value'];\r
1636                                 if ($_xh[$parser]['isf'])\r
1637                                 {\r
1638                                         $errno_v = $v->structmem('faultCode');\r
1639                                         $errstr_v = $v->structmem('faultString');\r
1640                                         $errno = $errno_v->scalarval();\r
1641 \r
1642                                         if ($errno == 0)\r
1643                                         {\r
1644                                                 // FAULT returned, errno needs to reflect that\r
1645                                                 $errno = -1;\r
1646                                         }\r
1647 \r
1648                                         $r = new xmlrpcresp($v, $errno, $errstr_v->scalarval());\r
1649                                 }\r
1650                                 else\r
1651                                 {\r
1652                                         $r=new xmlrpcresp($v);\r
1653                                 }\r
1654                         }\r
1655 \r
1656                         $r->hdrs = $_xh[$parser]['headers'];\r
1657                         return $r;\r
1658                 }\r
1659         }\r
1660 \r
1661         class xmlrpcval\r
1662         {\r
1663                 var $me=array();\r
1664                 var $mytype=0;\r
1665 \r
1666                 function xmlrpcval($val=-1, $type='')\r
1667                 {\r
1668                         global $xmlrpcTypes;\r
1669                         $this->me=array();\r
1670                         $this->mytype=0;\r
1671                         if ($val!=-1 || !is_int($val) || $type!='')\r
1672                         {\r
1673                                 if ($type=='')\r
1674                                 {\r
1675                                         $type='string';\r
1676                                 }\r
1677                                 if ($xmlrpcTypes[$type]==1)\r
1678                                 {\r
1679                                         $this->addScalar($val,$type);\r
1680                                 }\r
1681                                 elseif ($xmlrpcTypes[$type]==2)\r
1682                                 {\r
1683                                         $this->addArray($val);\r
1684                                 }\r
1685                                 elseif ($xmlrpcTypes[$type]==3)\r
1686                                 {\r
1687                                         $this->addStruct($val);\r
1688                                 }\r
1689                         }\r
1690                 }\r
1691 \r
1692                 function addScalar($val, $type='string')\r
1693                 {\r
1694                         global $xmlrpcTypes, $xmlrpcBoolean;\r
1695 \r
1696                         if ($this->mytype==1)\r
1697                         {\r
1698                                 echo '<B>xmlrpcval</B>: scalar can have only one value<BR>';\r
1699                                 return 0;\r
1700                         }\r
1701                         $typeof=$xmlrpcTypes[$type];\r
1702                         if ($typeof!=1)\r
1703                         {\r
1704                                 echo '<B>xmlrpcval</B>: not a scalar type (${typeof})<BR>';\r
1705                                 return 0;\r
1706                         }\r
1707 \r
1708                         if ($type==$xmlrpcBoolean)\r
1709                         {\r
1710                                 if (strcasecmp($val,'true')==0 || $val==1 || ($val==true && strcasecmp($val,'false')))\r
1711                                 {\r
1712                                         $val=1;\r
1713                                 }\r
1714                                 else\r
1715                                 {\r
1716                                         $val=0;\r
1717                                 }\r
1718                         }\r
1719 \r
1720                         if ($this->mytype==2)\r
1721                         {\r
1722                                 // we're adding to an array here\r
1723                                 $ar=$this->me['array'];\r
1724                                 $ar[]=new xmlrpcval($val, $type);\r
1725                                 $this->me['array']=$ar;\r
1726                         }\r
1727                         else\r
1728                         {\r
1729                                 // a scalar, so set the value and remember we're scalar\r
1730                                 $this->me[$type]=$val;\r
1731                                 $this->mytype=$typeof;\r
1732                         }\r
1733                         return 1;\r
1734                 }\r
1735 \r
1736                 function addArray($vals)\r
1737                 {\r
1738                         global $xmlrpcTypes;\r
1739                         if ($this->mytype!=0)\r
1740                         {\r
1741                                 echo '<B>xmlrpcval</B>: already initialized as a [' . $this->kindOf() . ']<BR>';\r
1742                                 return 0;\r
1743                         }\r
1744 \r
1745                         $this->mytype=$xmlrpcTypes['array'];\r
1746                         $this->me['array']=$vals;\r
1747                         return 1;\r
1748                 }\r
1749 \r
1750                 function addStruct($vals)\r
1751                 {\r
1752                         global $xmlrpcTypes;\r
1753                         if ($this->mytype!=0)\r
1754                         {\r
1755                                 echo '<B>xmlrpcval</B>: already initialized as a [' . $this->kindOf() . ']<BR>';\r
1756                                 return 0;\r
1757                         }\r
1758                         $this->mytype=$xmlrpcTypes['struct'];\r
1759                         $this->me['struct']=$vals;\r
1760                         return 1;\r
1761                 }\r
1762 \r
1763                 function dump($ar)\r
1764                 {\r
1765                         reset($ar);\r
1766                         while ( list( $key, $val ) = each( $ar ) )\r
1767                         {\r
1768                                 echo "$key => $val<br>";\r
1769                                 if ($key == 'array')\r
1770                                 {\r
1771                                         while ( list( $key2, $val2 ) = each( $val ) )\r
1772                                         {\r
1773                                                 echo "-- $key2 => $val2<br>";\r
1774                                         }\r
1775                                 }\r
1776                         }\r
1777                 }\r
1778 \r
1779                 function kindOf()\r
1780                 {\r
1781                         switch($this->mytype)\r
1782                         {\r
1783                                 case 3:\r
1784                                         return 'struct';\r
1785                                         break;\r
1786                                 case 2:\r
1787                                         return 'array';\r
1788                                         break;\r
1789                                 case 1:\r
1790                                         return 'scalar';\r
1791                                         break;\r
1792                                 default:\r
1793                                         return 'undef';\r
1794                         }\r
1795                 }\r
1796 \r
1797                 function serializedata($typ, $val)\r
1798                 {\r
1799                         $rs='';\r
1800                         global $xmlrpcTypes, $xmlrpcBase64, $xmlrpcString,\r
1801                         $xmlrpcBoolean;\r
1802                         switch(@$xmlrpcTypes[$typ])\r
1803                         {\r
1804                                 case 3:\r
1805                                         // struct\r
1806                                         $rs.="<struct>\n";\r
1807                                         reset($val);\r
1808                                         while(list($key2, $val2)=each($val))\r
1809                                         {\r
1810                                                 $rs.="<member><name>${key2}</name>\n";\r
1811                                                 $rs.=$this->serializeval($val2);\r
1812                                                 $rs.="</member>\n";\r
1813                                         }\r
1814                                         $rs.='</struct>';\r
1815                                         break;\r
1816                                 case 2:\r
1817                                         // array\r
1818                                         $rs.="<array>\n<data>\n";\r
1819                                         for($i=0; $i<sizeof($val); $i++)\r
1820                                         {\r
1821                                                 $rs.=$this->serializeval($val[$i]);\r
1822                                         }\r
1823                                         $rs.="</data>\n</array>";\r
1824                                         break;\r
1825                                 case 1:\r
1826                                         switch ($typ)\r
1827                                         {\r
1828                                                 case $xmlrpcBase64:\r
1829                                                         $rs.="<${typ}>" . base64_encode($val) . "</${typ}>";\r
1830                                                         break;\r
1831                                                 case $xmlrpcBoolean:\r
1832                                                         $rs.="<${typ}>" . ($val ? '1' : '0') . "</${typ}>";\r
1833                                                         break;\r
1834                                                 case $xmlrpcString:\r
1835                                                         // G. Giunta 2005/2/13: do NOT use htmlentities, since\r
1836                                                         // it will produce named html entities, which are invalid xml\r
1837                                                         // $rs.="<${typ}>" . xmlrpc_encode_entitites($val). "</${typ}>";\r
1838                                                         // $rs.="<${typ}>" . htmlentities($val). "</${typ}>";\r
1839                                                         \r
1840                                                         // N. Leenheer 2005/6/30: Use CDATA instead... \r
1841                                                         $rs.="<${typ}><![CDATA[" . $val. "]]></${typ}>";\r
1842                                                         break;\r
1843                                                 default:\r
1844                                                         $rs.="<${typ}>${val}</${typ}>";\r
1845                                         }\r
1846                                         break;\r
1847                                 default:\r
1848                                         break;\r
1849                         }\r
1850                         return $rs;\r
1851                 }\r
1852 \r
1853                 function serialize()\r
1854                 {\r
1855                         return $this->serializeval($this);\r
1856                 }\r
1857 \r
1858                 function serializeval($o)\r
1859                 {\r
1860                         //global $xmlrpcTypes;\r
1861                         $rs='';\r
1862                         $ar=$o->me;\r
1863                         reset($ar);\r
1864                         list($typ, $val) = each($ar);\r
1865                         $rs.='<value>';\r
1866                         $rs.=$this->serializedata($typ, $val);\r
1867                         $rs.="</value>\n";\r
1868                         return $rs;\r
1869                 }\r
1870 \r
1871                 function structmem($m)\r
1872                 {\r
1873                         $nv=$this->me['struct'][$m];\r
1874                         return $nv;\r
1875                 }\r
1876 \r
1877                 function structreset()\r
1878                 {\r
1879                         reset($this->me['struct']);\r
1880                 }\r
1881 \r
1882                 function structeach()\r
1883                 {\r
1884                         return each($this->me['struct']);\r
1885                 }\r
1886 \r
1887                 function getval()\r
1888                 {\r
1889                         // UNSTABLE\r
1890                         global $xmlrpcBoolean, $xmlrpcBase64;\r
1891                         reset($this->me);\r
1892                         list($a,$b)=each($this->me);\r
1893                         // contributed by I Sofer, 2001-03-24\r
1894                         // add support for nested arrays to scalarval\r
1895                         // i've created a new method here, so as to\r
1896                         // preserve back compatibility\r
1897 \r
1898                         if (is_array($b))\r
1899                         {\r
1900                                 @reset($b);\r
1901                                 while(list($id,$cont) = @each($b))\r
1902                                 {\r
1903                                         $b[$id] = $cont->scalarval();\r
1904                                 }\r
1905                         }\r
1906 \r
1907                         // add support for structures directly encoding php objects\r
1908                         if (is_object($b))\r
1909                         {\r
1910                                 $t = get_object_vars($b);\r
1911                                 @reset($t);\r
1912                                 while(list($id,$cont) = @each($t))\r
1913                                 {\r
1914                                         $t[$id] = $cont->scalarval();\r
1915                                 }\r
1916                                 @reset($t);\r
1917                                 while(list($id,$cont) = @each($t))\r
1918                                 {\r
1919                                         //eval('$b->'.$id.' = $cont;');\r
1920                                         @$b->$id = $cont;\r
1921                                 }\r
1922                         }\r
1923                         // end contrib\r
1924                         return $b;\r
1925                 }\r
1926 \r
1927                 function scalarval()\r
1928                 {\r
1929                         //global $xmlrpcBoolean, $xmlrpcBase64;\r
1930                         reset($this->me);\r
1931                         list($a,$b)=each($this->me);\r
1932                         return $b;\r
1933                 }\r
1934 \r
1935                 function scalartyp()\r
1936                 {\r
1937                         global $xmlrpcI4, $xmlrpcInt;\r
1938                         reset($this->me);\r
1939                         list($a,$b)=each($this->me);\r
1940                         if ($a==$xmlrpcI4)\r
1941                         {\r
1942                                 $a=$xmlrpcInt;\r
1943                         }\r
1944                         return $a;\r
1945                 }\r
1946 \r
1947                 function arraymem($m)\r
1948                 {\r
1949                         $nv=$this->me['array'][$m];\r
1950                         return $nv;\r
1951                 }\r
1952 \r
1953                 function arraysize()\r
1954                 {\r
1955                         reset($this->me);\r
1956                         list($a,$b)=each($this->me);\r
1957                         return sizeof($b);\r
1958                 }\r
1959         }\r
1960 \r
1961         // date helpers\r
1962         function iso8601_encode($timet, $utc=0)\r
1963         {\r
1964                 // return an ISO8601 encoded string\r
1965                 // really, timezones ought to be supported\r
1966                 // but the XML-RPC spec says:\r
1967                 //\r
1968                 // "Don't assume a timezone. It should be specified by the server in its\r
1969                 // documentation what assumptions it makes about timezones."\r
1970                 // \r
1971                 // these routines always assume localtime unless \r
1972                 // $utc is set to 1, in which case UTC is assumed\r
1973                 // and an adjustment for locale is made when encoding\r
1974                 if (!$utc)\r
1975                 {\r
1976                         $t=strftime("%Y%m%dT%H:%M:%S", $timet);\r
1977                 }\r
1978                 else\r
1979                 {\r
1980                         if (function_exists('gmstrftime'))\r
1981                         {\r
1982                                 // gmstrftime doesn't exist in some versions\r
1983                                 // of PHP\r
1984                                 $t=gmstrftime("%Y%m%dT%H:%M:%S", $timet);\r
1985                         }\r
1986                         else\r
1987                         {\r
1988                                 $t=strftime("%Y%m%dT%H:%M:%S", $timet-date('Z'));\r
1989                         }\r
1990                 }\r
1991                 return $t;\r
1992         }\r
1993 \r
1994         function iso8601_decode($idate, $utc=0)\r
1995         {\r
1996                 // return a timet in the localtime, or UTC\r
1997                 $t=0;\r
1998                 if (ereg("([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})", $idate, $regs))\r
1999                 {\r
2000                         if ($utc)\r
2001                         {\r
2002                                 $t=gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);\r
2003                         }\r
2004                         else\r
2005                         {\r
2006                                 $t=mktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);\r
2007                         }\r
2008                 } \r
2009                 return $t;\r
2010         }\r
2011 \r
2012         /****************************************************************\r
2013         * xmlrpc_decode takes a message in PHP xmlrpc object format and *\r
2014         * tranlates it into native PHP types.                           *\r
2015         *                                                               *\r
2016         * author: Dan Libby (dan@libby.com)                             *\r
2017         ****************************************************************/\r
2018         function php_xmlrpc_decode($xmlrpc_val)\r
2019         {\r
2020                 $kind = $xmlrpc_val->kindOf();\r
2021 \r
2022                 if($kind == 'scalar')\r
2023                 {\r
2024                         return $xmlrpc_val->scalarval();\r
2025                 }\r
2026                 elseif($kind == 'array')\r
2027                 {\r
2028                         $size = $xmlrpc_val->arraysize();\r
2029                         $arr = array();\r
2030 \r
2031                         for($i = 0; $i < $size; $i++)\r
2032                         {\r
2033                                 $arr[] = php_xmlrpc_decode($xmlrpc_val->arraymem($i));\r
2034                         }\r
2035                         return $arr;\r
2036                 }\r
2037                 elseif($kind == 'struct')\r
2038                 {\r
2039                         $xmlrpc_val->structreset();\r
2040                         $arr = array();\r
2041 \r
2042                         while(list($key,$value)=$xmlrpc_val->structeach())\r
2043                         {\r
2044                                 $arr[$key] = php_xmlrpc_decode($value);\r
2045                         }\r
2046                         return $arr;\r
2047                 }\r
2048         }\r
2049 \r
2050         if(function_exists('xmlrpc_decode'))\r
2051         {\r
2052                 define('XMLRPC_EPI_ENABLED','1');\r
2053         }\r
2054         else\r
2055         {\r
2056                 define('XMLRPC_EPI_ENABLED','0');\r
2057                 function xmlrpc_decode($xmlrpc_val)\r
2058                 {\r
2059                         $kind = $xmlrpc_val->kindOf();\r
2060 \r
2061                         if($kind == 'scalar')\r
2062                         {\r
2063                                 return $xmlrpc_val->scalarval();\r
2064                         }\r
2065                         elseif($kind == 'array')\r
2066                         {\r
2067                                 $size = $xmlrpc_val->arraysize();\r
2068                                 $arr = array();\r
2069 \r
2070                                 for($i = 0; $i < $size; $i++)\r
2071                                 {\r
2072                                         $arr[]=xmlrpc_decode($xmlrpc_val->arraymem($i));\r
2073                                 }\r
2074                                 return $arr;\r
2075                         }\r
2076                         elseif($kind == 'struct')\r
2077                         {\r
2078                                 $xmlrpc_val->structreset();\r
2079                                 $arr = array();\r
2080 \r
2081                                 while(list($key,$value)=$xmlrpc_val->structeach())\r
2082                                 {\r
2083                                         $arr[$key] = xmlrpc_decode($value);\r
2084                                 }\r
2085                                 return $arr;\r
2086                         }\r
2087                 }\r
2088         }\r
2089 \r
2090         /****************************************************************\r
2091         * xmlrpc_encode takes native php types and encodes them into    *\r
2092         * xmlrpc PHP object format.                                     *\r
2093         * BUG: All sequential arrays are turned into structs.  I don't  *\r
2094         * know of a good way to determine if an array is sequential     *\r
2095         * only.                                                         *\r
2096         *                                                               *\r
2097         * feature creep -- could support more types via optional type   *\r
2098         * argument.                                                     *\r
2099         *                                                               *\r
2100         * author: Dan Libby (dan@libby.com)                             *\r
2101         ****************************************************************/\r
2102         function php_xmlrpc_encode($php_val)\r
2103         {\r
2104                 global $xmlrpcInt;\r
2105                 global $xmlrpcDouble;\r
2106                 global $xmlrpcString;\r
2107                 global $xmlrpcArray;\r
2108                 global $xmlrpcStruct;\r
2109                 global $xmlrpcBoolean;\r
2110 \r
2111                 $type = gettype($php_val);\r
2112                 $xmlrpc_val = new xmlrpcval;\r
2113 \r
2114                 switch($type)\r
2115                 {\r
2116                         case 'array':\r
2117                         case 'object':\r
2118                                 $arr = array();\r
2119                                 while (list($k,$v) = each($php_val))\r
2120                                 {\r
2121                                         $arr[$k] = php_xmlrpc_encode($v);\r
2122                                 }\r
2123                                 $xmlrpc_val->addStruct($arr);\r
2124                                 break;\r
2125                         case 'integer':\r
2126                                 $xmlrpc_val->addScalar($php_val, $xmlrpcInt);\r
2127                                 break;\r
2128                         case 'double':\r
2129                                 $xmlrpc_val->addScalar($php_val, $xmlrpcDouble);\r
2130                                 break;\r
2131                         case 'string':\r
2132                                 $xmlrpc_val->addScalar($php_val, $xmlrpcString);\r
2133                                 break;\r
2134                                 // <G_Giunta_2001-02-29>\r
2135                                 // Add support for encoding/decoding of booleans, since they are supported in PHP\r
2136                         case 'boolean':\r
2137                                 $xmlrpc_val->addScalar($php_val, $xmlrpcBoolean);\r
2138                                 break;\r
2139                                 // </G_Giunta_2001-02-29>\r
2140                         // catch "resource", "NULL", "user function", "unknown type"\r
2141                         //case 'unknown type':\r
2142                         default:\r
2143                                 // giancarlo pinerolo <ping@alt.it>\r
2144                                 // it has to return \r
2145                                 // an empty object in case (which is already\r
2146                                 // at this point), not a boolean. \r
2147                                 break;\r
2148                         }\r
2149                         return $xmlrpc_val;\r
2150         }\r
2151 \r
2152         if(XMLRPC_EPI_ENABLED == '0')\r
2153         {\r
2154                 function xmlrpc_encode($php_val)\r
2155                 {\r
2156                         global $xmlrpcInt;\r
2157                         global $xmlrpcDouble;\r
2158                         global $xmlrpcString;\r
2159                         global $xmlrpcArray;\r
2160                         global $xmlrpcStruct;\r
2161                         global $xmlrpcBoolean;\r
2162 \r
2163                         $type = gettype($php_val);\r
2164                         $xmlrpc_val = new xmlrpcval;\r
2165 \r
2166                         switch($type)\r
2167                         {\r
2168                                 case 'array':\r
2169                                 case 'object':\r
2170                                         $arr = array();\r
2171                                         while (list($k,$v) = each($php_val))\r
2172                                         {\r
2173                                                 $arr[$k] = xmlrpc_encode($v);\r
2174                                         }\r
2175                                         $xmlrpc_val->addStruct($arr);\r
2176                                         break;\r
2177                                 case 'integer':\r
2178                                         $xmlrpc_val->addScalar($php_val, $xmlrpcInt);\r
2179                                         break;\r
2180                                 case 'double':\r
2181                                         $xmlrpc_val->addScalar($php_val, $xmlrpcDouble);\r
2182                                         break;\r
2183                                 case 'string':\r
2184                                         $xmlrpc_val->addScalar($php_val, $xmlrpcString);\r
2185                                         break;\r
2186                                         // <G_Giunta_2001-02-29>\r
2187                                         // Add support for encoding/decoding of booleans, since they are supported in PHP\r
2188                                 case 'boolean':\r
2189                                         $xmlrpc_val->addScalar($php_val, $xmlrpcBoolean);\r
2190                                         break;\r
2191                                         // </G_Giunta_2001-02-29>\r
2192                                 //case 'unknown type':\r
2193                                 default:\r
2194                                         // giancarlo pinerolo <ping@alt.it>\r
2195                                         // it has to return \r
2196                                         // an empty object in case (which is already\r
2197                                         // at this point), not a boolean. \r
2198                                         break;\r
2199                         }\r
2200                         return $xmlrpc_val;\r
2201                 }\r
2202         }\r
2203 ?>\r