[ Index ]

PHP Cross Reference of DokuWiki

title

Body

[close]

/vendor/kissifrot/php-ixr/src/Server/ -> Server.php (source)

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