OSDN Git Service

02c1b966f031901e9a16dc82103a3b60fa67be1c
[nucleus-jp/nucleus-jp-ancient.git] / utf8 / nucleus / libs / xmlrpcs.inc.php
1 <?php
2 // by Edd Dumbill (C) 1999-2002
3 // <edd@usefulinc.com>
4 // $Id: xmlrpcs.inc.php,v 1.8 2007-01-31 10:02:58 kimitake Exp $
5 // $NucleusJP: xmlrpcs.inc.php,v 1.7 2006/07/12 07:11:47 kimitake Exp $
6
7 // Copyright (c) 1999,2000,2002 Edd Dumbill.
8 // All rights reserved.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions
12 // are met:
13 //
14 //    * Redistributions of source code must retain the above copyright
15 //      notice, this list of conditions and the following disclaimer.
16 //
17 //    * Redistributions in binary form must reproduce the above
18 //      copyright notice, this list of conditions and the following
19 //      disclaimer in the documentation and/or other materials provided
20 //      with the distribution.
21 //
22 //    * Neither the name of the "XML-RPC for PHP" nor the names of its
23 //      contributors may be used to endorse or promote products derived
24 //      from this software without specific prior written permission.
25 //
26 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
29 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
30 // REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
31 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
32 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
33 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
35 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
37 // OF THE POSSIBILITY OF SUCH DAMAGE.
38
39         // XML RPC Server class
40         // requires: xmlrpc.inc
41
42         // listMethods: either a string, or nothing
43         $_xmlrpcs_listMethods_sig=array(array($xmlrpcArray, $xmlrpcString), array($xmlrpcArray));
44         $_xmlrpcs_listMethods_doc='This method lists all the methods that the XML-RPC server knows how to dispatch';
45         function _xmlrpcs_listMethods($server, $m)
46         {
47                 global $xmlrpcerr, $xmlrpcstr, $_xmlrpcs_dmap;
48                 $v=new xmlrpcval();
49                 $dmap=$server->dmap;
50                 $outAr=array();
51                 for(reset($dmap); list($key, $val)=each($dmap); )
52                 {
53                         $outAr[]=new xmlrpcval($key, 'string');
54                 }
55                 $dmap=$_xmlrpcs_dmap;
56                 for(reset($dmap); list($key, $val)=each($dmap); )
57                 {
58                         $outAr[]=new xmlrpcval($key, 'string');
59                 }
60                 $v->addArray($outAr);
61                 return new xmlrpcresp($v);
62         }
63
64         $_xmlrpcs_methodSignature_sig=array(array($xmlrpcArray, $xmlrpcString));
65         $_xmlrpcs_methodSignature_doc='Returns an array of known signatures (an array of arrays) for the method name passed. If no signatures are known, returns a none-array (test for type != array to detect missing signature)';
66         function _xmlrpcs_methodSignature($server, $m)
67         {
68                 global $xmlrpcerr, $xmlrpcstr, $_xmlrpcs_dmap;
69
70                 $methName=$m->getParam(0);
71                 $methName=$methName->scalarval();
72                 if (ereg("^system\.", $methName))
73                 {
74                         $dmap=$_xmlrpcs_dmap; $sysCall=1;
75                 }
76                 else
77                 {
78                         $dmap=$server->dmap; $sysCall=0;
79                 }
80                 //      print "<!-- ${methName} -->\n";
81                 if (isset($dmap[$methName]))
82                 {
83                         if ($dmap[$methName]['signature'])
84                         {
85                                 $sigs=array();
86                                 $thesigs=$dmap[$methName]['signature'];
87                                 for($i=0; $i<sizeof($thesigs); $i++)
88                                 {
89                                         $cursig=array();
90                                         $inSig=$thesigs[$i];
91                                         for($j=0; $j<sizeof($inSig); $j++)
92                                         {
93                                                 $cursig[]=new xmlrpcval($inSig[$j], 'string');
94                                         }
95                                         $sigs[]=new xmlrpcval($cursig, 'array');
96                                 }
97                                 $r=new xmlrpcresp(new xmlrpcval($sigs, 'array'));
98                         }
99                         else
100                         {
101                                 $r=new xmlrpcresp(new xmlrpcval('undef', 'string'));
102                         }
103                 }
104                 else
105                 {
106                         $r=new xmlrpcresp(0,$xmlrpcerr['introspect_unknown'], $xmlrpcstr['introspect_unknown']);
107                 }
108                 return $r;
109         }
110
111         $_xmlrpcs_methodHelp_sig=array(array($xmlrpcString, $xmlrpcString));
112         $_xmlrpcs_methodHelp_doc='Returns help text if defined for the method passed, otherwise returns an empty string';
113         function _xmlrpcs_methodHelp($server, $m)
114         {
115                 global $xmlrpcerr, $xmlrpcstr, $_xmlrpcs_dmap;
116
117                 $methName=$m->getParam(0);
118                 $methName=$methName->scalarval();
119                 if (ereg("^system\.", $methName))
120                 {
121                         $dmap=$_xmlrpcs_dmap; $sysCall=1;
122                 }
123                 else
124                 {
125                         $dmap=$server->dmap; $sysCall=0;
126                 }
127                 // print "<!-- ${methName} -->\n";
128                 if (isset($dmap[$methName]))
129                 {
130                         if ($dmap[$methName]['docstring'])
131                         {
132                                 $r=new xmlrpcresp(new xmlrpcval($dmap[$methName]['docstring']), 'string');
133                         }
134                         else
135                         {
136                                 $r=new xmlrpcresp(new xmlrpcval('', 'string'));
137                         }
138                 }
139                 else
140                 {
141                         $r=new xmlrpcresp(0, $xmlrpcerr['introspect_unknown'], $xmlrpcstr['introspect_unknown']);
142                 }
143                 return $r;
144         }
145
146         $_xmlrpcs_multicall_sig = array(array($xmlrpcArray, $xmlrpcArray));
147         $_xmlrpcs_multicall_doc = 'Boxcar multiple RPC calls in one request. See http://www.xmlrpc.com/discuss/msgReader$1208 for details';
148
149         function _xmlrpcs_multicall_error($err)
150         {
151                 if (is_string($err))
152                 {
153                         global $xmlrpcerr, $xmlrpcstr;
154                         $str  = $xmlrpcstr["multicall_${err}"];
155                         $code = $xmlrpcerr["multicall_${err}"];
156                 }
157                 else
158                 {
159                         $code = $err->faultCode();
160                         $str = $err->faultString();
161                 }
162                 $struct['faultCode'] = new xmlrpcval($code, 'int');
163                 $struct['faultString'] = new xmlrpcval($str, 'string');
164                 return new xmlrpcval($struct, 'struct');
165         }
166
167         function _xmlrpcs_multicall_do_call($server, $call)
168         {
169                 if ($call->kindOf() != 'struct')
170                 {
171                         return _xmlrpcs_multicall_error('notstruct');
172                 }
173                 $methName = $call->structmem('methodName');
174                 if (!$methName)
175                 {
176                         return _xmlrpcs_multicall_error('nomethod');
177                 }
178                 if ($methName->kindOf() != 'scalar' || $methName->scalartyp() != 'string')
179                 {
180                         return _xmlrpcs_multicall_error('notstring');
181                 }
182                 if ($methName->scalarval() == 'system.multicall')
183                 {
184                         return _xmlrpcs_multicall_error('recursion');
185                 }
186
187                 $params = $call->structmem('params');
188                 if (!$params)
189                 {
190                         return _xmlrpcs_multicall_error('noparams');
191                 }
192                 if ($params->kindOf() != 'array')
193                 {
194                         return _xmlrpcs_multicall_error('notarray');
195                 }
196                 $numParams = $params->arraysize();
197
198                 $msg = new xmlrpcmsg($methName->scalarval());
199                 for ($i = 0; $i < $numParams; $i++)
200                 {
201                         $msg->addParam($params->arraymem($i));
202                 }
203
204                 $result = $server->execute($msg);
205
206                 if ($result->faultCode() != 0)
207                 {
208                         return _xmlrpcs_multicall_error($result);    // Method returned fault.
209                 }
210
211                 return new xmlrpcval(array($result->value()), 'array');
212         }
213
214         function _xmlrpcs_multicall($server, $m)
215         {
216                 $calls = $m->getParam(0);
217                 $numCalls = $calls->arraysize();
218                 $result = array();
219
220                 for ($i = 0; $i < $numCalls; $i++)
221                 {
222                         $call = $calls->arraymem($i);
223                         $result[$i] = _xmlrpcs_multicall_do_call($server, $call);
224                 }
225
226                 return new xmlrpcresp(new xmlrpcval($result, 'array'));
227         }
228
229         $_xmlrpcs_dmap=array(
230                 'system.listMethods' => array(
231                         'function' => '_xmlrpcs_listMethods',
232                         'signature' => $_xmlrpcs_listMethods_sig,
233                         'docstring' => $_xmlrpcs_listMethods_doc),
234                 'system.methodHelp' => array(
235                         'function' => '_xmlrpcs_methodHelp',
236                         'signature' => $_xmlrpcs_methodHelp_sig,
237                         'docstring' => $_xmlrpcs_methodHelp_doc),
238                 'system.methodSignature' => array(
239                         'function' => '_xmlrpcs_methodSignature',
240                         'signature' => $_xmlrpcs_methodSignature_sig,
241                         'docstring' => $_xmlrpcs_methodSignature_doc),
242                 'system.multicall' => array(
243                         'function' => '_xmlrpcs_multicall',
244                         'signature' => $_xmlrpcs_multicall_sig,
245                         'docstring' => $_xmlrpcs_multicall_doc
246                 )
247         );
248
249         $_xmlrpc_debuginfo='';
250         function xmlrpc_debugmsg($m)
251         {
252                 global $_xmlrpc_debuginfo;
253                 $_xmlrpc_debuginfo=$_xmlrpc_debuginfo . $m . "\n";
254         }
255
256         class xmlrpc_server
257         {
258                 var $dmap=array();
259
260                 function xmlrpc_server($dispMap='', $serviceNow=1)
261                 {
262                         global $HTTP_RAW_POST_DATA;
263                         // dispMap is a dispatch array of methods
264                         // mapped to function names and signatures
265                         // if a method
266                         // doesn't appear in the map then an unknown
267                         // method error is generated
268                         /* milosch - changed to make passing dispMap optional.
269                          * instead, you can use the class add_to_map() function
270                          * to add functions manually (borrowed from SOAPX4)
271                          */
272                         if($dispMap)
273                         {
274                                 $this->dmap = $dispMap;
275                                 if($serviceNow)
276                                 {
277                                         $this->service();
278                                 }
279                         }
280                 }
281
282                 function serializeDebug()
283                 {
284                         global $_xmlrpc_debuginfo;
285                         if ($_xmlrpc_debuginfo!='')
286                         {
287                                 return "<!-- DEBUG INFO:\n\n" . xmlrpc_encode_entitites($_xmlrpc_debuginfo) . "\n-->\n";
288                         }
289                         else
290                         {
291                                 return '';
292                         }
293                 }
294
295                 function service()
296                 {
297                         //global $xmlrpc_defencoding;
298
299                         $r=$this->parseRequest();
300                         //$payload='<?xml version="1.0" encoding="' . $xmlrpc_defencoding . '"?' . '>' . "\n"
301                         $payload='<?xml version="1.0" ?' . '>' . "\n"
302                                 . $this->serializeDebug()
303                                 . $r->serialize();
304                         header('Content-Type: text/xml');
305                         header('Content-Length: ' . (int)strlen($payload));
306                         print $payload;
307                 }
308
309                 /*
310                 add a method to the dispatch map
311                 */
312                 function add_to_map($methodname,$function,$sig,$doc)
313                 {
314                         $this->dmap[$methodname] = array(
315                                 'function'  => $function,
316                                 'signature' => $sig,
317                                 'docstring' => $doc
318                         );
319                 }
320
321                 function verifySignature($in, $sig)
322                 {
323                         for($i=0; $i<sizeof($sig); $i++)
324                         {
325                                 // check each possible signature in turn
326                                 $cursig=$sig[$i];
327                                 if (sizeof($cursig)==$in->getNumParams()+1)
328                                 {
329                                         $itsOK=1;
330                                         for($n=0; $n<$in->getNumParams(); $n++)
331                                         {
332                                                 $p=$in->getParam($n);
333                                                 // print "<!-- $p -->\n";
334                                                 if ($p->kindOf() == 'scalar')
335                                                 {
336                                                         $pt=$p->scalartyp();
337                                                 }
338                                                 else
339                                                 {
340                                                         $pt=$p->kindOf();
341                                                 }
342                                                 // $n+1 as first type of sig is return type
343                                                 if ($pt != $cursig[$n+1])
344                                                 {
345                                                         $itsOK=0;
346                                                         $pno=$n+1; $wanted=$cursig[$n+1]; $got=$pt;
347                                                         break;
348                                                 }
349                                         }
350                                         if ($itsOK)
351                                         {
352                                                 return array(1,'');
353                                         }
354                                 }
355                         }
356                         if (isset($wanted))
357                                 return array(0, "Wanted ${wanted}, got ${got} at param ${pno})");
358                         else
359                                 return array(0, "No method signature matches number of parameters");
360                 }
361
362                 function parseRequest($data='')
363                 {
364                         global $_xh,$HTTP_RAW_POST_DATA;
365                         global $xmlrpcerr, $xmlrpcstr, $xmlrpcerrxml, $xmlrpc_defencoding,
366                         $_xmlrpcs_dmap, $xmlrpc_internalencoding;
367
368                         if ($data=='')
369                         {
370                                 $data=$HTTP_RAW_POST_DATA;
371                         }
372             // G. Giunta 2005/02/13: we do NOT expect to receive html entities
373             // so we do not try to convert them into xml character entities
374                         //$data = xmlrpc_html_entity_xlate($data);
375                         $parser = xml_parser_create($xmlrpc_defencoding);
376
377                         $_xh[$parser]=array();
378                         //$_xh[$parser]['st']='';
379                         //$_xh[$parser]['cm']=0;
380                         $_xh[$parser]['isf']=0;
381                         $_xh[$parser]['isf_reason']='';
382                         $_xh[$parser]['params']=array();
383                         $_xh[$parser]['stack']=array();
384                         $_xh[$parser]['sp'] = 0;
385                         $_xh[$parser]['valuestack'] = array();
386                         $_xh[$parser]['method']='';
387
388                         // decompose incoming XML into request structure
389
390                         xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true);
391             // G. Giunta 2005/02/13: PHP internally uses ISO-8859-1, so we have to tell
392             // the xml parser to give us back data in the expected charset
393             @xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $xmlrpc_internalencoding);
394
395                         xml_set_element_handler($parser, 'xmlrpc_se', 'xmlrpc_ee');
396                         xml_set_character_data_handler($parser, 'xmlrpc_cd');
397                         xml_set_default_handler($parser, 'xmlrpc_dh');
398                         if (!xml_parse($parser, $data, 1))
399                         {
400                                 // return XML error as a faultCode
401                                 $r=new xmlrpcresp(0,
402                                 $xmlrpcerrxml+xml_get_error_code($parser),
403                                 sprintf('XML error: %s at line %d',
404                                         xml_error_string(xml_get_error_code($parser)),
405                                         xml_get_current_line_number($parser)));
406                                 xml_parser_free($parser);
407                         }
408                         else
409                         if ($_xh[$parser]['isf'])
410                         {
411                                 xml_parser_free($parser);
412                                 $r=new xmlrpcresp(0,
413                                         $xmlrpcerr['invalid_request'],
414                                         $xmlrpcstr['invalid_request'] . ' ' . $_xh[$parser]['isf_reason']);
415                         }
416                         else
417                         {
418                                 xml_parser_free($parser);
419
420                                 $m=new xmlrpcmsg($_xh[$parser]['method']);
421                                 // now add parameters in
422                                 $plist='';
423                                 //$allOK = 1;
424                                 for($i=0; $i<sizeof($_xh[$parser]['params']); $i++)
425                                 {
426                                         //print "<!-- " . $_xh[$parser]['params'][$i]. "-->\n";
427                                         $plist.="$i - " .  $_xh[$parser]['params'][$i]. ";\n";
428                                         //$allOK = 0;
429                                         //@eval('$m->addParam(' . $_xh[$parser]['params'][$i]. '); $allOK=1;');
430                                         @$m->addParam($_xh[$parser]['params'][$i]);
431                                         //if (!$allOK)
432                                         //{
433                                         //      break;
434                                         //}
435                                 }
436                                 // uncomment this to really see what the server's getting!
437                                 // xmlrpc_debugmsg($plist);
438                                 //if (!$allOK)
439                                 //{
440                                 //      $r = new xmlrpcresp(0,
441                                 //              $xmlrpcerr['incorrect_params'],
442                                 //              $xmlrpcstr['incorrect_params'] . ": xml error in param " . $i);
443                                 //}
444                                 //else
445                                 //{
446                                         $r = $this->execute($m);
447                                 //}
448                         }
449                         return $r;
450                 }
451
452                 function execute ($m)
453                 {
454                         global $xmlrpcerr, $xmlrpcstr, $_xmlrpcs_dmap;
455                         // now to deal with the method
456                         $methName = $m->method();
457                         $sysCall = ereg("^system\.", $methName);
458                         $dmap = $sysCall ? $_xmlrpcs_dmap : $this->dmap;
459
460                         if (!isset($dmap[$methName]['function']))
461                         {
462                                 // No such method
463                                 return new xmlrpcresp(0,
464                                         $xmlrpcerr['unknown_method'],
465                                         $xmlrpcstr['unknown_method']);
466                         }
467
468                         // Check signature.
469                         if (isset($dmap[$methName]['signature']))
470                         {
471                                 $sig = $dmap[$methName]['signature'];
472                                 list($ok, $errstr) = $this->verifySignature($m, $sig);
473                                 if(!$ok)
474                                 {
475                                         // Didn't match.
476                                         return new xmlrpcresp(
477                                                 0,
478                                                 $xmlrpcerr['incorrect_params'],
479                                                 $xmlrpcstr['incorrect_params'] . ": ${errstr}"
480                                         );
481                                 }
482                         }
483
484                         $func = $dmap[$methName]['function'];
485
486                         if ($sysCall)
487                         {
488                                 return call_user_func($func, $this, $m);
489                         }
490                         else
491                         {
492                                 return call_user_func($func, $m);
493                         }
494                 }
495
496                 function echoInput()
497                 {
498                         global $HTTP_RAW_POST_DATA;
499
500                         // a debugging routine: just echos back the input
501                         // packet as a string value
502
503                         $r=new xmlrpcresp;
504                         $r->xv=new xmlrpcval( "'Aha said I: '" . $HTTP_RAW_POST_DATA, 'string');
505                         print $r->serialize();
506                 }
507         }
508 ?>