|
1 <?php |
|
2 |
|
3 /** |
|
4 * IXR_Server |
|
5 * |
|
6 * @package IXR |
|
7 * @since 1.5.0 |
|
8 */ |
|
9 class IXR_Server |
|
10 { |
|
11 var $data; |
|
12 var $callbacks = array(); |
|
13 var $message; |
|
14 var $capabilities; |
|
15 |
|
16 /** |
|
17 * PHP5 constructor. |
|
18 */ |
|
19 function __construct( $callbacks = false, $data = false, $wait = false ) |
|
20 { |
|
21 $this->setCapabilities(); |
|
22 if ($callbacks) { |
|
23 $this->callbacks = $callbacks; |
|
24 } |
|
25 $this->setCallbacks(); |
|
26 if (!$wait) { |
|
27 $this->serve($data); |
|
28 } |
|
29 } |
|
30 |
|
31 /** |
|
32 * PHP4 constructor. |
|
33 */ |
|
34 public function IXR_Server( $callbacks = false, $data = false, $wait = false ) { |
|
35 self::__construct( $callbacks, $data, $wait ); |
|
36 } |
|
37 |
|
38 function serve($data = false) |
|
39 { |
|
40 if (!$data) { |
|
41 if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] !== 'POST') { |
|
42 if ( function_exists( 'status_header' ) ) { |
|
43 status_header( 405 ); // WP #20986 |
|
44 header( 'Allow: POST' ); |
|
45 } |
|
46 header('Content-Type: text/plain'); // merged from WP #9093 |
|
47 die('XML-RPC server accepts POST requests only.'); |
|
48 } |
|
49 |
|
50 global $HTTP_RAW_POST_DATA; |
|
51 if (empty($HTTP_RAW_POST_DATA)) { |
|
52 // workaround for a bug in PHP 5.2.2 - http://bugs.php.net/bug.php?id=41293 |
|
53 $data = file_get_contents('php://input'); |
|
54 } else { |
|
55 $data =& $HTTP_RAW_POST_DATA; |
|
56 } |
|
57 } |
|
58 $this->message = new IXR_Message($data); |
|
59 if (!$this->message->parse()) { |
|
60 $this->error(-32700, 'parse error. not well formed'); |
|
61 } |
|
62 if ($this->message->messageType != 'methodCall') { |
|
63 $this->error(-32600, 'server error. invalid xml-rpc. not conforming to spec. Request must be a methodCall'); |
|
64 } |
|
65 $result = $this->call($this->message->methodName, $this->message->params); |
|
66 |
|
67 // Is the result an error? |
|
68 if (is_a($result, 'IXR_Error')) { |
|
69 $this->error($result); |
|
70 } |
|
71 |
|
72 // Encode the result |
|
73 $r = new IXR_Value($result); |
|
74 $resultxml = $r->getXml(); |
|
75 |
|
76 // Create the XML |
|
77 $xml = <<<EOD |
|
78 <methodResponse> |
|
79 <params> |
|
80 <param> |
|
81 <value> |
|
82 $resultxml |
|
83 </value> |
|
84 </param> |
|
85 </params> |
|
86 </methodResponse> |
|
87 |
|
88 EOD; |
|
89 // Send it |
|
90 $this->output($xml); |
|
91 } |
|
92 |
|
93 function call($methodname, $args) |
|
94 { |
|
95 if (!$this->hasMethod($methodname)) { |
|
96 return new IXR_Error(-32601, 'server error. requested method '.$methodname.' does not exist.'); |
|
97 } |
|
98 $method = $this->callbacks[$methodname]; |
|
99 |
|
100 // Perform the callback and send the response |
|
101 if (count($args) == 1) { |
|
102 // If only one parameter just send that instead of the whole array |
|
103 $args = $args[0]; |
|
104 } |
|
105 |
|
106 // Are we dealing with a function or a method? |
|
107 if (is_string($method) && substr($method, 0, 5) == 'this:') { |
|
108 // It's a class method - check it exists |
|
109 $method = substr($method, 5); |
|
110 if (!method_exists($this, $method)) { |
|
111 return new IXR_Error(-32601, 'server error. requested class method "'.$method.'" does not exist.'); |
|
112 } |
|
113 |
|
114 //Call the method |
|
115 $result = $this->$method($args); |
|
116 } else { |
|
117 // It's a function - does it exist? |
|
118 if (is_array($method)) { |
|
119 if (!is_callable(array($method[0], $method[1]))) { |
|
120 return new IXR_Error(-32601, 'server error. requested object method "'.$method[1].'" does not exist.'); |
|
121 } |
|
122 } else if (!function_exists($method)) { |
|
123 return new IXR_Error(-32601, 'server error. requested function "'.$method.'" does not exist.'); |
|
124 } |
|
125 |
|
126 // Call the function |
|
127 $result = call_user_func($method, $args); |
|
128 } |
|
129 return $result; |
|
130 } |
|
131 |
|
132 function error($error, $message = false) |
|
133 { |
|
134 // Accepts either an error object or an error code and message |
|
135 if ($message && !is_object($error)) { |
|
136 $error = new IXR_Error($error, $message); |
|
137 } |
|
138 $this->output($error->getXml()); |
|
139 } |
|
140 |
|
141 function output($xml) |
|
142 { |
|
143 $charset = function_exists('get_option') ? get_option('blog_charset') : ''; |
|
144 if ($charset) |
|
145 $xml = '<?xml version="1.0" encoding="'.$charset.'"?>'."\n".$xml; |
|
146 else |
|
147 $xml = '<?xml version="1.0"?>'."\n".$xml; |
|
148 $length = strlen($xml); |
|
149 header('Connection: close'); |
|
150 if ($charset) |
|
151 header('Content-Type: text/xml; charset='.$charset); |
|
152 else |
|
153 header('Content-Type: text/xml'); |
|
154 header('Date: '.date('r')); |
|
155 echo $xml; |
|
156 exit; |
|
157 } |
|
158 |
|
159 function hasMethod($method) |
|
160 { |
|
161 return in_array($method, array_keys($this->callbacks)); |
|
162 } |
|
163 |
|
164 function setCapabilities() |
|
165 { |
|
166 // Initialises capabilities array |
|
167 $this->capabilities = array( |
|
168 'xmlrpc' => array( |
|
169 'specUrl' => 'http://www.xmlrpc.com/spec', |
|
170 'specVersion' => 1 |
|
171 ), |
|
172 'faults_interop' => array( |
|
173 'specUrl' => 'http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php', |
|
174 'specVersion' => 20010516 |
|
175 ), |
|
176 'system.multicall' => array( |
|
177 'specUrl' => 'http://www.xmlrpc.com/discuss/msgReader$1208', |
|
178 'specVersion' => 1 |
|
179 ), |
|
180 ); |
|
181 } |
|
182 |
|
183 function getCapabilities($args) |
|
184 { |
|
185 return $this->capabilities; |
|
186 } |
|
187 |
|
188 function setCallbacks() |
|
189 { |
|
190 $this->callbacks['system.getCapabilities'] = 'this:getCapabilities'; |
|
191 $this->callbacks['system.listMethods'] = 'this:listMethods'; |
|
192 $this->callbacks['system.multicall'] = 'this:multiCall'; |
|
193 } |
|
194 |
|
195 function listMethods($args) |
|
196 { |
|
197 // Returns a list of methods - uses array_reverse to ensure user defined |
|
198 // methods are listed before server defined methods |
|
199 return array_reverse(array_keys($this->callbacks)); |
|
200 } |
|
201 |
|
202 function multiCall($methodcalls) |
|
203 { |
|
204 // See http://www.xmlrpc.com/discuss/msgReader$1208 |
|
205 $return = array(); |
|
206 foreach ($methodcalls as $call) { |
|
207 $method = $call['methodName']; |
|
208 $params = $call['params']; |
|
209 if ($method == 'system.multicall') { |
|
210 $result = new IXR_Error(-32600, 'Recursive calls to system.multicall are forbidden'); |
|
211 } else { |
|
212 $result = $this->call($method, $params); |
|
213 } |
|
214 if (is_a($result, 'IXR_Error')) { |
|
215 $return[] = array( |
|
216 'faultCode' => $result->code, |
|
217 'faultString' => $result->message |
|
218 ); |
|
219 } else { |
|
220 $return[] = array($result); |
|
221 } |
|
222 } |
|
223 return $return; |
|
224 } |
|
225 } |