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