<body>
<h1>Agesort demo</h1>
<h2>Send an array of "name" => "age" pairs to the server that will send it back sorted.</h2>
-<h3>The source code demonstrates basic lib usage, including manual creation of xml-rpc arrays and structs</h3>
-<p>Have a look at <a href="getstatename.php">getstatename.php</a> for automatic encoding and decoding, and at
- <a href="../vardemo.php">vardemo.php</a> for more examples of manual encoding and decoding</p>
+<h3>The code demonstrates usage of automatic encoding/decoding of php variables into xmlrpc values such as arrays and structs</h3>
+<p>Have a look at <a href="../vardemo.php">vardemo.php</a> for more examples of manual encoding and decoding</p>
<p>You can see the source to this page here: <a href="agesort.php?showSource=1">agesort.php</a></p>
');
-$inAr = array("Dave" => 24, "Edd" => 45, "Joe" => 37, "Fred" => 27);
+use PhpXmlRpc\Client;
+use PhpXmlRpc\Encoder;
+use PhpXmlRpc\Request;
-output("This is the input data:<br/><pre>");
-foreach ($inAr as $key => $val) {
- output($key . ", " . $val . "\n");
-}
-output("</pre>");
+$inAr = array(
+ array('name' => 'Dave', 'age' => 24),
+ array('name' => 'Edd', 'age' => 45),
+ array('name' => 'Joe', 'age' => 37),
+ array('name' => 'Fred', 'age' => 27),
+);
-// Create parameters from the input array: an xmlrpc array of xmlrpc structs
-$p = array();
-foreach ($inAr as $key => $val) {
- $p[] = new PhpXmlRpc\Value(
- array(
- "name" => new PhpXmlRpc\Value($key),
- "age" => new PhpXmlRpc\Value($val, "int")
- ),
- "struct"
- );
+output('This is the input data:<br/><pre>');
+foreach ($inAr as $val) {
+ output($val['name'] . ", " . $val['age'] . "\n");
}
-$v = new PhpXmlRpc\Value($p, "array");
+output('</pre>');
+
+// Create xml-rpc parameters from the input array: an array of structs
+$encoder = new Encoder();
+$v = $encoder->encode($inAr);
output("Encoded into xmlrpc format it looks like this: <pre>\n" . htmlentities($v->serialize()) . "</pre>\n");
-// create client and message objects
-$req = new PhpXmlRpc\Request('examples.sortByAge', array($v));
-$client = new PhpXmlRpc\Client(XMLRPCSERVER);
+// create client and request objects
+$req = new Request('examples.sortByAge', array($v));
+$client = new Client(XMLRPCSERVER);
// set maximum debug level, to have the complete communication printed to screen
$client->setDebug(2);
// send request
-output("Now sending request (detailed debug info follows)");
+output('Now sending the request... (very detailed debug info follows. Scroll to the bottom of the page for results!)<hr/>');
$resp = $client->send($req);
+output('<hr/>');
// check response for errors, and take appropriate action
if (!$resp->faultCode()) {
- output("The server gave me these results:<pre>");
+ output('The server gave me these results:<pre>');
$value = $resp->value();
- foreach ($value as $struct) {
- $name = $struct["name"];
- $age = $struct["age"];
- output(htmlspecialchars($name->scalarval()) . ", " . htmlspecialchars($age->scalarval()) . "\n");
+ foreach ($encoder->decode($value) as $struct) {
+ // note: here we are trusting the server's response to have the expected format
+ output(htmlspecialchars($struct['name']) . ", " . htmlspecialchars($struct['age']) . "\n");
}
- output("<hr/>For nerds: I got this value back<br/><pre>" .
+ output('</pre><hr/>For nerds: I got this value back<br/><pre>' .
htmlentities($resp->serialize()) . "</pre><hr/>\n");
} else {
- output("An error occurred:<pre>");
- output("Code: " . htmlspecialchars($resp->faultCode()) .
+ output('An error occurred:<pre>');
+ output('Code: ' . htmlspecialchars($resp->faultCode()) .
"\nReason: '" . htmlspecialchars($resp->faultString()) . "'</pre><hr/>");
}
<body>
<h1>Getstatename demo</h1>
<h2>Send a U.S. state number to the server and get back the state name</h2>
-<h3>The code demonstrates usage of automatic encoding/decoding of php variables into xmlrpc values</h3>
+<h3>The source code demonstrates basic lib usage, including manual creation and decoding of of xml-rpc values</h3>
<p>You can see the source to this page here: <a href="getstatename.php?showSource=1">getstatename.php</a></p>
');
-if (isset($_POST["stateno"]) && $_POST["stateno"] != "") {
- $stateNo = (integer)$_POST["stateno"];
- $encoder = new PhpXmlRpc\Encoder();
- $req = new PhpXmlRpc\Request('examples.getStateName',
- array($encoder->encode($stateNo))
+use PhpXmlRpc\Client;
+use PhpXmlRpc\Request;
+use PhpXmlRpc\Value;
+
+$stateNo = "";
+
+if (isset($_POST['stateno']) && $_POST['stateno'] != "") {
+ $stateNo = (integer)$_POST['stateno'];
+ $method = 'examples.getStateName';
+ $arguments = array(
+ new Value($stateNo, Value::$xmlrpcInt),
);
- output("Sending the following request:<pre>\n\n" . htmlentities($req->serialize()) . "\n\n</pre>Debug info of server data follows...\n\n");
- $client = new PhpXmlRpc\Client(XMLRPCSERVER);
+ $req = new Request($method, $arguments);
+ output("Sending the following request:<pre>\n\n" . htmlentities($req->serialize()) .
+ "\n\n</pre>Debug info of server data follows...\n\n");
+ $client = new Client(XMLRPCSERVER);
$client->setDebug(1);
- $r = $client->send($req);
- if (!$r->faultCode()) {
- $v = $r->value();
- output("<br/>State number <b>" . $stateNo . "</b> is <b>"
- . htmlspecialchars($encoder->decode($v)) . "</b><br/><br/>");
+ $resp = $client->send($req);
+ if (!$resp->faultCode()) {
+ $val = $resp->value();
+ // NB: we are _assuming_ that the server did return a scalar xml-rpc value here.
+ // If the server is not trusted, we might check that via `$val->kindOf() == 'scalar'`
+ output('<br/>State number <b>' . $stateNo . '</b> is <b>'
+ . htmlspecialchars($val->scalarval()) . '</b><br/><br/>');
} else {
- output("An error occurred: ");
- output("Code: " . htmlspecialchars($r->faultCode())
- . " Reason: '" . htmlspecialchars($r->faultString()) . "'</pre><br/>");
+ output('An error occurred: ');
+ output('<pre>Code: ' . htmlspecialchars($resp->faultCode())
+ . " Reason: '" . htmlspecialchars($resp->faultString()) . "'</pre>");
}
-} else {
- $stateNo = "";
}
output("<form action=\"getstatename.php\" method=\"POST\">
-<input name=\"stateno\" value=\"" . $stateNo . "\">
+<input name=\"stateno\" value=\"$stateNo\">
<input type=\"submit\" value=\"go\" name=\"submit\">
</form>
<p>Enter a state number to query its name</p>");
<head><title>xmlrpc - Introspect demo</title></head>
<body>
<h1>Introspect demo</h1>
-<h2>Query server for available methods and their description</h2>
-<h3>The code demonstrates usage of multicall and introspection methods</h3>
+<h2>Query server for available methods, their description and their signatures</h2>
+<h3>The code demonstrates usage of multicall, introspection methods `system.listMethods` and co., and `$client->return_type`</h3>
<p>You can see the source to this page here: <a href="introspect.php?showSource=1">introspect.php</a></p>
');
+use PhpXmlRpc\Client;
+use PhpXmlRpc\Helper\XMLParser;
+use PhpXmlRpc\Request;
+
function display_error($r)
{
output("An error occurred: ");
output("Code: " . $r->faultCode() . " Reason: '" . $r->faultString() . "'<br/>");
}
-$client = new PhpXmlRpc\Client(XMLRPCSERVER);
+$client = new Client(XMLRPCSERVER);
+// tell the client we want back plain php values
+$client->return_type = XMLParser::RETURN_PHP;
// First off, let's retrieve the list of methods available on the remote server
output("<h3>methods available at http://" . $client->server . $client->path . "</h3>\n");
-$req = new PhpXmlRpc\Request('system.listMethods');
+$req = new Request('system.listMethods');
$resp = $client->send($req);
if ($resp->faultCode()) {
} else {
$v = $resp->value();
+ // check if the server supports 'system.multicall', and configure the client accordingly
+ $avoidMulticall = true;
+ foreach ($v as $methodName) {
+ if ($methodName == 'system.multicall') {
+ $avoidMulticall = false;
+ break;
+ }
+ }
+
+ $client->no_multicall = $avoidMulticall;
+
// Then, retrieve the signature and help text of each available method
foreach ($v as $methodName) {
- output("<h4>" . htmlspecialchars($methodName->scalarval()) . "</h4>\n");
- // build messages first, add params later
- $m1 = new PhpXmlRpc\Request('system.methodHelp');
- $m2 = new PhpXmlRpc\Request('system.methodSignature');
- $val = new PhpXmlRpc\Value($methodName->scalarval(), "string");
- $m1->addParam($val);
- $m2->addParam($val);
- // Send multiple requests in one http call.
- // If server does not support multicall, client will automatically fall back to 2 separate calls
- $ms = array($m1, $m2);
- $rs = $client->send($ms);
- if ($rs[0]->faultCode()) {
- display_error($rs[0]);
+ output("<h4>" . htmlspecialchars($methodName) . "</h4>\n");
+ // build requests first, add params later
+ $r1 = new PhpXmlRpc\Request('system.methodHelp');
+ $r2 = new PhpXmlRpc\Request('system.methodSignature');
+ $val = new PhpXmlRpc\Value($methodName, "string");
+ $r1->addParam($val);
+ $r2->addParam($val);
+ // Send multiple requests in one/many http calls.
+ $reqs = array($r1, $r2);
+ $resps = $client->send($reqs);
+ if ($resps[0]->faultCode()) {
+ display_error($resps[0]);
} else {
- $val = $rs[0]->value();
- $txt = $val->scalarval();
+ output("<h5>Documentation</h5><p>\n");
+ $txt = $resps[0]->value();
if ($txt != "") {
- output("<h4>Documentation</h4><p>{$txt}</p>\n");
+ // NB: we explicitly avoid escaping the received data because the spec says that html _can be_ in methodHelp.
+ // That is not a very good practice nevertheless!
+ output("<p>$txt</p>\n");
} else {
output("<p>No documentation available.</p>\n");
}
}
- if ($rs[1]->faultCode()) {
- display_error($rs[1]);
+ if ($resps[1]->faultCode()) {
+ display_error($resps[1]);
} else {
- output("<h4>Signature</h4><p>\n");
- // note: using PhpXmlRpc\Encoder::decode() here would lead to cleaner code
- $val = $rs[1]->value();
- if ($val->kindOf() == "array") {
- foreach ($val as $x) {
- $ret = $x[0];
- output("<code>" . htmlspecialchars($ret->scalarval()) . " "
- . htmlspecialchars($methodName->scalarval()) . "(");
- if ($x->count() > 1) {
- for ($k = 1; $k < $x->count(); $k++) {
- $y = $x[$k];
- output(htmlspecialchars($y->scalarval()));
- if ($k < $x->count() - 1) {
+ output("<h5>Signature(s)</h5><p>\n");
+ $sigs = $resps[1]->value();
+ if (is_array($sigs)) {
+ foreach ($sigs as $sn => $sig) {
+ // can we trust the server to be fully compliant with the spec?
+ if (!is_array($sig)) {
+ output("Signature $sn: unknown\n");
+ continue;
+ }
+ $ret = $sig[0];
+ output("<code>" . htmlspecialchars($ret) . " "
+ . htmlspecialchars($methodName) . "(");
+ if (count($sig) > 1) {
+ for ($k = 1; $k < count($sig); $k++) {
+ output(htmlspecialchars($sig[$k]));
+ if ($k < count($sig) - 1) {
output(", ");
}
}
+++ /dev/null
-<?php
-require_once __DIR__ . "/_prepend.php";
-
-output('<html lang="en">
-<head><title>xmlrpc - Mail demo</title></head>
-<body>
-<h1>Mail demo</h1>
-<p>This form enables you to send mail via an XML-RPC server.
- When you press <kbd>Send</kbd> this page will reload, showing you the XML-RPC request sent to the host server, the
- XML-RPC response received and the internal evaluation done by the PHP implementation.</p>
-<p>You can see the source to this page here: <a href="mail.php?showSource=1">mail.php</a><br/>
- And the source to a functionally identical mail-by-XML-RPC server in the file <a
- href="../server/server.php?showSource=1">server.php</a> included with the library (look for the "mail_send"
- method)</p>
-');
-
-if (isset($_POST["mailto"]) && $_POST["mailto"]) {
- $server = XMLRPCSERVER;
- $req = new PhpXmlRpc\Request('mail.send', array(
- new PhpXmlRpc\Value($_POST["mailto"]),
- new PhpXmlRpc\Value($_POST["mailsub"]),
- new PhpXmlRpc\Value($_POST["mailmsg"]),
- new PhpXmlRpc\Value($_POST["mailfrom"]),
- new PhpXmlRpc\Value($_POST["mailcc"]),
- new PhpXmlRpc\Value($_POST["mailbcc"]),
- new PhpXmlRpc\Value("text/plain")
- ));
-
- $client = new PhpXmlRpc\Client($server);
- $client->setDebug(2);
- $resp = $client->send($req);
- if (!$resp->faultCode()) {
- output("Mail sent OK<br/>\n");
- } else {
- output("<font color=\"red\">");
- output("Mail send failed<br/>\n");
- output("Fault: ");
- output("Code: " . htmlspecialchars($resp->faultCode()) .
- " Reason: '" . htmlspecialchars($resp->faultString()) . "'<br/>");
- output("</font><br/>");
- }
-}
-output('
-<form method="POST">
- From <input size="60" name="mailfrom" value=""/><br/>
- <hr/>
- To <input size="60" name="mailto" value=""/><br/>
- Cc <input size="60" name="mailcc" value=""/><br/>
- Bcc <input size="60" name="mailbcc" value=""/><br/>
- <hr/>
- Subject <input size="60" name="mailsub" value="A message from xmlrpc"/>
- <hr/>
- Body <textarea rows="7" cols="60" name="mailmsg">Your message here</textarea><br/>
- <input type="Submit" value="Send"/>
-</form>
-</body>
-</html>
-');
<p>You can see the source to this page here: <a href="proxy.php?showSource=1">proxy.php</a></p>
');
-class PhpXmlRpcProxy
+class XmlRpcProxy
{
protected $client;
protected $prefix;
+ protected $encoder;
protected $encodingOptions = array();
+ /**
+ * We rely on injecting a fully-formed Client, so that all the necessary http/debugging options can be set into it
+ * without the need for this class to reimplement support for that configuration.
+ */
public function __construct(PhpXmlRpc\Client $client, $prefix = 'examples.', $encodingOptions = array())
{
$this->client = $client;
$this->prefix = $prefix;
$this->encodingOptions = $encodingOptions;
+ $this->encoder = new PhpXmlRpc\Encoder();
}
/**
- * Translates any method call to an xml-rpc call.
+ * Translates any php method call to an xml-rpc call.
+ * Note that the server might expose methods which can not be called directly this way, because their name includes
+ * characters which are not allowed in a php method. That's why we implement as well method `call`
*
* @author Toth Istvan
*
* @param string $name remote function name. Will be prefixed
- * @param array $arguments
+ * @param array $arguments any php value will do. For xml-rpc base64 values, wrap them in a Value object
* @return mixed
*
* @throws Exception
*/
public function __call($name, $arguments)
{
- $encoder = new PhpXmlRpc\Encoder();
- $valueArray = array();
+ $arguments = array();
foreach ($arguments as $parameter) {
- $valueArray[] = $encoder->encode($parameter, $this->encodingOptions);
+ $arguments[] = $this->encoder->encode($parameter, $this->encodingOptions);
}
// just in case this was set to something else
+ $originalReturnType = $this->client->return_type;
$this->client->return_type = 'phpvals';
- $resp = $this->client->send(new PhpXmlRpc\Request($this->prefix.$name, $valueArray));
+ $resp = $this->client->send(new PhpXmlRpc\Request($this->prefix.$name, $arguments));
+
+ $this->client->return_type = $originalReturnType;
if ($resp->faultCode()) {
- throw new Exception($resp->faultString(), $resp->faultCode());
+ throw new \Exception($resp->faultString(), $resp->faultCode());
} else {
return $resp->value();
}
* In case the remote method name has characters which are not valid as php method names, use this.
*
* @param string $name remote function name. Will be prefixed
- * @param array $arguments
+ * @param array $arguments any php value will do. For xml-rpc base64 values, wrap them in a Value object
* @return mixed
*
* @throws Exception
}
}
-$proxy = new PhpXmlRpcProxy(new PhpXmlRpc\Client(XMLRPCSERVER));
+$proxy = new XmlRpcProxy(new PhpXmlRpc\Client(XMLRPCSERVER));
$stateNo = rand(1, 51);
// sadly, no IDE will be able to assist with autocompletion for this method, unless you manually add an equivalent phpdoc comment...
<body>
<h1>Which toolkit demo</h1>
<h2>Query server for toolkit information</h2>
-<h3>The code demonstrates usage of the PhpXmlRpc\Encoder class</h3>
+<h3>The code demonstrates support for http redirects, the `interopEchoTests.whichToolkit` xml-rpc methods and use of pre-built xml</h3>
<p>You can see the source to this page here: <a href="which.php?showSource=1">which.php</a></p>
');
-$client = new PhpXmlRpc\Client(XMLRPCSERVER);
-$req = new PhpXmlRpc\Request('interopEchoTests.whichToolkit', array());
-$resp = $client->send($req);
+use PhpXmlRpc\Client;
+use PhpXmlRpc\Encoder;
+
+$client = new Client(XMLRPCSERVER);
+
+// to support http redirects we have to force usage of cURL even for http 1.0 requests
+$client->setUseCurl(Client::USE_CURL_ALWAYS);
+$client->setCurlOptions(array(CURLOPT_FOLLOWLOCATION => true, CURLOPT_POSTREDIR => 3));
+
+// use a pre-built request payload
+$payload = '<?xml version="1.0"?>
+<methodCall>
+ <methodName>interopEchoTests.whichToolkit</methodName>
+ <params/>
+</methodCall>';
+// and ask the client to give us back xml
+$client->return_type = 'xml';
+
+output("XML custom request:<br/><pre>" . htmlspecialchars($payload) . "</pre>\n");
+
+$resp = $client->send($payload);
+
if (!$resp->faultCode()) {
- $encoder = new PhpXmlRpc\Encoder();
- $value = $encoder->decode($resp->value());
+
+ $xml = $resp->value();
+ output("XML response:<br/><pre>" . htmlspecialchars($xml) . "</pre>\n");
+
+ $encoder = new Encoder();
+ // from xml to xml-rpc Response
+ $response = $encoder->decodeXml($xml);
+ // from Response to Value
+ $value = $response->value();
+ // from value to php
+ $value = $encoder->decode($value);
+
output("Toolkit info:<br/>\n");
output("<pre>");
output("name: " . htmlspecialchars($value["toolkitName"]) . "\n");
{
global $SERVER_SOFTWARE;
$ret = array(
- "toolkitDocsUrl" => "http://phpxmlrpc.sourceforge.net/",
+ "toolkitDocsUrl" => "https://gggeek.github.io/phpxmlrpc/",
"toolkitName" => PhpXmlRpc\PhpXmlRpc::$xmlrpcName,
"toolkitVersion" => PhpXmlRpc\PhpXmlRpc::$xmlrpcVersion,
"toolkitOperatingSystem" => isset($SERVER_SOFTWARE) ? $SERVER_SOFTWARE : $_SERVER['SERVER_SOFTWARE'],