wp/wp-includes/IXR/class-IXR-server.php
changeset 7 cf61fcea0001
child 16 a86126ab1dd4
equal deleted inserted replaced
6:490d5cc509ed 7:cf61fcea0001
       
     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 }