source: sourcecode/system/libraries/Xmlrpcs.php @ 1

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