3 * @author Gaetano Giunta
4 * @copyright (C) 2005-2014 G. Giunta
5 * @license code licensed under the BSD License: http://phpxmlrpc.sourceforge.net/license.txt
7 * @todo switch params for http compression from 0,1,2 to values to be used directly
8 * @todo use ob_start to catch debug info and echo it AFTER method call results?
9 * @todo be smarter in creating client stub for proxy/auth cases: only set appropriate property of client obj
13 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
14 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
15 <html xmlns="http://www.w3.org/1999/xhtml">
17 <title>XMLRPC Debugger</title>
18 <meta name="robots" content="index,nofollow" />
19 <style type="text/css">
21 body {border-top: 1px solid gray; padding: 1em; font-family: Verdana, Arial, Helvetica; font-size: 8pt;}
22 h3 {font-size: 9.5pt;}
24 .dbginfo {padding: 1em; background-color: #EEEEEE; border: 1px dashed silver; font-family: monospace;}
25 #response {padding: 1em; margin-top: 1em; background-color: #DDDDDD; border: 1px solid gray; white-space: pre; font-family: monospace;}
26 table {padding: 2px; margin-top: 1em;}
27 th {background-color: navy; color: white; padding: 0.5em;}
28 td {padding: 0.5em; font-family: monospace;}
30 .oddrow {background-color: #EEEEEE;}
31 .evidence {color: blue;}
32 #phpcode { background-color: #EEEEEE; padding: 1em; margin-top: 1em;}
39 include(dirname(__FILE__).'/common.php');
43 // make sure the script waits long enough for the call to complete...
45 set_time_limit($timeout+10);
47 include('xmlrpc.inc');
50 @include('jsonrpc.inc');
51 if (!class_exists('jsonrpc_client'))
53 die('Error: to debug the jsonrpc protocol the jsonrpc.inc file is needed');
55 $clientclass = 'jsonrpc_client';
56 $msgclass = 'jsonrpcmsg';
57 $protoname = 'JSONRPC';
61 $clientclass = 'xmlrpc_client';
62 $msgclass = 'xmlrpcmsg';
63 $protoname = 'XMLRPC';
68 $client = new $clientclass($path, $host, $port);
69 $server = "$host:$port$path";
71 $client = new $clientclass($path, $host);
72 $server = "$host$path";
76 $server = 'https://'.$server;
80 $server = 'http://'.$server;
83 $pproxy = explode(':', $proxy);
84 if (count($pproxy) > 1)
88 $client->setProxy($pproxy[0], $pport, $proxyuser, $proxypwd);
93 $client->setSSLVerifyPeer($verifypeer);
94 $client->setSSLVerifyHost($verifyhost);
97 $client->setCaCertificate($cainfo);
99 $httpprotocol = 'https';
101 else if ($protocol == 1)
102 $httpprotocol = 'http11';
104 $httpprotocol = 'http';
107 $client->setCredentials($username, $password, $authtype);
109 $client->setDebug($debug);
111 switch ($requestcompression) {
113 $client->request_compression = '';
116 $client->request_compression = 'gzip';
119 $client->request_compression = 'deflate';
123 switch ($responsecompression) {
125 $client->accepted_compression = '';
128 $client->accepted_compression = array('gzip');
131 $client->accepted_compression = array('deflate');
134 $client->accepted_compression = array('gzip', 'deflate');
138 $cookies = explode(',', $clientcookies);
139 foreach ($cookies as $cookie)
141 if (strpos($cookie, '='))
143 $cookie = explode('=', $cookie);
144 $client->setCookie(trim($cookie[0]), trim(@$cookie[1]));
152 @include('xmlrpc_wrappers.inc');
153 if (!function_exists('build_remote_method_wrapper_code'))
155 die('Error: to enable creation of method stubs the xmlrpc_wrappers.inc file is needed');
157 // fall thru intentionally
160 $msg[0] = new $msgclass('system.methodHelp', null, $id);
161 $msg[0]->addparam(new xmlrpcval($method));
162 $msg[1] = new $msgclass('system.methodSignature', null, $id+1);
163 $msg[1]->addparam(new xmlrpcval($method));
164 $actionname = 'Description of method "'.$method.'"';
167 $msg[0] = new $msgclass('system.listMethods', null, $id);
168 $actionname = 'List of available methods';
171 if (!payload_is_safe($payload))
172 die("Tsk tsk tsk, please stop it or I will have to call in the cops!");
173 $msg[0] = new $msgclass($method, null, $id);
174 // hack! build xml payload by hand
177 $msg[0]->payload = "{\n".
178 '"method": "' . $method . "\",\n\"params\": [" .
181 // fix: if user gave an empty string, use NULL, or we'll break json syntax
184 $msg[0]->payload .= "null\n}";
188 if (is_numeric($id) || $id == 'false' || $id == 'true' || $id == 'null')
190 $msg[0]->payload .= "$id\n}";
194 $msg[0]->payload .= "\"$id\"\n}";
199 $msg[0]->payload = $msg[0]->xml_header($inputcharset) .
200 '<methodName>' . $method . "</methodName>\n<params>" .
202 "</params>\n" . $msg[0]->xml_footer();
203 $actionname = 'Execution of method '.$method;
205 default: // give a warning
206 $actionname = '[ERROR: unknown action] "'.$action.'"';
209 // Before calling execute, echo out brief description of action taken + date and time ???
210 // this gives good user feedback for long-running methods...
211 echo '<h2>'.htmlspecialchars($actionname, ENT_COMPAT, $inputcharset).' on server '.htmlspecialchars($server, ENT_COMPAT, $inputcharset)." ...</h2>\n";
217 echo '<div class="dbginfo"><h2>Debug info:</h2>'; /// @todo use ob_start instead
219 $mtime = explode(' ',microtime());
220 $time = (float)$mtime[0] + (float)$mtime[1];
221 foreach ($msg as $message)
223 // catch errors: for older xmlrpc libs, send does not return by ref
224 @$response =& $client->send($message, $timeout, $httpprotocol);
226 if (!$response || $response->faultCode())
229 $mtime = explode(' ',microtime());
230 $time = (float)$mtime[0] + (float)$mtime[1] - $time;
237 if ($response->faultCode())
239 // call failed! echo out error msg!
240 //echo '<h2>'.htmlspecialchars($actionname, ENT_COMPAT, $inputcharset).' on server '.htmlspecialchars($server, ENT_COMPAT, $inputcharset).'</h2>';
241 echo "<h3>$protoname call FAILED!</h3>\n";
242 echo "<p>Fault code: [" . htmlspecialchars($response->faultCode(), ENT_COMPAT, $GLOBALS['xmlrpc_internalencoding']) .
243 "] Reason: '" . htmlspecialchars($response->faultString(), ENT_COMPAT, $GLOBALS['xmlrpc_internalencoding']) . "'</p>\n";
244 echo (strftime("%d/%b/%Y:%H:%M:%S\n"));
248 // call succeeded: parse results
249 //echo '<h2>'.htmlspecialchars($actionname, ENT_COMPAT, $inputcharset).' on server '.htmlspecialchars($server, ENT_COMPAT, $inputcharset).'</h2>';
250 printf ("<h3>%s call(s) OK (%.2f secs.)</h3>\n", $protoname, $time);
251 echo (strftime("%d/%b/%Y:%H:%M:%S\n"));
257 $v = $response->value();
258 if ($v->kindOf()=="array")
260 $max = $v->arraysize();
261 echo "<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n";
262 echo "<thead>\n<tr><th>Method</th><th>Description</th></tr>\n</thead>\n<tbody>\n";
263 for($i=0; $i < $max; $i++)
265 $rec = $v->arraymem($i);
266 if ($i%2) $class=' class="oddrow"'; else $class = ' class="evenrow"';
267 echo ("<tr><td$class>".htmlspecialchars($rec->scalarval(), ENT_COMPAT, $GLOBALS['xmlrpc_internalencoding'])."</td><td$class><form action=\"controller.php\" method=\"get\" target=\"frmcontroller\">".
268 "<input type=\"hidden\" name=\"host\" value=\"".htmlspecialchars($host, ENT_COMPAT, $inputcharset)."\" />".
269 "<input type=\"hidden\" name=\"port\" value=\"".htmlspecialchars($port, ENT_COMPAT, $inputcharset)."\" />".
270 "<input type=\"hidden\" name=\"path\" value=\"".htmlspecialchars($path, ENT_COMPAT, $inputcharset)."\" />".
271 "<input type=\"hidden\" name=\"id\" value=\"".htmlspecialchars($id, ENT_COMPAT, $inputcharset)."\" />".
272 "<input type=\"hidden\" name=\"debug\" value=\"$debug\" />".
273 "<input type=\"hidden\" name=\"username\" value=\"".htmlspecialchars($username, ENT_COMPAT, $inputcharset)."\" />".
274 "<input type=\"hidden\" name=\"password\" value=\"".htmlspecialchars($password, ENT_COMPAT, $inputcharset)."\" />".
275 "<input type=\"hidden\" name=\"authtype\" value=\"$authtype\" />".
276 "<input type=\"hidden\" name=\"verifyhost\" value=\"$verifyhost\" />".
277 "<input type=\"hidden\" name=\"verifypeer\" value=\"$verifypeer\" />".
278 "<input type=\"hidden\" name=\"cainfo\" value=\"".htmlspecialchars($cainfo, ENT_COMPAT, $inputcharset)."\" />".
279 "<input type=\"hidden\" name=\"proxy\" value=\"".htmlspecialchars($proxy, ENT_COMPAT, $inputcharset)."\" />".
280 "<input type=\"hidden\" name=\"proxyuser\" value=\"".htmlspecialchars($proxyuser, ENT_COMPAT, $inputcharset)."\" />".
281 "<input type=\"hidden\" name=\"proxypwd\" value=\"".htmlspecialchars($proxypwd, ENT_COMPAT, $inputcharset)."\" />".
282 "<input type=\"hidden\" name=\"responsecompression\" value=\"$responsecompression\" />".
283 "<input type=\"hidden\" name=\"requestcompression\" value=\"$requestcompression\" />".
284 "<input type=\"hidden\" name=\"clientcookies\" value=\"".htmlspecialchars($clientcookies, ENT_COMPAT, $inputcharset)."\" />".
285 "<input type=\"hidden\" name=\"protocol\" value=\"$protocol\" />".
286 "<input type=\"hidden\" name=\"timeout\" value=\"".htmlspecialchars($timeout, ENT_COMPAT, $inputcharset)."\" />".
287 "<input type=\"hidden\" name=\"method\" value=\"".$rec->scalarval()."\" />".
288 "<input type=\"hidden\" name=\"wstype\" value=\"$wstype\" />".
289 "<input type=\"hidden\" name=\"action\" value=\"describe\" />".
290 "<input type=\"hidden\" name=\"run\" value=\"now\" />".
291 "<input type=\"submit\" value=\"Describe\" /></form></td>");
294 // generate lo scheletro per il method payload per eventuali test
295 //$methodpayload="<methodCall>\n<methodName>".$rec->scalarval()."</methodName>\n<params>\n<param><value></value></param>\n</params>\n</methodCall>";
297 /*echo ("<form action=\"{$_SERVER['PHP_SELF']}\" method=\"get\"><td>".
298 "<input type=\"hidden\" name=\"host\" value=\"$host\" />".
299 "<input type=\"hidden\" name=\"port\" value=\"$port\" />".
300 "<input type=\"hidden\" name=\"path\" value=\"$path\" />".
301 "<input type=\"hidden\" name=\"method\" value=\"".$rec->scalarval()."\" />".
302 "<input type=\"hidden\" name=\"methodpayload\" value=\"$payload\" />".
303 "<input type=\"hidden\" name=\"action\" value=\"execute\" />".
304 "<input type=\"submit\" value=\"Test\" /></td></form>");*/
307 echo "</tbody>\n</table>";
313 $r1 = $resp[0]->value();
314 $r2 = $resp[1]->value();
316 echo "<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n";
317 echo "<thead>\n<tr><th>Method</th><th>".htmlspecialchars($method, ENT_COMPAT, $inputcharset)."</th><th> </th><th> </th></tr>\n</thead>\n<tbody>\n";
318 $desc = htmlspecialchars($r1->scalarval(), ENT_COMPAT, $GLOBALS['xmlrpc_internalencoding']);
321 echo "<tr><td class=\"evenrow\">Description</td><td colspan=\"3\" class=\"evenrow\">$desc</td></tr>\n";
324 if ($r2->kindOf()!="array")
325 echo "<tr><td class=\"oddrow\">Signature</td><td class=\"oddrow\">Unknown</td><td class=\"oddrow\"> </td></tr>\n";
328 for($i=0; $i < $r2->arraysize(); $i++)
330 if ($i+1%2) $class=' class="oddrow"'; else $class = ' class="evenrow"';
331 echo "<tr><td$class>Signature ".($i+1)."</td><td$class>";
332 $x = $r2->arraymem($i);
333 if ($x->kindOf()=="array")
335 $ret = $x->arraymem(0);
336 echo "<code>OUT: " . htmlspecialchars($ret->scalarval(), ENT_COMPAT, $GLOBALS['xmlrpc_internalencoding']) . "<br />IN: (";
337 if ($x->arraysize() > 1)
339 for($k = 1; $k < $x->arraysize(); $k++)
341 $y = $x->arraymem($k);
342 echo $y->scalarval();
345 $payload = $payload . '<param><value><'.htmlspecialchars($y->scalarval(), ENT_COMPAT, $GLOBALS['xmlrpc_internalencoding']).'></'.htmlspecialchars($y->scalarval(), ENT_COMPAT, $GLOBALS['xmlrpc_internalencoding'])."></value></param>\n";
347 $alt_payload .= $y->scalarval();
348 if ($k < $x->arraysize()-1)
362 //bottone per testare questo metodo
363 //$payload="<methodCall>\n<methodName>$method</methodName>\n<params>\n$payload</params>\n</methodCall>";
364 echo "<td$class><form action=\"controller.php\" target=\"frmcontroller\" method=\"get\">".
365 "<input type=\"hidden\" name=\"host\" value=\"".htmlspecialchars($host, ENT_COMPAT, $inputcharset)."\" />".
366 "<input type=\"hidden\" name=\"port\" value=\"".htmlspecialchars($port, ENT_COMPAT, $inputcharset)."\" />".
367 "<input type=\"hidden\" name=\"path\" value=\"".htmlspecialchars($path, ENT_COMPAT, $inputcharset)."\" />".
368 "<input type=\"hidden\" name=\"id\" value=\"".htmlspecialchars($id, ENT_COMPAT, $inputcharset)."\" />".
369 "<input type=\"hidden\" name=\"debug\" value=\"$debug\" />".
370 "<input type=\"hidden\" name=\"username\" value=\"".htmlspecialchars($username, ENT_COMPAT, $inputcharset)."\" />".
371 "<input type=\"hidden\" name=\"password\" value=\"".htmlspecialchars($password, ENT_COMPAT, $inputcharset)."\" />".
372 "<input type=\"hidden\" name=\"authtype\" value=\"$authtype\" />".
373 "<input type=\"hidden\" name=\"verifyhost\" value=\"$verifyhost\" />".
374 "<input type=\"hidden\" name=\"verifypeer\" value=\"$verifypeer\" />".
375 "<input type=\"hidden\" name=\"cainfo\" value=\"".htmlspecialchars($cainfo, ENT_COMPAT, $inputcharset)."\" />".
376 "<input type=\"hidden\" name=\"proxy\" value=\"".htmlspecialchars($proxy, ENT_COMPAT, $inputcharset)."\" />".
377 "<input type=\"hidden\" name=\"proxyuser\" value=\"".htmlspecialchars($proxyuser, ENT_COMPAT, $inputcharset)."\" />".
378 "<input type=\"hidden\" name=\"proxypwd\" value=\"".htmlspecialchars($proxypwd, ENT_COMPAT, $inputcharset)."\" />".
379 "<input type=\"hidden\" name=\"responsecompression\" value=\"$responsecompression\" />".
380 "<input type=\"hidden\" name=\"requestcompression\" value=\"$requestcompression\" />".
381 "<input type=\"hidden\" name=\"clientcookies\" value=\"".htmlspecialchars($clientcookies, ENT_COMPAT, $inputcharset)."\" />".
382 "<input type=\"hidden\" name=\"protocol\" value=\"$protocol\" />".
383 "<input type=\"hidden\" name=\"timeout\" value=\"".htmlspecialchars($timeout, ENT_COMPAT, $inputcharset)."\" />".
384 "<input type=\"hidden\" name=\"method\" value=\"".htmlspecialchars($method, ENT_COMPAT, $inputcharset)."\" />".
385 "<input type=\"hidden\" name=\"methodpayload\" value=\"".htmlspecialchars($payload, ENT_COMPAT, $inputcharset)."\" />".
386 "<input type=\"hidden\" name=\"altmethodpayload\" value=\"".htmlspecialchars($alt_payload, ENT_COMPAT, $inputcharset)."\" />".
387 "<input type=\"hidden\" name=\"wstype\" value=\"$wstype\" />".
388 "<input type=\"hidden\" name=\"action\" value=\"execute\" />";
390 echo "<input type=\"submit\" value=\"Load method synopsis\" />";
391 echo "</form></td>\n";
393 echo "<td$class><form action=\"controller.php\" target=\"frmcontroller\" method=\"get\">".
394 "<input type=\"hidden\" name=\"host\" value=\"".htmlspecialchars($host, ENT_COMPAT, $inputcharset)."\" />".
395 "<input type=\"hidden\" name=\"port\" value=\"".htmlspecialchars($port, ENT_COMPAT, $inputcharset)."\" />".
396 "<input type=\"hidden\" name=\"path\" value=\"".htmlspecialchars($path, ENT_COMPAT, $inputcharset)."\" />".
397 "<input type=\"hidden\" name=\"id\" value=\"".htmlspecialchars($id, ENT_COMPAT, $inputcharset)."\" />".
398 "<input type=\"hidden\" name=\"debug\" value=\"$debug\" />".
399 "<input type=\"hidden\" name=\"username\" value=\"".htmlspecialchars($username, ENT_COMPAT, $inputcharset)."\" />".
400 "<input type=\"hidden\" name=\"password\" value=\"".htmlspecialchars($password, ENT_COMPAT, $inputcharset)."\" />".
401 "<input type=\"hidden\" name=\"authtype\" value=\"$authtype\" />".
402 "<input type=\"hidden\" name=\"verifyhost\" value=\"$verifyhost\" />".
403 "<input type=\"hidden\" name=\"verifypeer\" value=\"$verifypeer\" />".
404 "<input type=\"hidden\" name=\"cainfo\" value=\"".htmlspecialchars($cainfo, ENT_COMPAT, $inputcharset)."\" />".
405 "<input type=\"hidden\" name=\"proxy\" value=\"".htmlspecialchars($proxy, ENT_COMPAT, $inputcharset)."\" />".
406 "<input type=\"hidden\" name=\"proxyuser\" value=\"".htmlspecialchars($proxyuser, ENT_COMPAT, $inputcharset)."\" />".
407 "<input type=\"hidden\" name=\"proxypwd\" value=\"".htmlspecialchars($proxypwd, ENT_COMPAT, $inputcharset)."\" />".
408 "<input type=\"hidden\" name=\"responsecompression\" value=\"$responsecompression\" />".
409 "<input type=\"hidden\" name=\"requestcompression\" value=\"$requestcompression\" />".
410 "<input type=\"hidden\" name=\"clientcookies\" value=\"".htmlspecialchars($clientcookies, ENT_COMPAT, $inputcharset)."\" />".
411 "<input type=\"hidden\" name=\"protocol\" value=\"$protocol\" />".
412 "<input type=\"hidden\" name=\"timeout\" value=\"".htmlspecialchars($timeout, ENT_COMPAT, $inputcharset)."\" />".
413 "<input type=\"hidden\" name=\"method\" value=\"".htmlspecialchars($method, ENT_COMPAT, $inputcharset)."\" />".
414 "<input type=\"hidden\" name=\"methodsig\" value=\"".$i."\" />".
415 "<input type=\"hidden\" name=\"methodpayload\" value=\"".htmlspecialchars($payload, ENT_COMPAT, $inputcharset)."\" />".
416 "<input type=\"hidden\" name=\"altmethodpayload\" value=\"".htmlspecialchars($alt_payload, ENT_COMPAT, $inputcharset)."\" />".
417 "<input type=\"hidden\" name=\"wstype\" value=\"$wstype\" />".
418 "<input type=\"hidden\" name=\"run\" value=\"now\" />".
419 "<input type=\"hidden\" name=\"action\" value=\"wrap\" />".
420 "<input type=\"submit\" value=\"Generate method call stub code\" />";
421 echo "</form></td></tr>\n";
425 echo "</tbody>\n</table>";
430 $r1 = $resp[0]->value();
431 $r2 = $resp[1]->value();
432 if ($r2->kindOf()!="array" || $r2->arraysize() <= $methodsig)
433 echo "Error: signature unknown\n";
436 $mdesc = $r1->scalarval();
437 $msig = php_xmlrpc_decode($r2);
438 $msig = $msig[$methodsig];
439 $proto = $protocol == 2 ? 'https' : $protocol == 1 ? 'http11' : '';
440 if ($proxy == '' && $username == '' && !$requestcompression && !$responsecompression &&
441 $clientcookies == '')
443 $opts = 0; // simple client copy in stub code
447 $opts = 1; // complete client copy in stub code
457 //$code = wrap_xmlrpc_method($client, $method, $methodsig, 0, $proto, '', $opts);
458 $code = build_remote_method_wrapper_code($client, $method, str_replace('.', '_', $prefix.'_'.$method), $msig, $mdesc, $timeout, $proto, $opts, $prefix);
461 echo "<div id=\"phpcode\">\n";
462 highlight_string("<?php\n".$code['docstring'].$code['source'].'?>');
467 // echo 'Error while building php code stub...';
473 echo '<div id="response"><h2>Response:</h2>'.htmlspecialchars($response->serialize(), ENT_COMPAT, $GLOBALS['xmlrpc_internalencoding']).'</div>';
476 default: // give a warning
478 } // if !$response->faultCode()
483 // no action taken yet: give some instructions on debugger usage
486 <h3>Instructions on usage of the debugger:</h3>
488 <li>Run a 'list available methods' action against desired server</li>
489 <li>If list of methods appears, click on 'describe method' for desired method</li>
490 <li>To run method: click on 'load method synopsis' for desired method. This will load a skeleton for method call parameters in the form above. Complete all xmlrpc values with appropriate data and click 'Execute'</li>
493 if (!extension_loaded('curl'))
495 echo "<p class=\"evidence\">You will need to enable the CURL extension to use the HTTPS and HTTP 1.1 transports</p>\n";
501 Server Address: phpxmlrpc.sourceforge.net<br/>
506 <p>all usernames and passwords entered on the above form will be written to the web server logs of this server. Use with care.</p>
510 <li>2015-04-19: fixed errors with LATIN-1 payloads and method names</li>
511 <li>2007-02-20: add visual editor for method payload; allow strings, bools as jsonrpc msg id</li>
512 <li>2006-06-26: support building php code stub for calling remote methods</li>
513 <li>2006-05-25: better support for long running queries; check for no-curl installs</li>
514 <li>2006-05-02: added support for JSON-RPC. Note that many interesting json-rpc features are not implemented yet, such as notifications or multicall.</li>
515 <li>2006-04-22: added option for setting custom CA certs to verify peer with in SSLmode</li>
516 <li>2006-03-05: added option for setting Basic/Digest/NTLM auth type</li>
517 <li>2006-01-18: added option echoing to screen xmlrpc request before sending it ('More' debug)</li>
518 <li>2005-10-01: added option for setting cookies to be sent to server</li>
519 <li>2005-08-07: added switches for compression of requests and responses and http 1.1</li>
520 <li>2005-06-27: fixed possible security breach in parsing malformed xml</li>
521 <li>2005-06-24: fixed error with calling methods having parameters...</li>