upgrade to codeigniter 1.7.2 for f12
[www-register-wizard.git] / libraries / Xmlrpcs.php
1 <?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
2 /**
3  * CodeIgniter
4  *
5  * An open source application development framework for PHP 4.3.2 or newer
6  *
7  * @package             CodeIgniter
8  * @author              ExpressionEngine Dev Team
9  * @copyright   Copyright (c) 2008 - 2009, EllisLab, Inc.
10  * @license             http://codeigniter.com/user_guide/license.html
11  * @link                http://codeigniter.com
12  * @since               Version 1.0
13  * @filesource
14  */
15
16 if ( ! function_exists('xml_parser_create'))
17 {       
18         show_error('Your PHP installation does not support XML');
19 }
20
21 if ( ! class_exists('CI_Xmlrpc'))
22 {
23         show_error('You must load the Xmlrpc class before loading the Xmlrpcs class in order to create a server.');
24 }
25
26 // ------------------------------------------------------------------------
27
28 /**
29  * XML-RPC server class
30  *
31  * @package             CodeIgniter
32  * @subpackage  Libraries
33  * @category    XML-RPC
34  * @author              ExpressionEngine Dev Team
35  * @link                http://codeigniter.com/user_guide/libraries/xmlrpc.html
36  */
37 class CI_Xmlrpcs extends CI_Xmlrpc
38 {
39         var $methods            = array();      //array of methods mapped to function names and signatures
40         var $debug_msg          = '';           // Debug Message
41         var $system_methods = array(); // XML RPC Server methods
42         var $controller_obj;
43
44         var $object                     = FALSE;
45         
46         
47         //-------------------------------------
48         //  Constructor, more or less
49         //-------------------------------------
50
51         function CI_Xmlrpcs($config=array())
52         {       
53                 parent::CI_Xmlrpc();
54                 $this->set_system_methods();
55         
56                 if (isset($config['functions']) && is_array($config['functions']))
57                 {
58                         $this->methods = array_merge($this->methods, $config['functions']);
59                 }
60                 
61                 log_message('debug', "XML-RPC Server Class Initialized");
62         }
63         
64         //-------------------------------------
65         //  Initialize Prefs and Serve
66         //-------------------------------------
67         
68         function initialize($config=array())
69         {       
70                 if (isset($config['functions']) && is_array($config['functions']))
71                 {
72                         $this->methods = array_merge($this->methods, $config['functions']);
73                 }
74                 
75                 if (isset($config['debug']))
76                 {
77                         $this->debug = $config['debug'];
78                 }
79                 
80                 if (isset($config['object']) && is_object($config['object']))
81                 {
82                         $this->object = $config['object'];
83                 }
84         }
85         
86         //-------------------------------------
87         //  Setting of System Methods
88         //-------------------------------------
89         
90         function set_system_methods ()
91         {
92                 $this->methods = array(
93                                         'system.listMethods'     => array(
94                                                                                                         'function' => 'this.listMethods',
95                                                                                                         'signature' => array(array($this->xmlrpcArray, $this->xmlrpcString), array($this->xmlrpcArray)),
96                                                                                                         'docstring' => 'Returns an array of available methods on this server'),
97                                         'system.methodHelp'              => array(
98                                                                                                         'function' => 'this.methodHelp',
99                                                                                                         'signature' => array(array($this->xmlrpcString, $this->xmlrpcString)),
100                                                                                                         'docstring' => 'Returns a documentation string for the specified method'),
101                                         'system.methodSignature' => array(
102                                                                                                         'function' => 'this.methodSignature',
103                                                                                                         'signature' => array(array($this->xmlrpcArray, $this->xmlrpcString)),
104                                                                                                         'docstring' => 'Returns an array describing the return type and required parameters of a method'),
105                                         'system.multicall'               => array(
106                                                                                                 'function' => 'this.multicall',
107                                                                                                 'signature' => array(array($this->xmlrpcArray, $this->xmlrpcArray)),
108                                                                                                 'docstring' => 'Combine multiple RPC calls in one request. See http://www.xmlrpc.com/discuss/msgReader$1208 for details')
109                                         );
110         }
111
112
113         //-------------------------------------
114         //  Main Server Function
115         //-------------------------------------
116         
117         function serve()
118         {
119                 $r = $this->parseRequest();
120                 $payload  = '<?xml version="1.0" encoding="'.$this->xmlrpc_defencoding.'"?'.'>'."\n";
121                 $payload .= $this->debug_msg;
122                 $payload .= $r->prepare_response();
123                 
124                 header("Content-Type: text/xml");
125                 header("Content-Length: ".strlen($payload));
126                 exit($payload);
127         }
128
129         //-------------------------------------
130         //  Add Method to Class
131         //-------------------------------------
132         
133         function add_to_map($methodname,$function,$sig,$doc)
134         {
135                 $this->methods[$methodname] = array(
136                         'function'  => $function,
137                         'signature' => $sig,
138                         'docstring' => $doc
139                 );
140         }
141
142
143         //-------------------------------------
144         //  Parse Server Request
145         //-------------------------------------
146         
147         function parseRequest($data='')
148         {
149                 global $HTTP_RAW_POST_DATA;
150                 
151                 //-------------------------------------
152                 //  Get Data
153                 //-------------------------------------
154
155                 if ($data == '')
156                 {
157                         $data = $HTTP_RAW_POST_DATA;
158                 }
159
160                 //-------------------------------------
161                 //  Set up XML Parser
162                 //-------------------------------------
163                 
164                 $parser = xml_parser_create($this->xmlrpc_defencoding);
165                 $parser_object = new XML_RPC_Message("filler");
166                 
167                 $parser_object->xh[$parser]                                     = array();
168                 $parser_object->xh[$parser]['isf']                      = 0;
169                 $parser_object->xh[$parser]['isf_reason']       = '';
170                 $parser_object->xh[$parser]['params']           = array();
171                 $parser_object->xh[$parser]['stack']            = array();
172                 $parser_object->xh[$parser]['valuestack']       = array();
173                 $parser_object->xh[$parser]['method']           = '';
174
175                 xml_set_object($parser, $parser_object);
176                 xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true);
177                 xml_set_element_handler($parser, 'open_tag', 'closing_tag');
178                 xml_set_character_data_handler($parser, 'character_data');
179                 //xml_set_default_handler($parser, 'default_handler');
180                 
181                 
182                 //-------------------------------------
183                 //  PARSE + PROCESS XML DATA
184                 //-------------------------------------         
185                 
186                 if ( ! xml_parse($parser, $data, 1))
187                 {
188                         // return XML error as a faultCode
189                         $r = new XML_RPC_Response(0,
190                         $this->xmlrpcerrxml + xml_get_error_code($parser),
191                         sprintf('XML error: %s at line %d',
192                                 xml_error_string(xml_get_error_code($parser)),
193                                 xml_get_current_line_number($parser)));
194                         xml_parser_free($parser);
195                 }
196                 elseif($parser_object->xh[$parser]['isf'])
197                 {
198                         return new XML_RPC_Response(0, $this->xmlrpcerr['invalid_return'], $this->xmlrpcstr['invalid_return']);
199                 }
200                 else
201                 {
202                         xml_parser_free($parser);
203                         
204                         $m = new XML_RPC_Message($parser_object->xh[$parser]['method']);
205                         $plist='';
206                         
207                         for($i=0; $i < count($parser_object->xh[$parser]['params']); $i++)
208                         {
209                                 if ($this->debug === TRUE)
210                                 {
211                                         $plist .= "$i - " .  print_r(get_object_vars($parser_object->xh[$parser]['params'][$i]), TRUE). ";\n";
212                                 }
213                                 
214                                 $m->addParam($parser_object->xh[$parser]['params'][$i]);
215                         }
216                         
217                         if ($this->debug === TRUE)
218                         {
219                                 echo "<pre>";
220                                 echo "---PLIST---\n" . $plist . "\n---PLIST END---\n\n";
221                                 echo "</pre>";
222                         }
223                         
224                         $r = $this->_execute($m);
225                 }
226                 
227                 //-------------------------------------
228                 //  SET DEBUGGING MESSAGE
229                 //-------------------------------------         
230                 
231                 if ($this->debug === TRUE)
232                 {
233                         $this->debug_msg = "<!-- DEBUG INFO:\n\n".$plist."\n END DEBUG-->\n";
234                 }
235                 
236                 return $r;
237         }
238
239         //-------------------------------------
240         //  Executes the Method
241         //-------------------------------------
242         
243         function _execute($m)
244         {
245                 $methName = $m->method_name;
246                 
247                 // Check to see if it is a system call
248                 $system_call = (strncmp($methName, 'system', 5) == 0) ? TRUE : FALSE;
249                 
250                 //-------------------------------------
251                 //  Valid Method
252                 //-------------------------------------
253                 
254                 if ( ! isset($this->methods[$methName]['function']))
255                 {
256                         return new XML_RPC_Response(0, $this->xmlrpcerr['unknown_method'], $this->xmlrpcstr['unknown_method']);
257                 }
258                 
259                 //-------------------------------------
260                 //  Check for Method (and Object)
261                 //-------------------------------------
262                         
263                 $method_parts = explode(".", $this->methods[$methName]['function']);
264                 $objectCall = (isset($method_parts['1']) && $method_parts['1'] != "") ? TRUE : FALSE;
265                 
266                 if ($system_call === TRUE)
267                 {
268                         if ( ! is_callable(array($this,$method_parts['1'])))
269                         {
270                                 return new XML_RPC_Response(0, $this->xmlrpcerr['unknown_method'], $this->xmlrpcstr['unknown_method']);
271                         }
272                 }
273                 else
274                 {
275                         if ($objectCall && ! is_callable(array($method_parts['0'],$method_parts['1'])))
276                         {
277                                 return new XML_RPC_Response(0, $this->xmlrpcerr['unknown_method'], $this->xmlrpcstr['unknown_method']);
278                         }
279                         elseif ( ! $objectCall && ! is_callable($this->methods[$methName]['function']))
280                         {
281                                 return new XML_RPC_Response(0, $this->xmlrpcerr['unknown_method'], $this->xmlrpcstr['unknown_method']);
282                         }
283                 }
284                 
285                 //-------------------------------------
286                 //  Checking Methods Signature
287                 //-------------------------------------
288                 
289                 if (isset($this->methods[$methName]['signature']))
290                 {
291                         $sig = $this->methods[$methName]['signature'];
292                         for($i=0; $i<count($sig); $i++)
293                         {
294                                 $current_sig = $sig[$i];
295                 
296                                 if (count($current_sig) == count($m->params)+1)
297                                 {
298                                         for($n=0; $n < count($m->params); $n++)
299                                         {
300                                                 $p = $m->params[$n];
301                                                 $pt = ($p->kindOf() == 'scalar') ? $p->scalarval() : $p->kindOf();
302                                                 
303                                                 if ($pt != $current_sig[$n+1])
304                                                 {
305                                                         $pno = $n+1;
306                                                         $wanted = $current_sig[$n+1];
307                                                         
308                                                         return new XML_RPC_Response(0,
309                                                                 $this->xmlrpcerr['incorrect_params'],
310                                                                 $this->xmlrpcstr['incorrect_params'] .
311                                                                 ": Wanted {$wanted}, got {$pt} at param {$pno})");
312                                                 }
313                                         }
314                                 }
315                         }
316                 }
317
318                 //-------------------------------------
319                 //  Calls the Function
320                 //-------------------------------------
321
322                 if ($objectCall === TRUE)
323                 {
324                         if ($method_parts[0] == "this" && $system_call == TRUE)
325                         {
326                                 return call_user_func(array($this, $method_parts[1]), $m);
327                         }
328                         else
329                         {
330                                 if ($this->object === FALSE)
331                                 {
332                                         $CI =& get_instance();
333                                         return $CI->$method_parts['1']($m);
334                                 }
335                                 else
336                                 {
337                                         return $this->object->$method_parts['1']($m);
338                                         //return call_user_func(array(&$method_parts['0'],$method_parts['1']), $m);
339                                 }
340                         }
341                 }
342                 else
343                 {
344                         return call_user_func($this->methods[$methName]['function'], $m);
345                 }
346         }
347         
348         
349         //-------------------------------------
350         //  Server Function:  List Methods
351         //-------------------------------------
352         
353         function listMethods($m)
354         {
355                 $v = new XML_RPC_Values();
356                 $output = array();
357                 
358                 foreach($this->methods as $key => $value)
359                 {
360                         $output[] = new XML_RPC_Values($key, 'string');
361                 }
362                 
363                 foreach($this->system_methods as $key => $value)
364                 {
365                         $output[]= new XML_RPC_Values($key, 'string');
366                 }
367
368                 $v->addArray($output);
369                 return new XML_RPC_Response($v);
370         }
371         
372         //-------------------------------------
373         //  Server Function:  Return Signature for Method
374         //-------------------------------------
375                 
376         function methodSignature($m)
377         {
378                 $parameters = $m->output_parameters();
379                 $method_name = $parameters[0];
380                 
381                 if (isset($this->methods[$method_name]))
382                 {
383                         if ($this->methods[$method_name]['signature'])
384                         {
385                                 $sigs = array();
386                                 $signature = $this->methods[$method_name]['signature'];
387                                 
388                                 for($i=0; $i < count($signature); $i++)
389                                 {
390                                         $cursig = array();
391                                         $inSig = $signature[$i];
392                                         for($j=0; $j<count($inSig); $j++)
393                                         {
394                                                 $cursig[]= new XML_RPC_Values($inSig[$j], 'string');
395                                         }
396                                         $sigs[]= new XML_RPC_Values($cursig, 'array');
397                                 }
398                                 $r = new XML_RPC_Response(new XML_RPC_Values($sigs, 'array'));
399                         }
400                         else
401                         {
402                                 $r = new XML_RPC_Response(new XML_RPC_Values('undef', 'string'));
403                         }
404                 }
405                 else
406                 {
407                         $r = new XML_RPC_Response(0,$this->xmlrpcerr['introspect_unknown'], $this->xmlrpcstr['introspect_unknown']);
408                 }
409                 return $r;
410         }
411         
412         //-------------------------------------
413         //  Server Function:  Doc String for Method
414         //-------------------------------------
415         
416         function methodHelp($m)
417         {
418                 $parameters = $m->output_parameters();
419                 $method_name = $parameters[0];
420         
421                 if (isset($this->methods[$method_name]))
422                 {
423                         $docstring = isset($this->methods[$method_name]['docstring']) ? $this->methods[$method_name]['docstring'] : '';
424                         
425                         return new XML_RPC_Response(new XML_RPC_Values($docstring, 'string'));
426                 }
427                 else
428                 {
429                         return new XML_RPC_Response(0, $this->xmlrpcerr['introspect_unknown'], $this->xmlrpcstr['introspect_unknown']);
430                 }
431         }
432
433         //-------------------------------------
434         //  Server Function:  Multi-call
435         //-------------------------------------
436
437         function multicall($m)
438         {
439                 // Disabled
440                 return new XML_RPC_Response(0, $this->xmlrpcerr['unknown_method'], $this->xmlrpcstr['unknown_method']);
441                 
442                 $parameters = $m->output_parameters();
443                 $calls = $parameters[0];
444
445                 $result = array();
446
447                 foreach ($calls as $value)
448                 {
449                         //$attempt = $this->_execute(new XML_RPC_Message($value[0], $value[1]));
450                         
451                         $m = new XML_RPC_Message($value[0]);
452                         $plist='';
453                         
454                         for($i=0; $i < count($value[1]); $i++)
455                         {
456                                 $m->addParam(new XML_RPC_Values($value[1][$i], 'string'));
457                         }
458                         
459                         $attempt = $this->_execute($m);
460
461                         if ($attempt->faultCode() != 0)
462                         {
463                                 return $attempt;
464                         }
465
466                         $result[] = new XML_RPC_Values(array($attempt->value()), 'array');
467                 }
468
469                 return new XML_RPC_Response(new XML_RPC_Values($result, 'array'));
470         }
471         
472         
473         //-------------------------------------
474         //  Multi-call Function:  Error Handling
475         //-------------------------------------
476
477         function multicall_error($err)
478         {
479                 $str  = is_string($err) ? $this->xmlrpcstr["multicall_${err}"] : $err->faultString();
480                 $code = is_string($err) ? $this->xmlrpcerr["multicall_${err}"] : $err->faultCode();
481                 
482                 $struct['faultCode'] = new XML_RPC_Values($code, 'int');
483                 $struct['faultString'] = new XML_RPC_Values($str, 'string');
484         
485                 return new XML_RPC_Values($struct, 'struct');
486         }
487         
488         
489         //-------------------------------------
490         //  Multi-call Function:  Processes method
491         //-------------------------------------
492         
493         function do_multicall($call)
494         {
495                 if ($call->kindOf() != 'struct')
496                         return $this->multicall_error('notstruct');
497                 elseif ( ! $methName = $call->me['struct']['methodName'])
498                         return $this->multicall_error('nomethod');
499                 
500                 list($scalar_type,$scalar_value)=each($methName->me);
501                 $scalar_type = $scalar_type == $this->xmlrpcI4 ? $this->xmlrpcInt : $scalar_type;
502                         
503                 if ($methName->kindOf() != 'scalar' OR $scalar_type != 'string')
504                         return $this->multicall_error('notstring');
505                 elseif ($scalar_value == 'system.multicall')
506                         return $this->multicall_error('recursion');
507                 elseif ( ! $params = $call->me['struct']['params'])
508                         return $this->multicall_error('noparams');
509                 elseif ($params->kindOf() != 'array')
510                         return $this->multicall_error('notarray');
511                         
512                 list($a,$b)=each($params->me);
513                 $numParams = count($b);
514
515                 $msg = new XML_RPC_Message($scalar_value);
516                 for ($i = 0; $i < $numParams; $i++)
517                 {
518                         $msg->params[] = $params->me['array'][$i];
519                 }
520
521                 $result = $this->_execute($msg);
522
523                 if ($result->faultCode() != 0)
524                 {
525                         return $this->multicall_error($result);
526                 }
527
528                 return new XML_RPC_Values(array($result->value()), 'array');
529         }       
530         
531 }
532 // END XML_RPC_Server class
533
534
535 /* End of file Xmlrpcs.php */
536 /* Location: ./system/libraries/Xmlrpcs.php */