3 * Defines functions and signatures which can be registered as methods exposed by an XMLRPC Server
5 * To use this, use something akin to:
6 * $signatures = include('functions.php');
8 * Simplest possible way to implement webservices: create xmlrpc-aware php functions in the global namespace
11 use PhpXmlRpc\Encoder;
12 use PhpXmlRpc\Response;
16 // a PHP version of the state-number server
17 // send me an integer and i'll sell you a state
19 $GLOBALS['stateNames'] = array(
20 "Alabama", "Alaska", "Arizona", "Arkansas", "California",
21 "Colorado", "Columbia", "Connecticut", "Delaware", "Florida",
22 "Georgia", "Hawaii", "Idaho", "Illinois", "Indiana", "Iowa", "Kansas",
23 "Kentucky", "Louisiana", "Maine", "Maryland", "Massachusetts", "Michigan",
24 "Minnesota", "Mississippi", "Missouri", "Montana", "Nebraska", "Nevada",
25 "New Hampshire", "New Jersey", "New Mexico", "New York", "North Carolina",
26 "North Dakota", "Ohio", "Oklahoma", "Oregon", "Pennsylvania", "Rhode Island",
27 "South Carolina", "South Dakota", "Tennessee", "Texas", "Utah", "Vermont",
28 "Virginia", "Washington", "West Virginia", "Wisconsin", "Wyoming",
31 $findstate_sig = array(array(Value::$xmlrpcString, Value::$xmlrpcInt));
32 $findstate_doc = 'When passed an integer between 1 and 51 returns the name of a US state, where the integer is the ' .
33 'index of that state name in an alphabetic order.';
34 function findState($req)
37 // get the first param
38 $sno = $req->getParam(0);
40 // param must be there and of the correct type: server object does the validation for us
42 // extract the value of the state number
43 $snv = $sno->scalarval();
44 // look it up in our array (zero-based)
45 if (isset($GLOBALS['stateNames'][$snv - 1])) {
46 $stateName = $GLOBALS['stateNames'][$snv - 1];
48 // not there, so complain
49 $err = "I don't have a state for the index '" . $snv . "'";
52 // if we generated an error, create an error return response
54 return new Response(0, PhpXmlRpc\PhpXmlRpc::$xmlrpcerruser, $err);
56 // otherwise, we create the right response with the state name
57 return new Response(new Value($stateName));
63 // send me an array of structs thus:
70 // and I'll return it to you in sorted order
72 function agesorter_compare($a, $b)
74 /// @todo move away from usage of globals for such a simple case
75 global $agesorter_arr;
77 // don't even ask me _why_ these come padded with hyphens, I couldn't tell you :p
78 $a = str_replace("-", "", $a);
79 $b = str_replace("-", "", $b);
81 if ($agesorter_arr[$a] == $agesorter_arr[$b]) {
85 return ($agesorter_arr[$a] > $agesorter_arr[$b]) ? -1 : 1;
88 $agesorter_sig = array(array(Value::$xmlrpcArray, Value::$xmlrpcArray));
89 $agesorter_doc = 'Send this method an array of [string, int] structs, eg:
96 And the array will be returned with the entries sorted by their numbers.
98 function ageSorter($req)
100 global $agesorter_arr;
102 Server::xmlrpc_debugmsg("Entering 'agesorter'");
104 $sno = $req->getParam(0);
105 // error string for [if|when] things go wrong
109 $max = $sno->count();
110 Server::xmlrpc_debugmsg("Found $max array elements");
111 foreach ($sno as $i => $rec) {
112 if ($rec->kindOf() != "struct") {
113 $err = "Found non-struct in array at element $i";
116 // extract name and age from struct
119 // $n and $a are Values,
120 // so get the scalarval from them
121 $agar[$n->scalarval()] = $a->scalarval();
124 // create the output value
125 $v = new Value(array(), Value::$xmlrpcArray);
127 $agesorter_arr = $agar;
128 // hack, must make global as uksort() won't
129 // allow us to pass any other auxiliary information
130 uksort($agesorter_arr, 'agesorter_compare');
131 foreach($agesorter_arr as $key => $val) {
132 // recreate each struct element
135 "name" => new Value($key),
136 "age" => new Value($val, "int")
143 return new Response(0, PhpXmlRpc\PhpXmlRpc::$xmlrpcerruser, $err);
145 return new Response($v);
149 $addtwo_sig = array(array(Value::$xmlrpcInt, Value::$xmlrpcInt, Value::$xmlrpcInt));
150 $addtwo_doc = 'Add two integers together and return the result';
151 function addTwo($req)
153 $s = $req->getParam(0);
154 $t = $req->getParam(1);
156 return new Response(new Value($s->scalarval() + $t->scalarval(), Value::$xmlrpcInt));
159 $addtwodouble_sig = array(array(Value::$xmlrpcDouble, Value::$xmlrpcDouble, Value::$xmlrpcDouble));
160 $addtwodouble_doc = 'Add two doubles together and return the result';
161 function addTwoDouble($req)
163 $s = $req->getParam(0);
164 $t = $req->getParam(1);
166 return new Response(new Value($s->scalarval() + $t->scalarval(), Value::$xmlrpcDouble));
169 $stringecho_sig = array(array(Value::$xmlrpcString, Value::$xmlrpcString));
170 $stringecho_doc = 'Accepts a string parameter, returns the string.';
171 function stringEcho($req)
173 // just sends back a string
174 return new Response(new Value($req->getParam(0)->scalarval()));
177 $echoback_sig = array(array(Value::$xmlrpcString, Value::$xmlrpcString));
178 $echoback_doc = 'Accepts a string parameter, returns the entire incoming payload';
179 function echoBack($req)
181 // just sends back a string with what i got sent to me, just escaped, that's all
182 $s = "I got the following message:\n" . $req->serialize();
184 return new Response(new Value($s));
187 $echosixtyfour_sig = array(array(Value::$xmlrpcString, Value::$xmlrpcBase64));
188 $echosixtyfour_doc = 'Accepts a base64 parameter and returns it decoded as a string';
189 function echoSixtyFour($req)
191 // Accepts an encoded value, but sends it back as a normal string.
192 // This is to test that base64 encoding is working as expected
193 $incoming = $req->getParam(0);
195 return new Response(new Value($incoming->scalarval(), Value::$xmlrpcString));
198 $bitflipper_sig = array(array(Value::$xmlrpcArray, Value::$xmlrpcArray));
199 $bitflipper_doc = 'Accepts an array of booleans, and returns them inverted';
200 function bitFlipper($req)
202 $v = $req->getParam(0);
203 $rv = new Value(array(), Value::$xmlrpcArray);
206 if ($b->scalarval()) {
207 $rv[] = new Value(false, Value::$xmlrpcBoolean);
209 $rv[] = new Value(true, Value::$xmlrpcBoolean);
213 return new Response($rv);
216 $getallheaders_sig = array(array(Value::$xmlrpcStruct));
217 $getallheaders_doc = 'Returns a struct containing all the HTTP headers received with the request. Provides limited functionality with IIS';
218 function getAllHeaders_xmlrpc($req)
220 $encoder = new Encoder();
222 if (function_exists('getallheaders')) {
223 return new Response($encoder->encode(getallheaders()));
226 // IIS: poor man's version of getallheaders
227 foreach ($_SERVER as $key => $val) {
228 if (strpos($key, 'HTTP_') === 0) {
229 $key = ucfirst(str_replace('_', '-', strtolower(substr($key, 5))));
230 $headers[$key] = $val;
234 return new Response($encoder->encode($headers));
238 $setcookies_sig = array(array(Value::$xmlrpcInt, Value::$xmlrpcStruct));
239 $setcookies_doc = 'Sends to client a response containing a single \'1\' digit, and sets to it http cookies as received in the request (array of structs describing a cookie)';
240 function setCookies($req)
242 $encoder = new Encoder();
243 $cookies = $req->getParam(0);
244 foreach ($cookies as $name => $value) {
245 $cookieDesc = $encoder->decode($value);
246 setcookie($name, @$cookieDesc['value'], @$cookieDesc['expires'], @$cookieDesc['path'], @$cookieDesc['domain'], @$cookieDesc['secure']);
249 return new Response(new Value(1, Value::$xmlrpcInt));
252 $getcookies_sig = array(array(Value::$xmlrpcStruct));
253 $getcookies_doc = 'Sends to client a response containing all http cookies as received in the request (as struct)';
254 function getCookies($req)
256 $encoder = new Encoder();
257 return new Response($encoder->encode($_COOKIE));
260 $mailsend_sig = array(array(
261 Value::$xmlrpcBoolean, Value::$xmlrpcString, Value::$xmlrpcString,
262 Value::$xmlrpcString, Value::$xmlrpcString, Value::$xmlrpcString,
263 Value::$xmlrpcString, Value::$xmlrpcString,
265 $mailsend_doc = 'mail.send(recipient, subject, text, sender, cc, bcc, mimetype)<br/>
266 recipient, cc, and bcc are strings, comma-separated lists of email addresses, as described above.<br/>
267 subject is a string, the subject of the message.<br/>
268 sender is a string, it\'s the email address of the person sending the message. This string can not be
269 a comma-separated list, it must contain a single email address only.<br/>
270 text is a string, it contains the body of the message.<br/>
271 mimetype, a string, is a standard MIME type, for example, text/plain.
273 // WARNING; this functionality depends on the sendmail -t option
274 // it may not work with Windows machines properly; particularly
275 // the Bcc option. Sneak on your friends at your own risk!
276 function mailSend($req)
280 $mTo = $req->getParam(0);
281 $mSub = $req->getParam(1);
282 $mBody = $req->getParam(2);
283 $mFrom = $req->getParam(3);
284 $mCc = $req->getParam(4);
285 $mBcc = $req->getParam(5);
286 $mMime = $req->getParam(6);
288 if ($mTo->scalarval() == "") {
289 $err = "Error, no 'To' field specified";
292 if ($mFrom->scalarval() == "") {
293 $err = "Error, no 'From' field specified";
296 $msgHdr = "From: " . $mFrom->scalarval() . "\n";
297 $msgHdr .= "To: " . $mTo->scalarval() . "\n";
299 if ($mCc->scalarval() != "") {
300 $msgHdr .= "Cc: " . $mCc->scalarval() . "\n";
302 if ($mBcc->scalarval() != "") {
303 $msgHdr .= "Bcc: " . $mBcc->scalarval() . "\n";
305 if ($mMime->scalarval() != "") {
306 $msgHdr .= "Content-type: " . $mMime->scalarval() . "\n";
308 $msgHdr .= "X-Mailer: XML-RPC for PHP mailer 1.0";
311 if (!mail("", $mSub->scalarval(), $mBody->scalarval(), $msgHdr)
313 $err = "Error, could not send the mail.";
318 return new Response(0, PhpXmlRpc\PhpXmlRpc::$xmlrpcerruser, $err);
320 return new Response(new Value(true, Value::$xmlrpcBoolean));
325 "examples.getStateName" => array(
326 "function" => "findState",
327 "signature" => $findstate_sig,
328 "docstring" => $findstate_doc,
330 "examples.sortByAge" => array(
331 "function" => "ageSorter",
332 "signature" => $agesorter_sig,
333 "docstring" => $agesorter_doc,
335 "examples.addtwo" => array(
336 "function" => "addTwo",
337 "signature" => $addtwo_sig,
338 "docstring" => $addtwo_doc,
340 "examples.addtwodouble" => array(
341 "function" => "addTwoDouble",
342 "signature" => $addtwodouble_sig,
343 "docstring" => $addtwodouble_doc,
345 "examples.stringecho" => array(
346 "function" => "stringEcho",
347 "signature" => $stringecho_sig,
348 "docstring" => $stringecho_doc,
350 "examples.echo" => array(
351 "function" => "echoBack",
352 "signature" => $echoback_sig,
353 "docstring" => $echoback_doc,
355 "examples.decode64" => array(
356 "function" => "echoSixtyFour",
357 "signature" => $echosixtyfour_sig,
358 "docstring" => $echosixtyfour_doc,
360 "examples.invertBooleans" => array(
361 "function" => "bitFlipper",
362 "signature" => $bitflipper_sig,
363 "docstring" => $bitflipper_doc,
366 "examples.getallheaders" => array(
367 "function" => 'getAllHeaders_xmlrpc',
368 "signature" => $getallheaders_sig,
369 "docstring" => $getallheaders_doc,
371 "examples.setcookies" => array(
372 "function" => 'setCookies',
373 "signature" => $setcookies_sig,
374 "docstring" => $setcookies_doc,
376 "examples.getcookies" => array(
377 "function" => 'getCookies',
378 "signature" => $getcookies_sig,
379 "docstring" => $getcookies_doc,
382 "mail.send" => array(
383 "function" => "mailSend",
384 "signature" => $mailsend_sig,
385 "docstring" => $mailsend_doc,