Server.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. <?php
  2. // by Edd Dumbill (C) 1999,2000
  3. // <edd@usefulinc.com>
  4. // $Id: Server.php,v 1.2 2002/02/28 10:59:30 ssb Exp $
  5. // License is granted to use or modify this software ("XML-RPC for PHP")
  6. // for commercial or non-commercial use provided the copyright of the author
  7. // is preserved in any distributed or derivative work.
  8. // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
  9. // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  10. // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  11. // IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  12. // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  13. // NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  14. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  15. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  16. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  17. // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  18. // Adapted to PEAR standards by Stig Sæther Bakken <stig@php.net>
  19. // XML RPC Server class
  20. // requires: xmlrpc.inc
  21. require_once "XML/RPC.php";
  22. // listMethods: either a string, or nothing
  23. $GLOBALS['XML_RPC_Server_listMethods_sig']=
  24. array(array($GLOBALS['XML_RPC_Array'], $GLOBALS['XML_RPC_String']),
  25. array($GLOBALS['XML_RPC_Array']));
  26. $GLOBALS['XML_RPC_Server_listMethods_doc']=
  27. 'This method lists all the methods that the XML-RPC server knows how to dispatch';
  28. function XML_RPC_Server_listMethods($server, $m)
  29. {
  30. global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap;
  31. $v=new XML_RPC_Value();
  32. $dmap=$server->dmap;
  33. $outAr=array();
  34. for(reset($dmap); list($key, $val)=each($dmap); ) {
  35. $outAr[]=new XML_RPC_Value($key, "string");
  36. }
  37. $dmap=$XML_RPC_Server_dmap;
  38. for(reset($dmap); list($key, $val)=each($dmap); ) {
  39. $outAr[]=new XML_RPC_Value($key, "string");
  40. }
  41. $v->addArray($outAr);
  42. return new XML_RPC_Response($v);
  43. }
  44. $GLOBALS['XML_RPC_Server_methodSignature_sig']=
  45. array(array($GLOBALS['XML_RPC_Array'], $GLOBALS['XML_RPC_String']));
  46. $GLOBALS['XML_RPC_Server_methodSignature_doc']=
  47. 'Returns an array of known signatures (an array of arrays) for the method name passed. If no signatures are known, returns a none-array (test for type != array to detect missing signature)';
  48. function XML_RPC_Server_methodSignature($server, $m)
  49. {
  50. global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap;
  51. $methName=$m->getParam(0);
  52. $methName=$methName->scalarval();
  53. if (ereg("^system\.", $methName)) {
  54. $dmap=$XML_RPC_Server_dmap; $sysCall=1;
  55. } else {
  56. $dmap=$server->dmap; $sysCall=0;
  57. }
  58. // print "<!-- ${methName} -->\n";
  59. if (isset($dmap[$methName])) {
  60. if ($dmap[$methName]["signature"]) {
  61. $sigs=array();
  62. $thesigs=$dmap[$methName]["signature"];
  63. for($i=0; $i<sizeof($thesigs); $i++) {
  64. $cursig=array();
  65. $inSig=$thesigs[$i];
  66. for($j=0; $j<sizeof($inSig); $j++) {
  67. $cursig[]=new XML_RPC_Value($inSig[$j], "string");
  68. }
  69. $sigs[]=new XML_RPC_Value($cursig, "array");
  70. }
  71. $r=new XML_RPC_Response(new XML_RPC_Value($sigs, "array"));
  72. } else {
  73. $r=new XML_RPC_Response(new XML_RPC_Value("undef", "string"));
  74. }
  75. } else {
  76. $r=new XML_RPC_Response(0,
  77. $XML_RPC_err["introspect_unknown"],
  78. $XML_RPC_str["introspect_unknown"]);
  79. }
  80. return $r;
  81. }
  82. $GLOBALS['XML_RPC_Server_methodHelp_sig']=
  83. array(array($GLOBALS['XML_RPC_String'], $GLOBALS['XML_RPC_String']));
  84. $GLOBALS['XML_RPC_Server_methodHelp_doc']=
  85. 'Returns help text if defined for the method passed, otherwise returns an empty string';
  86. function XML_RPC_Server_methodHelp($server, $m)
  87. {
  88. global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap;
  89. $methName=$m->getParam(0);
  90. $methName=$methName->scalarval();
  91. if (ereg("^system\.", $methName)) {
  92. $dmap=$XML_RPC_Server_dmap; $sysCall=1;
  93. } else {
  94. $dmap=$server->dmap; $sysCall=0;
  95. }
  96. // print "<!-- ${methName} -->\n";
  97. if (isset($dmap[$methName])) {
  98. if ($dmap[$methName]["docstring"]) {
  99. $r=new XML_RPC_Response(new XML_RPC_Value($dmap[$methName]["docstring"]),
  100. "string");
  101. } else {
  102. $r=new XML_RPC_Response(new XML_RPC_Value("", "string"));
  103. }
  104. } else {
  105. $r=new XML_RPC_Response(0,
  106. $XML_RPC_err["introspect_unknown"],
  107. $XML_RPC_str["introspect_unknown"]);
  108. }
  109. return $r;
  110. }
  111. $GLOBALS['XML_RPC_Server_dmap']=array(
  112. "system.listMethods" =>
  113. array("function" => "XML_RPC_Server_listMethods",
  114. "signature" => $GLOBALS['XML_RPC_Server_listMethods_sig'],
  115. "docstring" => $GLOBALS['XML_RPC_Server_listMethods_doc']),
  116. "system.methodHelp" =>
  117. array("function" => "XML_RPC_Server_methodHelp",
  118. "signature" => $GLOBALS['XML_RPC_Server_methodHelp_sig'],
  119. "docstring" => $GLOBALS['XML_RPC_Server_methodHelp_doc']),
  120. "system.methodSignature" =>
  121. array("function" => "XML_RPC_Server_methodSignature",
  122. "signature" => $GLOBALS['XML_RPC_Server_methodSignature_sig'],
  123. "docstring" => $GLOBALS['XML_RPC_Server_methodSignature_doc'])
  124. );
  125. $GLOBALS['XML_RPC_Server_debuginfo']="";
  126. function XML_RPC_Server_debugmsg($m)
  127. {
  128. global $XML_RPC_Server_debuginfo;
  129. $XML_RPC_Server_debuginfo=$XML_RPC_Server_debuginfo . $m . "\n";
  130. }
  131. class XML_RPC_Server
  132. {
  133. var $dmap=array();
  134. function XML_RPC_Server($dispMap, $serviceNow=1)
  135. {
  136. global $HTTP_RAW_POST_DATA;
  137. // dispMap is a despatch array of methods
  138. // mapped to function names and signatures
  139. // if a method
  140. // doesn't appear in the map then an unknown
  141. // method error is generated
  142. $this->dmap=$dispMap;
  143. if ($serviceNow) {
  144. $this->service();
  145. }
  146. }
  147. function serializeDebug()
  148. {
  149. global $XML_RPC_Server_debuginfo;
  150. if ($XML_RPC_Server_debuginfo!="")
  151. return "<!-- DEBUG INFO:\n\n" .
  152. $XML_RPC_Server_debuginfo . "\n-->\n";
  153. else
  154. return "";
  155. }
  156. function service()
  157. {
  158. $r=$this->parseRequest();
  159. $payload="<?xml version=\"1.0\"?>\n" .
  160. $this->serializeDebug() .
  161. $r->serialize();
  162. Header("Content-type: text/xml\nContent-length: " .
  163. strlen($payload));
  164. print $payload;
  165. }
  166. function verifySignature($in, $sig)
  167. {
  168. for($i=0; $i<sizeof($sig); $i++) {
  169. // check each possible signature in turn
  170. $cursig=$sig[$i];
  171. if (sizeof($cursig)==$in->getNumParams()+1) {
  172. $itsOK=1;
  173. for($n=0; $n<$in->getNumParams(); $n++) {
  174. $p=$in->getParam($n);
  175. // print "<!-- $p -->\n";
  176. if ($p->kindOf() == "scalar") {
  177. $pt=$p->scalartyp();
  178. } else {
  179. $pt=$p->kindOf();
  180. }
  181. // $n+1 as first type of sig is return type
  182. if ($pt != $cursig[$n+1]) {
  183. $itsOK=0;
  184. $pno=$n+1; $wanted=$cursig[$n+1]; $got=$pt;
  185. break;
  186. }
  187. }
  188. if ($itsOK)
  189. return array(1);
  190. }
  191. }
  192. return array(0, "Wanted ${wanted}, got ${got} at param ${pno})");
  193. }
  194. function parseRequest($data="")
  195. {
  196. global $XML_RPC_xh,$HTTP_RAW_POST_DATA;
  197. global $XML_RPC_err, $XML_RPC_str, $XML_RPC_errxml,
  198. $XML_RPC_defencoding, $XML_RPC_Server_dmap;
  199. if ($data=="") {
  200. $data=$HTTP_RAW_POST_DATA;
  201. }
  202. $parser = xml_parser_create($XML_RPC_defencoding);
  203. $XML_RPC_xh[$parser]=array();
  204. $XML_RPC_xh[$parser]['st']="";
  205. $XML_RPC_xh[$parser]['cm']=0;
  206. $XML_RPC_xh[$parser]['isf']=0;
  207. $XML_RPC_xh[$parser]['params']=array();
  208. $XML_RPC_xh[$parser]['method']="";
  209. $plist = '';
  210. // decompose incoming XML into request structure
  211. xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true);
  212. xml_set_element_handler($parser, "XML_RPC_se", "XML_RPC_ee");
  213. xml_set_character_data_handler($parser, "XML_RPC_cd");
  214. xml_set_default_handler($parser, "XML_RPC_dh");
  215. if (!xml_parse($parser, $data, 1)) {
  216. // return XML error as a faultCode
  217. $r=new XML_RPC_Response(0,
  218. $XML_RPC_errxml+xml_get_error_code($parser),
  219. sprintf("XML error: %s at line %d",
  220. xml_error_string(xml_get_error_code($parser)),
  221. xml_get_current_line_number($parser)));
  222. xml_parser_free($parser);
  223. } else {
  224. xml_parser_free($parser);
  225. $m=new XML_RPC_Message($XML_RPC_xh[$parser]['method']);
  226. // now add parameters in
  227. for($i=0; $i<sizeof($XML_RPC_xh[$parser]['params']); $i++) {
  228. // print "<!-- " . $XML_RPC_xh[$parser]['params'][$i]. "-->\n";
  229. $plist.="$i - " . $XML_RPC_xh[$parser]['params'][$i]. " \n";
  230. eval('$m->addParam(' . $XML_RPC_xh[$parser]['params'][$i]. ");");
  231. }
  232. XML_RPC_Server_debugmsg($plist);
  233. // now to deal with the method
  234. $methName=$XML_RPC_xh[$parser]['method'];
  235. if (ereg("^system\.", $methName)) {
  236. $dmap=$XML_RPC_Server_dmap; $sysCall=1;
  237. } else {
  238. $dmap=$this->dmap; $sysCall=0;
  239. }
  240. if (isset($dmap[$methName]['function'])) {
  241. // dispatch if exists
  242. if (isset($dmap[$methName]['signature'])) {
  243. $sr=$this->verifySignature($m,
  244. $dmap[$methName]['signature'] );
  245. }
  246. if ( (!isset($dmap[$methName]['signature'])) || $sr[0]) {
  247. // if no signature or correct signature
  248. if ($sysCall) {
  249. eval('$r=' . $dmap[$methName]['function'] .
  250. '($this, $m);');
  251. } else {
  252. eval('$r=' . $dmap[$methName]['function'] .
  253. '($m);');
  254. }
  255. } else {
  256. $r=new XML_RPC_Response(0,
  257. $XML_RPC_err["incorrect_params"],
  258. $XML_RPC_str["incorrect_params"].": ". $sr[1]);
  259. }
  260. } else {
  261. // else prepare error response
  262. $r=new XML_RPC_Response(0,
  263. $XML_RPC_err["unknown_method"],
  264. $XML_RPC_str["unknown_method"]);
  265. }
  266. }
  267. return $r;
  268. }
  269. function echoInput() {
  270. global $HTTP_RAW_POST_DATA;
  271. // a debugging routine: just echos back the input
  272. // packet as a string value
  273. $r=new XML_RPC_Response;
  274. $r->xv=new XML_RPC_Value( "'Aha said I: '" . $HTTP_RAW_POST_DATA, "string");
  275. print $r->serialize();
  276. }
  277. }
  278. ?>