WordPress 4.7
[autoinstalls/wordpress.git] / wp-includes / IXR / class-IXR-server.php
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 }