NCCOOS Trac Projects: Top | Web | Platforms | Processing | Viz | Sprints | Sandbox | (Wind)

root/Chameleon/trunk/Chameleon/XMLRPC/IXR_Library.inc.php

Revision 13 (checked in by jcleary, 17 years ago)

Latest Chameleon code checkout from previous repository

Line 
1 <?php
2 /*
3    IXR - The Inutio XML-RPC Library - (c) Incutio Ltd 2002
4    Version 1.61 - Simon Willison, 11th July 2003 (htmlentities -> htmlspecialchars)
5    Site:   http://scripts.incutio.com/xmlrpc/
6    Manual: http://scripts.incutio.com/xmlrpc/manual.php
7    Made available under the Artistic License: http://www.opensource.org/licenses/artistic-license.php
8 */
9
10
11 class IXR_Value {
12     var $data;
13     var $type;
14     function IXR_Value ($data, $type = false) {
15         $this->data = $data;
16         if (!$type) {
17             $type = $this->calculateType();
18         }
19         $this->type = $type;
20         if ($type == 'struct') {
21             /* Turn all the values in the array in to new IXR_Value objects */
22             foreach ($this->data as $key => $value) {
23                 $this->data[$key] = new IXR_Value($value);
24             }
25         }
26         if ($type == 'array') {
27             for ($i = 0, $j = count($this->data); $i < $j; $i++) {
28                 $this->data[$i] = new IXR_Value($this->data[$i]);
29             }
30         }
31     }
32     function calculateType() {
33         if ($this->data === true || $this->data === false) {
34             return 'boolean';
35         }
36         if (is_integer($this->data)) {
37             return 'int';
38         }
39         if (is_double($this->data)) {
40             return 'double';
41         }
42         // Deal with IXR object types base64 and date
43         if (is_object($this->data) && is_a($this->data, 'IXR_Date')) {
44             return 'date';
45         }
46         if (is_object($this->data) && is_a($this->data, 'IXR_Base64')) {
47             return 'base64';
48         }
49         // If it is a normal PHP object convert it in to a struct
50         if (is_object($this->data)) {
51            
52             $this->data = get_object_vars($this->data);
53             return 'struct';
54         }
55         if (!is_array($this->data)) {
56             return 'string';
57         }
58         /* We have an array - is it an array or a struct ? */
59         if ($this->isStruct($this->data)) {
60             return 'struct';
61         } else {
62             return 'array';
63         }
64     }
65     function getXml() {
66         /* Return XML for this value */
67         switch ($this->type) {
68             case 'boolean':
69                 return '<boolean>'.(($this->data) ? '1' : '0').'</boolean>';
70                 break;
71             case 'int':
72                 return '<int>'.$this->data.'</int>';
73                 break;
74             case 'double':
75                 return '<double>'.$this->data.'</double>';
76                 break;
77             case 'string':
78                 return '<string>'.htmlspecialchars($this->data).'</string>';
79                 break;
80             case 'array':
81                 $return = '<array><data>'."\n";
82                 foreach ($this->data as $item) {
83                     $return .= '  <value>'.$item->getXml()."</value>\n";
84                 }
85                 $return .= '</data></array>';
86                 return $return;
87                 break;
88             case 'struct':
89                 $return = '<struct>'."\n";
90                 foreach ($this->data as $name => $value) {
91                     $return .= "  <member><name>$name</name><value>";
92                     $return .= $value->getXml()."</value></member>\n";
93                 }
94                 $return .= '</struct>';
95                 return $return;
96                 break;
97             case 'date':
98             case 'base64':
99                 return $this->data->getXml();
100                 break;
101         }
102         return false;
103     }
104     function isStruct($array) {
105         /* Nasty function to check if an array is a struct or not */
106         $expected = 0;
107         foreach ($array as $key => $value) {
108             if ((string)$key != (string)$expected) {
109                 return true;
110             }
111             $expected++;
112         }
113         return false;
114     }
115 }
116
117
118 class IXR_Message {
119     var $message;
120     var $messageType;  // methodCall / methodResponse / fault
121     var $faultCode;
122     var $faultString;
123     var $methodName;
124     var $params;
125     // Current variable stacks
126     var $_arraystructs = array();   // The stack used to keep track of the current array/struct
127     var $_arraystructstypes = array(); // Stack keeping track of if things are structs or array
128     var $_currentStructName = array();  // A stack as well
129     var $_param;
130     var $_value;
131     var $_currentTag;
132     var $_currentTagContents;
133     // The XML parser
134     var $_parser;
135     function IXR_Message ($message) {
136         $this->message = $message;
137     }
138     function parse() {
139         // first remove the XML declaration
140         $this->message = preg_replace('/<\?xml(.*)?\?'.'>/', '', $this->message);
141         if (trim($this->message) == '') {
142             return false;
143         }
144
145         $this->_parser = xml_parser_create();
146         // Set XML parser to take the case of tags in to account
147         xml_parser_set_option($this->_parser, XML_OPTION_CASE_FOLDING, false);
148         // Set XML parser callback functions
149         xml_set_object($this->_parser, $this);
150         xml_set_element_handler($this->_parser, 'tag_open', 'tag_close');
151         xml_set_character_data_handler($this->_parser, 'cdata');
152                
153         if (!xml_parse($this->_parser, $this->message)) {
154             /* die(sprintf('XML error: %s at line %d',
155                 xml_error_string(xml_get_error_code($this->_parser)),
156                 xml_get_current_line_number($this->_parser))); */
157
158             return false;
159         }
160            
161         xml_parser_free($this->_parser);
162         // Grab the error messages, if any
163         if ($this->messageType == 'fault') {
164             $this->faultCode = $this->params[0]['faultCode'];
165             $this->faultString = $this->params[0]['faultString'];
166         }
167         return true;
168     }
169     function tag_open($parser, $tag, $attr) {
170         $this->currentTag = $tag;
171         switch($tag) {
172             case 'methodCall':
173             case 'methodResponse':
174             case 'fault':
175                 $this->messageType = $tag;
176                 break;
177             /* Deal with stacks of arrays and structs */
178             case 'data':    // data is to all intents and puposes more interesting than array
179                 $this->_arraystructstypes[] = 'array';
180                 $this->_arraystructs[] = array();
181                 break;
182             case 'struct':
183                 $this->_arraystructstypes[] = 'struct';
184                 $this->_arraystructs[] = array();
185                 break;
186         }
187     }
188     function cdata($parser, $cdata) {
189         $this->_currentTagContents .= $cdata;
190     }
191     function tag_close($parser, $tag) {
192         $valueFlag = false;
193         switch($tag) {
194             case 'int':
195             case 'i4':
196                 $value = (int)trim($this->_currentTagContents);
197                 $this->_currentTagContents = '';
198                 $valueFlag = true;
199                 break;
200             case 'double':
201                 $value = (double)trim($this->_currentTagContents);
202                 $this->_currentTagContents = '';
203                 $valueFlag = true;
204                 break;
205             case 'string':
206                 $value = (string)trim($this->_currentTagContents);
207                 $this->_currentTagContents = '';
208                 $valueFlag = true;
209                 break;
210             case 'dateTime.iso8601':
211                 $value = new IXR_Date(trim($this->_currentTagContents));
212                 // $value = $iso->getTimestamp();
213                 $this->_currentTagContents = '';
214                 $valueFlag = true;
215                 break;
216             case 'value':
217                 // "If no type is indicated, the type is string."
218                 if (trim($this->_currentTagContents) != '') {
219                     $value = (string)$this->_currentTagContents;
220                     $this->_currentTagContents = '';
221                     $valueFlag = true;
222                 }
223                 break;
224             case 'boolean':
225                 $value = (boolean)trim($this->_currentTagContents);
226                 $this->_currentTagContents = '';
227                 $valueFlag = true;
228                 break;
229             case 'base64':
230                 $value = base64_decode($this->_currentTagContents);
231                 $this->_currentTagContents = '';
232                 $valueFlag = true;
233                 break;
234             /* Deal with stacks of arrays and structs */
235             case 'data':
236             case 'struct':
237                 $value = array_pop($this->_arraystructs);
238                 array_pop($this->_arraystructstypes);
239                 $valueFlag = true;
240                 break;
241             case 'member':
242                 array_pop($this->_currentStructName);
243                 break;
244             case 'name':
245                 $this->_currentStructName[] = trim($this->_currentTagContents);
246                 $this->_currentTagContents = '';
247                 break;
248             case 'methodName':
249                 $this->methodName = trim($this->_currentTagContents);
250                 $this->_currentTagContents = '';
251                 break;
252         }
253         if ($valueFlag) {
254             /*
255             if (!is_array($value) && !is_object($value)) {
256                 $value = trim($value);
257             }
258             */
259             if (count($this->_arraystructs) > 0) {
260                 // Add value to struct or array
261                 if ($this->_arraystructstypes[count($this->_arraystructstypes)-1] == 'struct') {
262                     // Add to struct
263                     $this->_arraystructs[count($this->_arraystructs)-1][$this->_currentStructName[count($this->_currentStructName)-1]] = $value;
264                 } else {
265                     // Add to array
266                     $this->_arraystructs[count($this->_arraystructs)-1][] = $value;
267                 }
268             } else {
269                 // Just add as a paramater
270                 $this->params[] = $value;
271             }
272         }
273     }       
274 }
275
276
277 class IXR_Server {
278     var $data;
279     var $callbacks = array();
280     var $message;
281     var $capabilities;
282     function IXR_Server($callbacks = false, $data = false) {
283         $this->setCapabilities();
284         if ($callbacks) {
285             $this->callbacks = $callbacks;
286         }
287         $this->setCallbacks();
288         $this->serve($data);
289     }
290     function serve($data = false) {
291         if (!$data) {
292             global $HTTP_RAW_POST_DATA;
293             if (!$HTTP_RAW_POST_DATA) {
294                die('XML-RPC server accepts POST requests only.');
295             }
296             $data = $HTTP_RAW_POST_DATA;
297         }
298         $this->message = new IXR_Message($data);
299         if (!$this->message->parse()) {
300             $this->error(-32700, 'parse error. not well formed');
301         }
302         if ($this->message->messageType != 'methodCall') {
303             $this->error(-32600, 'server error. invalid xml-rpc. not conforming to spec. Request must be a methodCall');
304         }
305         $result = $this->call($this->message->methodName, $this->message->params);
306         // Is the result an error?
307         if (is_a($result, 'IXR_Error')) {
308             $this->error($result);
309         }
310         // Encode the result
311         $r = new IXR_Value($result);
312         $resultxml = $r->getXml();
313         // Create the XML
314         $xml = <<<EOD
315 <methodResponse>
316   <params>
317     <param>
318       <value>
319         $resultxml
320       </value>
321     </param>
322   </params>
323 </methodResponse>
324
325 EOD;
326         // Send it
327         $this->output($xml);
328     }
329     function call($methodname, $args) {
330         if (!$this->hasMethod($methodname)) {
331             return new IXR_Error(-32601, 'server error. requested method '.$methodname.' does not exist.');
332         }
333         $method = $this->callbacks[$methodname];
334         // Perform the callback and send the response
335         if (count($args) == 1) {
336             // If only one paramater just send that instead of the whole array
337             $args = $args[0];
338         }
339         // Are we dealing with a function or a method?
340         if (substr($method, 0, 5) == 'this:') {
341             // It's a class method - check it exists
342             $method = substr($method, 5);
343             if (!method_exists($this, $method)) {
344                 return new IXR_Error(-32601, 'server error. requested class method "'.$method.'" does not exist.');
345             }
346             // Call the method
347             $result = $this->$method($args);
348         } else {
349             // It's a function - does it exist?
350             if (!function_exists($method)) {
351                 return new IXR_Error(-32601, 'server error. requested function "'.$method.'" does not exist.');
352             }
353             // Call the function
354             $result = $method($args);
355         }
356         return $result;
357     }
358
359     function error($error, $message = false) {
360         // Accepts either an error object or an error code and message
361         if ($message && !is_object($error)) {
362             $error = new IXR_Error($error, $message);
363         }
364         $this->output($error->getXml());
365     }
366     function output($xml) {
367         $xml = '<?xml version="1.0"?>'."\n".$xml;
368         $length = strlen($xml);
369         header('Connection: close');
370         header('Content-Length: '.$length);
371         header('Content-Type: text/xml');
372         header('Date: '.date('r'));
373         echo $xml;
374         exit;
375     }
376     function hasMethod($method) {
377         return in_array($method, array_keys($this->callbacks));
378     }
379     function setCapabilities() {
380         // Initialises capabilities array
381         $this->capabilities = array(
382             'xmlrpc' => array(
383                 'specUrl' => 'http://www.xmlrpc.com/spec',
384                 'specVersion' => 1
385             ),
386             'faults_interop' => array(
387                 'specUrl' => 'http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php',
388                 'specVersion' => 20010516
389             ),
390             'system.multicall' => array(
391                 'specUrl' => 'http://www.xmlrpc.com/discuss/msgReader$1208',
392                 'specVersion' => 1
393             ),
394         );   
395     }
396     function getCapabilities($args) {
397         return $this->capabilities;
398     }
399     function setCallbacks() {
400         $this->callbacks['system.getCapabilities'] = 'this:getCapabilities';
401         $this->callbacks['system.listMethods'] = 'this:listMethods';
402         $this->callbacks['system.multicall'] = 'this:multiCall';
403     }
404     function listMethods($args) {
405         // Returns a list of methods - uses array_reverse to ensure user defined
406         // methods are listed before server defined methods
407         return array_reverse(array_keys($this->callbacks));
408     }
409     function multiCall($methodcalls) {
410         // See http://www.xmlrpc.com/discuss/msgReader$1208
411         $return = array();
412         foreach ($methodcalls as $call) {
413             $method = $call['methodName'];
414             $params = $call['params'];
415             if ($method == 'system.multicall') {
416                 $result = new IXR_Error(-32600, 'Recursive calls to system.multicall are forbidden');
417             } else {
418                 $result = $this->call($method, $params);
419             }
420             if (is_a($result, 'IXR_Error')) {
421                 $return[] = array(
422                     'faultCode' => $result->code,
423                     'faultString' => $result->message
424                 );
425             } else {
426                 $return[] = array($result);
427             }
428         }
429         return $return;
430     }
431 }
432
433 class IXR_Request {
434     var $method;
435     var $args;
436     var $xml;
437     function IXR_Request($method, $args) {
438         $this->method = $method;
439         $this->args = $args;
440         $this->xml = <<<EOD
441 <?xml version="1.0"?>
442 <methodCall>
443 <methodName>{$this->method}</methodName>
444 <params>
445
446 EOD;
447         foreach ($this->args as $arg) {
448             $this->xml .= '<param><value>';
449             $v = new IXR_Value($arg);
450             $this->xml .= $v->getXml();
451             $this->xml .= "</value></param>\n";
452         }
453         $this->xml .= '</params></methodCall>';
454     }
455     function getLength() {
456         return strlen($this->xml);
457     }
458     function getXml() {
459         return $this->xml;
460     }
461 }
462
463
464 class IXR_Client {
465     var $server;
466     var $port;
467     var $path;
468     var $useragent;
469     var $response;
470     var $message = false;
471     var $debug = false;
472     // Storage place for an error message
473     var $error = false;
474     function IXR_Client($server, $path = false, $port = 80) {
475         if (!$path) {
476             // Assume we have been given a URL instead
477             $bits = parse_url($server);
478             $this->server = $bits['host'];
479             $this->port = isset($bits['port']) ? $bits['port'] : 80;
480             $this->path = isset($bits['path']) ? $bits['path'] : '/';
481             // Make absolutely sure we have a path
482             if (!$this->path) {
483                 $this->path = '/';
484             }
485         } else {
486             $this->server = $server;
487             $this->path = $path;
488             $this->port = $port;
489         }
490         $this->useragent = 'The Incutio XML-RPC PHP Library';
491     }
492     function query() {
493         $args = func_get_args();
494         $method = array_shift($args);
495         $request = new IXR_Request($method, $args);
496         $length = $request->getLength();
497         $xml = $request->getXml();
498         $r = "\r\n";
499         $request  = "POST {$this->path} HTTP/1.0$r";
500         $request .= "Host: {$this->server}$r";
501         $request .= "Content-Type: text/xml$r";
502         $request .= "User-Agent: {$this->useragent}$r";
503         $request .= "Content-length: {$length}$r$r";
504         $request .= $xml;
505
506         // Now send the request
507         if ($this->debug) {
508             echo '<pre>'.htmlspecialchars($request)."\n</pre>\n\n";
509         }
510         $fp = @fsockopen($this->server, $this->port);
511         if (!$fp) {
512             $this->error = new IXR_Error(-32300, 'transport error - could not open socket');
513             return false;
514         }
515
516         fputs($fp, $request);
517         $contents = '';
518         $gotFirstLine = false;
519         $gettingHeaders = true;
520         while (!feof($fp)) {
521             $line = fgets($fp, 4096);
522             if (!$gotFirstLine) {
523                 // Check line for '200'
524                 if (strstr($line, '200') === false) {
525                     $this->error = new IXR_Error(-32300, 'transport error - HTTP status code was not 200');
526                     return false;
527                 }
528                 $gotFirstLine = true;
529             }
530             if (trim($line) == '') {
531                 $gettingHeaders = false;
532             }
533             if (!$gettingHeaders) {
534                 $contents .= $line;
535             }
536         }
537
538         if ($this->debug) {
539             echo '<pre>'.htmlspecialchars($contents)."\n</pre>\n\n";
540         }
541         // Now parse what we've got back
542         $this->message = new IXR_Message($contents);
543         if (!$this->message->parse()) {
544             // XML error
545             $this->error = new IXR_Error(-32700, 'parse error. not well formed');
546             return false;
547         }
548         // Is the message a fault?
549         if ($this->message->messageType == 'fault') {
550             $this->error = new IXR_Error($this->message->faultCode, $this->message->faultString);
551             return false;
552         }
553
554         // Message must be OK
555         return true;
556     }
557     function getResponse() {
558         // methodResponses can only have one param - return that
559         return $this->message->params[0];
560     }
561     function isError() {
562         return (is_object($this->error));
563     }
564     function getErrorCode() {
565         return $this->error->code;
566     }
567     function getErrorMessage() {
568         return $this->error->message;
569     }
570 }
571
572
573 class IXR_Error {
574     var $code;
575     var $message;
576     function IXR_Error($code, $message) {
577         $this->code = $code;
578         $this->message = $message;
579     }
580     function getXml() {
581         $xml = <<<EOD
582 <methodResponse>
583   <fault>
584     <value>
585       <struct>
586         <member>
587           <name>faultCode</name>
588           <value><int>{$this->code}</int></value>
589         </member>
590         <member>
591           <name>faultString</name>
592           <value><string>{$this->message}</string></value>
593         </member>
594       </struct>
595     </value>
596   </fault>
597 </methodResponse>
598
599 EOD;
600         return $xml;
601     }
602 }
603
604
605 class IXR_Date {
606     var $year;
607     var $month;
608     var $day;
609     var $hour;
610     var $minute;
611     var $second;
612     function IXR_Date($time) {
613         // $time can be a PHP timestamp or an ISO one
614         if (is_numeric($time)) {
615             $this->parseTimestamp($time);
616         } else {
617             $this->parseIso($time);
618         }
619     }
620     function parseTimestamp($timestamp) {
621         $this->year = date('Y', $timestamp);
622         $this->month = date('Y', $timestamp);
623         $this->day = date('Y', $timestamp);
624         $this->hour = date('H', $timestamp);
625         $this->minute = date('i', $timestamp);
626         $this->second = date('s', $timestamp);
627     }
628     function parseIso($iso) {
629         $this->year = substr($iso, 0, 4);
630         $this->month = substr($iso, 4, 2);
631         $this->day = substr($iso, 6, 2);
632         $this->hour = substr($iso, 9, 2);
633         $this->minute = substr($iso, 12, 2);
634         $this->second = substr($iso, 15, 2);
635     }
636     function getIso() {
637         return $this->year.$this->month.$this->day.'T'.$this->hour.':'.$this->minute.':'.$this->second;
638     }
639     function getXml() {
640         return '<dateTime.iso8601>'.$this->getIso().'</dateTime.iso8601>';
641     }
642     function getTimestamp() {
643         return mktime($this->hour, $this->minute, $this->second, $this->month, $this->day, $this->year);
644     }
645 }
646
647
648 class IXR_Base64 {
649     var $data;
650     function IXR_Base64($data) {
651         $this->data = $data;
652     }
653     function getXml() {
654         return '<base64>'.base64_encode($this->data).'</base64>';
655     }
656 }
657
658
659 class IXR_IntrospectionServer extends IXR_Server {
660     var $signatures;
661     var $help;
662     function IXR_IntrospectionServer() {
663         $this->setCallbacks();
664         $this->setCapabilities();
665         $this->capabilities['introspection'] = array(
666             'specUrl' => 'http://xmlrpc.usefulinc.com/doc/reserved.html',
667             'specVersion' => 1
668         );
669         $this->addCallback(
670             'system.methodSignature',
671             'this:methodSignature',
672             array('array', 'string'),
673             'Returns an array describing the return type and required parameters of a method'
674         );
675         $this->addCallback(
676             'system.getCapabilities',
677             'this:getCapabilities',
678             array('struct'),
679             'Returns a struct describing the XML-RPC specifications supported by this server'
680         );
681         $this->addCallback(
682             'system.listMethods',
683             'this:listMethods',
684             array('array'),
685             'Returns an array of available methods on this server'
686         );
687         $this->addCallback(
688             'system.methodHelp',
689             'this:methodHelp',
690             array('string', 'string'),
691             'Returns a documentation string for the specified method'
692         );
693     }
694     function addCallback($method, $callback, $args, $help) {
695         $this->callbacks[$method] = $callback;
696         $this->signatures[$method] = $args;
697         $this->help[$method] = $help;
698     }
699     function call($methodname, $args) {
700         // Make sure it's in an array
701         if ($args && !is_array($args)) {
702             $args = array($args);
703         }
704         // Over-rides default call method, adds signature check
705         if (!$this->hasMethod($methodname)) {
706             return new IXR_Error(-32601, 'server error. requested method "'.$this->message->methodName.'" not specified.');
707         }
708         $method = $this->callbacks[$methodname];
709         $signature = $this->signatures[$methodname];
710         $returnType = array_shift($signature);
711         // Check the number of arguments
712         if (count($args) != count($signature)) {
713             // print 'Num of args: '.count($args).' Num in signature: '.count($signature);
714             return new IXR_Error(-32602, 'server error. wrong number of method parameters');
715         }
716         // Check the argument types
717         $ok = true;
718         $argsbackup = $args;
719         for ($i = 0, $j = count($args); $i < $j; $i++) {
720             $arg = array_shift($args);
721             $type = array_shift($signature);
722             switch ($type) {
723                 case 'int':
724                 case 'i4':
725                     if (is_array($arg) || !is_int($arg)) {
726                         $ok = false;
727                     }
728                     break;
729                 case 'base64':
730                 case 'string':
731                     if (!is_string($arg)) {
732                         $ok = false;
733                     }
734                     break;
735                 case 'boolean':
736                     if ($arg !== false && $arg !== true) {
737                         $ok = false;
738                     }
739                     break;
740                 case 'float':
741                 case 'double':
742                     if (!is_float($arg)) {
743                         $ok = false;
744                     }
745                     break;
746                 case 'date':
747                 case 'dateTime.iso8601':
748                     if (!is_a($arg, 'IXR_Date')) {
749                         $ok = false;
750                     }
751                     break;
752             }
753             if (!$ok) {
754                 return new IXR_Error(-32602, 'server error. invalid method parameters');
755             }
756         }
757         // It passed the test - run the "real" method call
758         return parent::call($methodname, $argsbackup);
759     }
760     function methodSignature($method) {
761         if (!$this->hasMethod($method)) {
762             return new IXR_Error(-32601, 'server error. requested method "'.$method.'" not specified.');
763         }
764         // We should be returning an array of types
765         $types = $this->signatures[$method];
766         $return = array();
767         foreach ($types as $type) {
768             switch ($type) {
769                 case 'string':
770                     $return[] = 'string';
771                     break;
772                 case 'int':
773                 case 'i4':
774                     $return[] = 42;
775                     break;
776                 case 'double':
777                     $return[] = 3.1415;
778                      break;
779                 case 'dateTime.iso8601':
780                     $return[] = new IXR_Date(time());
781                     break;
782                 case 'boolean':
783                     $return[] = true;
784                     break;
785                 case 'base64':
786                     $return[] = new IXR_Base64('base64');
787                     break;
788                 case 'array':
789                     $return[] = array('array');
790                     break;
791                 case 'struct':
792                     $return[] = array('struct' => 'struct');
793                     break;
794             }
795         }
796         return $return;
797     }
798     function methodHelp($method) {
799         return $this->help[$method];
800     }
801 }
802
803
804 class IXR_ClientMulticall extends IXR_Client {
805     var $calls = array();
806     function IXR_ClientMulticall($server, $path = false, $port = 80) {
807         parent::IXR_Client($server, $path, $port);
808         $this->useragent = 'The Incutio XML-RPC PHP Library (multicall client)';
809     }
810     function addCall() {
811         $args = func_get_args();
812         $methodName = array_shift($args);
813         $struct = array(
814             'methodName' => $methodName,
815             'params' => $args
816         );
817         $this->calls[] = $struct;
818     }
819     function query() {
820         // Prepare multicall, then call the parent::query() method
821         return parent::query('system.multicall', $this->calls);
822     }
823 }
824
825 ?>
Note: See TracBrowser for help on using the browser.