1*7f8f2456SAndreas Gohr<?php 2*7f8f2456SAndreas Gohrnamespace IXR\Server; 3*7f8f2456SAndreas Gohr 4*7f8f2456SAndreas Gohruse IXR\DataType\Base64; 5*7f8f2456SAndreas Gohruse IXR\DataType\Date; 6*7f8f2456SAndreas Gohruse IXR\Message\Error; 7*7f8f2456SAndreas Gohr 8*7f8f2456SAndreas Gohr/** 9*7f8f2456SAndreas Gohr * IXR_IntrospectionServer 10*7f8f2456SAndreas Gohr * 11*7f8f2456SAndreas Gohr * @package IXR 12*7f8f2456SAndreas Gohr * @since 1.5.0 13*7f8f2456SAndreas Gohr */ 14*7f8f2456SAndreas Gohrclass IntrospectionServer extends Server 15*7f8f2456SAndreas Gohr{ 16*7f8f2456SAndreas Gohr 17*7f8f2456SAndreas Gohr private $signatures; 18*7f8f2456SAndreas Gohr private $help; 19*7f8f2456SAndreas Gohr 20*7f8f2456SAndreas Gohr public function __construct() 21*7f8f2456SAndreas Gohr { 22*7f8f2456SAndreas Gohr $this->setCallbacks(); 23*7f8f2456SAndreas Gohr $this->setCapabilities(); 24*7f8f2456SAndreas Gohr $this->capabilities['introspection'] = [ 25*7f8f2456SAndreas Gohr 'specUrl' => 'http://xmlrpc.usefulinc.com/doc/reserved.html', 26*7f8f2456SAndreas Gohr 'specVersion' => 1 27*7f8f2456SAndreas Gohr ]; 28*7f8f2456SAndreas Gohr $this->addCallback( 29*7f8f2456SAndreas Gohr 'system.methodSignature', 30*7f8f2456SAndreas Gohr 'this:methodSignature', 31*7f8f2456SAndreas Gohr ['array', 'string'], 32*7f8f2456SAndreas Gohr 'Returns an array describing the return type and required parameters of a method' 33*7f8f2456SAndreas Gohr ); 34*7f8f2456SAndreas Gohr $this->addCallback( 35*7f8f2456SAndreas Gohr 'system.getCapabilities', 36*7f8f2456SAndreas Gohr 'this:getCapabilities', 37*7f8f2456SAndreas Gohr ['struct'], 38*7f8f2456SAndreas Gohr 'Returns a struct describing the XML-RPC specifications supported by this server' 39*7f8f2456SAndreas Gohr ); 40*7f8f2456SAndreas Gohr $this->addCallback( 41*7f8f2456SAndreas Gohr 'system.listMethods', 42*7f8f2456SAndreas Gohr 'this:listMethods', 43*7f8f2456SAndreas Gohr ['array'], 44*7f8f2456SAndreas Gohr 'Returns an array of available methods on this server' 45*7f8f2456SAndreas Gohr ); 46*7f8f2456SAndreas Gohr $this->addCallback( 47*7f8f2456SAndreas Gohr 'system.methodHelp', 48*7f8f2456SAndreas Gohr 'this:methodHelp', 49*7f8f2456SAndreas Gohr ['string', 'string'], 50*7f8f2456SAndreas Gohr 'Returns a documentation string for the specified method' 51*7f8f2456SAndreas Gohr ); 52*7f8f2456SAndreas Gohr } 53*7f8f2456SAndreas Gohr 54*7f8f2456SAndreas Gohr public function addCallback($method, $callback, $args, $help) 55*7f8f2456SAndreas Gohr { 56*7f8f2456SAndreas Gohr $this->callbacks[$method] = $callback; 57*7f8f2456SAndreas Gohr $this->signatures[$method] = $args; 58*7f8f2456SAndreas Gohr $this->help[$method] = $help; 59*7f8f2456SAndreas Gohr } 60*7f8f2456SAndreas Gohr 61*7f8f2456SAndreas Gohr public function call($methodname, $args) 62*7f8f2456SAndreas Gohr { 63*7f8f2456SAndreas Gohr // Make sure it's in an array 64*7f8f2456SAndreas Gohr if ($args && !is_array($args)) { 65*7f8f2456SAndreas Gohr $args = [$args]; 66*7f8f2456SAndreas Gohr } 67*7f8f2456SAndreas Gohr 68*7f8f2456SAndreas Gohr // Over-rides default call method, adds signature check 69*7f8f2456SAndreas Gohr if (!$this->hasMethod($methodname)) { 70*7f8f2456SAndreas Gohr return new Error(-32601, 71*7f8f2456SAndreas Gohr 'server error. requested method "' . $this->message->methodName . '" not specified.'); 72*7f8f2456SAndreas Gohr } 73*7f8f2456SAndreas Gohr $method = $this->callbacks[$methodname]; 74*7f8f2456SAndreas Gohr $signature = $this->signatures[$methodname]; 75*7f8f2456SAndreas Gohr array_shift($signature); 76*7f8f2456SAndreas Gohr 77*7f8f2456SAndreas Gohr // Check the number of arguments 78*7f8f2456SAndreas Gohr if (count($args) != count($signature)) { 79*7f8f2456SAndreas Gohr return new Error(-32602, 'server error. wrong number of method parameters'); 80*7f8f2456SAndreas Gohr } 81*7f8f2456SAndreas Gohr 82*7f8f2456SAndreas Gohr // Check the argument types 83*7f8f2456SAndreas Gohr $ok = true; 84*7f8f2456SAndreas Gohr $argsbackup = $args; 85*7f8f2456SAndreas Gohr for ($i = 0, $j = count($args); $i < $j; $i++) { 86*7f8f2456SAndreas Gohr $arg = array_shift($args); 87*7f8f2456SAndreas Gohr $type = array_shift($signature); 88*7f8f2456SAndreas Gohr switch ($type) { 89*7f8f2456SAndreas Gohr case 'int': 90*7f8f2456SAndreas Gohr case 'i4': 91*7f8f2456SAndreas Gohr if (is_array($arg) || !is_int($arg)) { 92*7f8f2456SAndreas Gohr $ok = false; 93*7f8f2456SAndreas Gohr } 94*7f8f2456SAndreas Gohr break; 95*7f8f2456SAndreas Gohr case 'base64': 96*7f8f2456SAndreas Gohr case 'string': 97*7f8f2456SAndreas Gohr if (!is_string($arg)) { 98*7f8f2456SAndreas Gohr $ok = false; 99*7f8f2456SAndreas Gohr } 100*7f8f2456SAndreas Gohr break; 101*7f8f2456SAndreas Gohr case 'boolean': 102*7f8f2456SAndreas Gohr if ($arg !== false && $arg !== true) { 103*7f8f2456SAndreas Gohr $ok = false; 104*7f8f2456SAndreas Gohr } 105*7f8f2456SAndreas Gohr break; 106*7f8f2456SAndreas Gohr case 'float': 107*7f8f2456SAndreas Gohr case 'double': 108*7f8f2456SAndreas Gohr if (!is_float($arg)) { 109*7f8f2456SAndreas Gohr $ok = false; 110*7f8f2456SAndreas Gohr } 111*7f8f2456SAndreas Gohr break; 112*7f8f2456SAndreas Gohr case 'date': 113*7f8f2456SAndreas Gohr case 'dateTime.iso8601': 114*7f8f2456SAndreas Gohr if (!($arg instanceof Date)) { 115*7f8f2456SAndreas Gohr $ok = false; 116*7f8f2456SAndreas Gohr } 117*7f8f2456SAndreas Gohr break; 118*7f8f2456SAndreas Gohr } 119*7f8f2456SAndreas Gohr if (!$ok) { 120*7f8f2456SAndreas Gohr return new Error(-32602, 'server error. invalid method parameters'); 121*7f8f2456SAndreas Gohr } 122*7f8f2456SAndreas Gohr } 123*7f8f2456SAndreas Gohr // It passed the test - run the "real" method call 124*7f8f2456SAndreas Gohr return parent::call($methodname, $argsbackup); 125*7f8f2456SAndreas Gohr } 126*7f8f2456SAndreas Gohr 127*7f8f2456SAndreas Gohr public function methodSignature($method) 128*7f8f2456SAndreas Gohr { 129*7f8f2456SAndreas Gohr if (!$this->hasMethod($method)) { 130*7f8f2456SAndreas Gohr return new Error(-32601, 'server error. requested method "' . $method . '" not specified.'); 131*7f8f2456SAndreas Gohr } 132*7f8f2456SAndreas Gohr // We should be returning an array of types 133*7f8f2456SAndreas Gohr $types = $this->signatures[$method]; 134*7f8f2456SAndreas Gohr $return = []; 135*7f8f2456SAndreas Gohr foreach ($types as $type) { 136*7f8f2456SAndreas Gohr switch ($type) { 137*7f8f2456SAndreas Gohr case 'string': 138*7f8f2456SAndreas Gohr $return[] = 'string'; 139*7f8f2456SAndreas Gohr break; 140*7f8f2456SAndreas Gohr case 'int': 141*7f8f2456SAndreas Gohr case 'i4': 142*7f8f2456SAndreas Gohr $return[] = 42; 143*7f8f2456SAndreas Gohr break; 144*7f8f2456SAndreas Gohr case 'double': 145*7f8f2456SAndreas Gohr $return[] = 3.1415; 146*7f8f2456SAndreas Gohr break; 147*7f8f2456SAndreas Gohr case 'dateTime.iso8601': 148*7f8f2456SAndreas Gohr $return[] = new Date(time()); 149*7f8f2456SAndreas Gohr break; 150*7f8f2456SAndreas Gohr case 'boolean': 151*7f8f2456SAndreas Gohr $return[] = true; 152*7f8f2456SAndreas Gohr break; 153*7f8f2456SAndreas Gohr case 'base64': 154*7f8f2456SAndreas Gohr $return[] = new Base64('base64'); 155*7f8f2456SAndreas Gohr break; 156*7f8f2456SAndreas Gohr case 'array': 157*7f8f2456SAndreas Gohr $return[] = ['array']; 158*7f8f2456SAndreas Gohr break; 159*7f8f2456SAndreas Gohr case 'struct': 160*7f8f2456SAndreas Gohr $return[] = ['struct' => 'struct']; 161*7f8f2456SAndreas Gohr break; 162*7f8f2456SAndreas Gohr } 163*7f8f2456SAndreas Gohr } 164*7f8f2456SAndreas Gohr return $return; 165*7f8f2456SAndreas Gohr } 166*7f8f2456SAndreas Gohr 167*7f8f2456SAndreas Gohr public function methodHelp($method) 168*7f8f2456SAndreas Gohr { 169*7f8f2456SAndreas Gohr return $this->help[$method]; 170*7f8f2456SAndreas Gohr } 171*7f8f2456SAndreas Gohr} 172