180a1088b8f0a43569c7dd4681a4ccc547f3f832
[plcapi.git] / demo / server / server.php
1 <?php
2 /**
3  * Demo server for xmlrpc library.
4  *
5  * Implements a lot of webservices, including a suite of services used for
6  * interoperability testing (validator1 methods), and some whose only purpose
7  * is to be used for unit-testing the library.
8  *
9  * Please do not copy this file verbatim into your production server.
10  **/
11
12 // give user a chance to see the source for this server instead of running the services
13 if ($_SERVER['REQUEST_METHOD'] != 'POST' && isset($_GET['showSource'])) {
14     highlight_file(__FILE__);
15     die();
16 }
17
18 include_once __DIR__ . "/../../vendor/autoload.php";
19
20 // out-of-band information: let the client manipulate the server operations.
21 // we do this to help the testsuite script: do not reproduce in production!
22 if (isset($_COOKIE['PHPUNIT_SELENIUM_TEST_ID']) && extension_loaded('xdebug')) {
23     $GLOBALS['PHPUNIT_COVERAGE_DATA_DIRECTORY'] = '/tmp/phpxmlrpc_coverage';
24     if (!is_dir($GLOBALS['PHPUNIT_COVERAGE_DATA_DIRECTORY'])) {
25         mkdir($GLOBALS['PHPUNIT_COVERAGE_DATA_DIRECTORY']);
26     }
27
28     include_once __DIR__ . "/../../vendor/phpunit/phpunit-selenium/PHPUnit/Extensions/SeleniumCommon/prepend.php";
29 }
30
31 use PhpXmlRpc\Value;
32
33 /**
34  * Used to test usage of object methods in dispatch maps and in wrapper code.
35  */
36 class xmlrpcServerMethodsContainer
37 {
38     /**
39      * Method used to test logging of php warnings generated by user functions.
40      */
41     public function phpWarningGenerator($req)
42     {
43         $a = $undefinedVariable; // this triggers a warning in E_ALL mode, since $undefinedVariable is undefined
44         return new PhpXmlRpc\Response(new Value(1, 'boolean'));
45     }
46
47     /**
48      * Method used to test catching of exceptions in the server.
49      */
50     public function exceptionGenerator($req)
51     {
52         throw new Exception("it's just a test", 1);
53     }
54
55     /**
56      * A PHP version of the state-number server. Send me an integer and i'll sell you a state.
57      * Used to test wrapping of PHP methods into xmlrpc methods.
58      *
59      * @param integer $num
60      * @return string
61      * @throws Exception
62      */
63     public static function findState($num)
64     {
65         return inner_findstate($num);
66     }
67
68     /**
69      * Returns an instance of stdClass.
70      * Used to test wrapping of PHP objects with class preservation
71      */
72     public function returnObject()
73     {
74         $obj = new stdClass();
75         $obj->hello = 'world';
76         return $obj;
77     }
78 }
79
80 // a PHP version of the state-number server
81 // send me an integer and i'll sell you a state
82
83 $stateNames = array(
84     "Alabama", "Alaska", "Arizona", "Arkansas", "California",
85     "Colorado", "Columbia", "Connecticut", "Delaware", "Florida",
86     "Georgia", "Hawaii", "Idaho", "Illinois", "Indiana", "Iowa", "Kansas",
87     "Kentucky", "Louisiana", "Maine", "Maryland", "Massachusetts", "Michigan",
88     "Minnesota", "Mississippi", "Missouri", "Montana", "Nebraska", "Nevada",
89     "New Hampshire", "New Jersey", "New Mexico", "New York", "North Carolina",
90     "North Dakota", "Ohio", "Oklahoma", "Oregon", "Pennsylvania", "Rhode Island",
91     "South Carolina", "South Dakota", "Tennessee", "Texas", "Utah", "Vermont",
92     "Virginia", "Washington", "West Virginia", "Wisconsin", "Wyoming",
93 );
94
95 $findstate_sig = array(array(Value::$xmlrpcString, Value::$xmlrpcInt));
96 $findstate_doc = 'When passed an integer between 1 and 51 returns the
97 name of a US state, where the integer is the index of that state name
98 in an alphabetic order.';
99
100 function findState($req)
101 {
102     global $stateNames;
103
104     $err = "";
105     // get the first param
106     $sno = $req->getParam(0);
107
108     // param must be there and of the correct type: server object does the validation for us
109
110     // extract the value of the state number
111     $snv = $sno->scalarval();
112     // look it up in our array (zero-based)
113     if (isset($stateNames[$snv - 1])) {
114         $stateName = $stateNames[$snv - 1];
115     } else {
116         // not there, so complain
117         $err = "I don't have a state for the index '" . $snv . "'";
118     }
119
120     // if we generated an error, create an error return response
121     if ($err) {
122         return new PhpXmlRpc\Response(0, PhpXmlRpc\PhpXmlRpc::$xmlrpcerruser, $err);
123     } else {
124         // otherwise, we create the right response with the state name
125         return new PhpXmlRpc\Response(new Value($stateName));
126     }
127 }
128
129 /**
130  * Inner code of the state-number server.
131  * Used to test wrapping of PHP functions into xmlrpc methods.
132  *
133  * @param integer $stateNo the state number
134  *
135  * @return string the name of the state (or error description)
136  *
137  * @throws Exception if state is not found
138  */
139 function inner_findstate($stateNo)
140 {
141     global $stateNames;
142
143     if (isset($stateNames[$stateNo - 1])) {
144         return $stateNames[$stateNo - 1];
145     } else {
146         // not, there so complain
147         throw new Exception("I don't have a state for the index '" . $stateNo . "'", PhpXmlRpc\PhpXmlRpc::$xmlrpcerruser);
148     }
149 }
150
151 $wrapper = new PhpXmlRpc\Wrapper();
152
153 $findstate2_sig = $wrapper->wrapPhpFunction('inner_findstate');
154
155 $findstate3_sig = $wrapper->wrapPhpFunction(array('xmlrpcServerMethodsContainer', 'findState'));
156
157 $obj = new xmlrpcServerMethodsContainer();
158 $findstate4_sig = $wrapper->wrapPhpFunction(array($obj, 'findstate'));
159
160 $findstate5_sig = $wrapper->wrapPhpFunction('xmlrpcServerMethodsContainer::findState', '', array('return_source' => true));
161 eval($findstate5_sig['source']);
162
163 $findstate6_sig = $wrapper->wrapPhpFunction('inner_findstate', '', array('return_source' => true));
164 eval($findstate6_sig['source']);
165
166 $findstate7_sig = $wrapper->wrapPhpFunction(array('xmlrpcServerMethodsContainer', 'findState'), '', array('return_source' => true));
167 eval($findstate7_sig['source']);
168
169 $obj = new xmlrpcServerMethodsContainer();
170 $findstate8_sig = $wrapper->wrapPhpFunction(array($obj, 'findstate'), '', array('return_source' => true));
171 eval($findstate8_sig['source']);
172
173 $findstate9_sig = $wrapper->wrapPhpFunction('xmlrpcServerMethodsContainer::findState', '', array('return_source' => true));
174 eval($findstate9_sig['source']);
175
176 $findstate10_sig = array(
177     "function" => function ($req) { return findState($req); },
178     "signature" => $findstate_sig,
179     "docstring" => $findstate_doc,
180 );
181
182 $findstate11_sig = $wrapper->wrapPhpFunction(function ($stateNo) { return inner_findstate($stateNo); });
183
184 $c = new xmlrpcServerMethodsContainer;
185 $moreSignatures = $wrapper->wrapPhpClass($c, array('prefix' => 'tests.', 'method_type' => 'all'));
186
187 $returnObj_sig =  $wrapper->wrapPhpFunction(array($c, 'returnObject'), '', array('encode_php_objs' => true));
188
189 // used to test signatures with NULL params
190 $findstate12_sig = array(
191     array(Value::$xmlrpcString, Value::$xmlrpcInt, Value::$xmlrpcNull),
192     array(Value::$xmlrpcString, Value::$xmlrpcNull, Value::$xmlrpcInt),
193 );
194
195 function findStateWithNulls($req)
196 {
197     $a = $req->getParam(0);
198     $b = $req->getParam(1);
199
200     if ($a->scalartyp() == Value::$xmlrpcNull)
201         return new PhpXmlRpc\Response(new Value(inner_findstate($b->scalarval())));
202     else
203         return new PhpXmlRpc\Response(new Value(inner_findstate($a->scalarval())));
204 }
205
206 $addtwo_sig = array(array(Value::$xmlrpcInt, Value::$xmlrpcInt, Value::$xmlrpcInt));
207 $addtwo_doc = 'Add two integers together and return the result';
208 function addTwo($req)
209 {
210     $s = $req->getParam(0);
211     $t = $req->getParam(1);
212
213     return new PhpXmlRpc\Response(new Value($s->scalarval() + $t->scalarval(), "int"));
214 }
215
216 $addtwodouble_sig = array(array(Value::$xmlrpcDouble, Value::$xmlrpcDouble, Value::$xmlrpcDouble));
217 $addtwodouble_doc = 'Add two doubles together and return the result';
218 function addTwoDouble($req)
219 {
220     $s = $req->getParam(0);
221     $t = $req->getParam(1);
222
223     return new PhpXmlRpc\Response(new Value($s->scalarval() + $t->scalarval(), "double"));
224 }
225
226 $stringecho_sig = array(array(Value::$xmlrpcString, Value::$xmlrpcString));
227 $stringecho_doc = 'Accepts a string parameter, returns the string.';
228 function stringEcho($req)
229 {
230     // just sends back a string
231     return new PhpXmlRpc\Response(new Value($req->getParam(0)->scalarval()));
232 }
233
234 $echoback_sig = array(array(Value::$xmlrpcString, Value::$xmlrpcString));
235 $echoback_doc = 'Accepts a string parameter, returns the entire incoming payload';
236 function echoBack($req)
237 {
238     // just sends back a string with what i got sent to me, just escaped, that's all
239     $s = "I got the following message:\n" . $req->serialize();
240
241     return new PhpXmlRpc\Response(new Value($s));
242 }
243
244 $echosixtyfour_sig = array(array(Value::$xmlrpcString, Value::$xmlrpcBase64));
245 $echosixtyfour_doc = 'Accepts a base64 parameter and returns it decoded as a string';
246 function echoSixtyFour($req)
247 {
248     // Accepts an encoded value, but sends it back as a normal string.
249     // This is to test that base64 encoding is working as expected
250     $incoming = $req->getParam(0);
251
252     return new PhpXmlRpc\Response(new Value($incoming->scalarval(), "string"));
253 }
254
255 $bitflipper_sig = array(array(Value::$xmlrpcArray, Value::$xmlrpcArray));
256 $bitflipper_doc = 'Accepts an array of booleans, and returns them inverted';
257 function bitFlipper($req)
258 {
259     $v = $req->getParam(0);
260     $sz = $v->arraysize();
261     $rv = new Value(array(), Value::$xmlrpcArray);
262
263     for ($j = 0; $j < $sz; $j++) {
264         $b = $v->arraymem($j);
265         if ($b->scalarval()) {
266             $rv->addScalar(false, "boolean");
267         } else {
268             $rv->addScalar(true, "boolean");
269         }
270     }
271
272     return new PhpXmlRpc\Response($rv);
273 }
274
275 // Sorting demo
276 //
277 // send me an array of structs thus:
278 //
279 // Dave 35
280 // Edd  45
281 // Fred 23
282 // Barney 37
283 //
284 // and I'll return it to you in sorted order
285
286 function agesorter_compare($a, $b)
287 {
288     global $agesorter_arr;
289
290     // don't even ask me _why_ these come padded with hyphens, I couldn't tell you :p
291     $a = str_replace("-", "", $a);
292     $b = str_replace("-", "", $b);
293
294     if ($agesorter_arr[$a] == $agesorter_arr[$b]) {
295         return 0;
296     }
297
298     return ($agesorter_arr[$a] > $agesorter_arr[$b]) ? -1 : 1;
299 }
300
301 $agesorter_sig = array(array(Value::$xmlrpcArray, Value::$xmlrpcArray));
302 $agesorter_doc = 'Send this method an array of [string, int] structs, eg:
303 <pre>
304  Dave   35
305  Edd    45
306  Fred   23
307  Barney 37
308 </pre>
309 And the array will be returned with the entries sorted by their numbers.
310 ';
311 function ageSorter($req)
312 {
313     global $agesorter_arr, $s;
314
315     PhpXmlRpc\Server::xmlrpc_debugmsg("Entering 'agesorter'");
316     // get the parameter
317     $sno = $req->getParam(0);
318     // error string for [if|when] things go wrong
319     $err = "";
320     // create the output value
321     $v = new Value();
322     $agar = array();
323
324     $max = $sno->arraysize();
325     PhpXmlRpc\Server::xmlrpc_debugmsg("Found $max array elements");
326     for ($i = 0; $i < $max; $i++) {
327         $rec = $sno->arraymem($i);
328         if ($rec->kindOf() != "struct") {
329             $err = "Found non-struct in array at element $i";
330             break;
331         }
332         // extract name and age from struct
333         $n = $rec->structmem("name");
334         $a = $rec->structmem("age");
335         // $n and $a are xmlrpcvals,
336         // so get the scalarval from them
337         $agar[$n->scalarval()] = $a->scalarval();
338     }
339
340     $agesorter_arr = $agar;
341     // hack, must make global as uksort() won't
342     // allow us to pass any other auxiliary information
343     uksort($agesorter_arr, 'agesorter_compare');
344     $outAr = array();
345     while (list($key, $val) = each($agesorter_arr)) {
346         // recreate each struct element
347         $outAr[] = new Value(array("name" => new Value($key),
348             "age" => new Value($val, "int"),), "struct");
349     }
350     // add this array to the output value
351     $v->addArray($outAr);
352
353     if ($err) {
354         return new PhpXmlRpc\Response(0, PhpXmlRpc\PhpXmlRpc::$xmlrpcerruser, $err);
355     } else {
356         return new PhpXmlRpc\Response($v);
357     }
358 }
359
360 // signature and instructions, place these in the dispatch map
361 $mailsend_sig = array(array(
362     Value::$xmlrpcBoolean, Value::$xmlrpcString, Value::$xmlrpcString,
363     Value::$xmlrpcString, Value::$xmlrpcString, Value::$xmlrpcString,
364     Value::$xmlrpcString, Value::$xmlrpcString,
365 ));
366 $mailsend_doc = 'mail.send(recipient, subject, text, sender, cc, bcc, mimetype)<br/>
367 recipient, cc, and bcc are strings, comma-separated lists of email addresses, as described above.<br/>
368 subject is a string, the subject of the message.<br/>
369 sender is a string, it\'s the email address of the person sending the message. This string can not be
370 a comma-separated list, it must contain a single email address only.<br/>
371 text is a string, it contains the body of the message.<br/>
372 mimetype, a string, is a standard MIME type, for example, text/plain.
373 ';
374 // WARNING; this functionality depends on the sendmail -t option
375 // it may not work with Windows machines properly; particularly
376 // the Bcc option. Sneak on your friends at your own risk!
377 function mailSend($req)
378 {
379     $err = "";
380
381     $mTo = $req->getParam(0);
382     $mSub = $req->getParam(1);
383     $mBody = $req->getParam(2);
384     $mFrom = $req->getParam(3);
385     $mCc = $req->getParam(4);
386     $mBcc = $req->getParam(5);
387     $mMime = $req->getParam(6);
388
389     if ($mTo->scalarval() == "") {
390         $err = "Error, no 'To' field specified";
391     }
392
393     if ($mFrom->scalarval() == "") {
394         $err = "Error, no 'From' field specified";
395     }
396
397     $msgHdr = "From: " . $mFrom->scalarval() . "\n";
398     $msgHdr .= "To: " . $mTo->scalarval() . "\n";
399
400     if ($mCc->scalarval() != "") {
401         $msgHdr .= "Cc: " . $mCc->scalarval() . "\n";
402     }
403     if ($mBcc->scalarval() != "") {
404         $msgHdr .= "Bcc: " . $mBcc->scalarval() . "\n";
405     }
406     if ($mMime->scalarval() != "") {
407         $msgHdr .= "Content-type: " . $mMime->scalarval() . "\n";
408     }
409     $msgHdr .= "X-Mailer: XML-RPC for PHP mailer 1.0";
410
411     if ($err == "") {
412         if (!mail("",
413             $mSub->scalarval(),
414             $mBody->scalarval(),
415             $msgHdr)
416         ) {
417             $err = "Error, could not send the mail.";
418         }
419     }
420
421     if ($err) {
422         return new PhpXmlRpc\Response(0, PhpXmlRpc\PhpXmlRpc::$xmlrpcerruser, $err);
423     } else {
424         return new PhpXmlRpc\Response(new Value("true", Value::$xmlrpcBoolean));
425     }
426 }
427
428 $getallheaders_sig = array(array(Value::$xmlrpcStruct));
429 $getallheaders_doc = 'Returns a struct containing all the HTTP headers received with the request. Provides limited functionality with IIS';
430 function getAllHeaders_xmlrpc($req)
431 {
432     $encoder = new PhpXmlRpc\Encoder();
433
434     if (function_exists('getallheaders')) {
435         return new PhpXmlRpc\Response($encoder->encode(getallheaders()));
436     } else {
437         $headers = array();
438         // IIS: poor man's version of getallheaders
439         foreach ($_SERVER as $key => $val) {
440             if (strpos($key, 'HTTP_') === 0) {
441                 $key = ucfirst(str_replace('_', '-', strtolower(substr($key, 5))));
442                 $headers[$key] = $val;
443             }
444         }
445
446         return new PhpXmlRpc\Response($encoder->encode($headers));
447     }
448 }
449
450 $setcookies_sig = array(array(Value::$xmlrpcInt, Value::$xmlrpcStruct));
451 $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)';
452 function setCookies($req)
453 {
454     $encoder = new PhpXmlRpc\Encoder();
455     $m = $req->getParam(0);
456     while (list($name, $value) = $m->structeach()) {
457         $cookieDesc = $encoder->decode($value);
458         setcookie($name, @$cookieDesc['value'], @$cookieDesc['expires'], @$cookieDesc['path'], @$cookieDesc['domain'], @$cookieDesc['secure']);
459     }
460
461     return new PhpXmlRpc\Response(new Value(1, 'int'));
462 }
463
464 $getcookies_sig = array(array(Value::$xmlrpcStruct));
465 $getcookies_doc = 'Sends to client a response containing all http cookies as received in the request (as struct)';
466 function getCookies($req)
467 {
468     $encoder = new PhpXmlRpc\Encoder();
469     return new PhpXmlRpc\Response($encoder->encode($_COOKIE));
470 }
471
472 $v1_arrayOfStructs_sig = array(array(Value::$xmlrpcInt, Value::$xmlrpcArray));
473 $v1_arrayOfStructs_doc = 'This handler takes a single parameter, an array of structs, each of which contains at least three elements named moe, larry and curly, all <i4>s. Your handler must add all the struct elements named curly and return the result.';
474 function v1_arrayOfStructs($req)
475 {
476     $sno = $req->getParam(0);
477     $numCurly = 0;
478     for ($i = 0; $i < $sno->arraysize(); $i++) {
479         $str = $sno->arraymem($i);
480         $str->structreset();
481         while (list($key, $val) = $str->structeach()) {
482             if ($key == "curly") {
483                 $numCurly += $val->scalarval();
484             }
485         }
486     }
487
488     return new PhpXmlRpc\Response(new Value($numCurly, "int"));
489 }
490
491 $v1_easyStruct_sig = array(array(Value::$xmlrpcInt, Value::$xmlrpcStruct));
492 $v1_easyStruct_doc = 'This handler takes a single parameter, a struct, containing at least three elements named moe, larry and curly, all &lt;i4&gt;s. Your handler must add the three numbers and return the result.';
493 function v1_easyStruct($req)
494 {
495     $sno = $req->getParam(0);
496     $moe = $sno->structmem("moe");
497     $larry = $sno->structmem("larry");
498     $curly = $sno->structmem("curly");
499     $num = $moe->scalarval() + $larry->scalarval() + $curly->scalarval();
500
501     return new PhpXmlRpc\Response(new Value($num, "int"));
502 }
503
504 $v1_echoStruct_sig = array(array(Value::$xmlrpcStruct, Value::$xmlrpcStruct));
505 $v1_echoStruct_doc = 'This handler takes a single parameter, a struct. Your handler must return the struct.';
506 function v1_echoStruct($req)
507 {
508     $sno = $req->getParam(0);
509
510     return new PhpXmlRpc\Response($sno);
511 }
512
513 $v1_manyTypes_sig = array(array(
514     Value::$xmlrpcArray, Value::$xmlrpcInt, Value::$xmlrpcBoolean,
515     Value::$xmlrpcString, Value::$xmlrpcDouble, Value::$xmlrpcDateTime,
516     Value::$xmlrpcBase64,
517 ));
518 $v1_manyTypes_doc = 'This handler takes six parameters, and returns an array containing all the parameters.';
519 function v1_manyTypes($req)
520 {
521     return new PhpXmlRpc\Response(new Value(array(
522         $req->getParam(0),
523         $req->getParam(1),
524         $req->getParam(2),
525         $req->getParam(3),
526         $req->getParam(4),
527         $req->getParam(5),),
528         "array"
529     ));
530 }
531
532 $v1_moderateSizeArrayCheck_sig = array(array(Value::$xmlrpcString, Value::$xmlrpcArray));
533 $v1_moderateSizeArrayCheck_doc = 'This handler takes a single parameter, which is an array containing between 100 and 200 elements. Each of the items is a string, your handler must return a string containing the concatenated text of the first and last elements.';
534 function v1_moderateSizeArrayCheck($req)
535 {
536     $ar = $req->getParam(0);
537     $sz = $ar->arraysize();
538     $first = $ar->arraymem(0);
539     $last = $ar->arraymem($sz - 1);
540
541     return new PhpXmlRpc\Response(new Value($first->scalarval() .
542         $last->scalarval(), "string"));
543 }
544
545 $v1_simpleStructReturn_sig = array(array(Value::$xmlrpcStruct, Value::$xmlrpcInt));
546 $v1_simpleStructReturn_doc = 'This handler takes one parameter, and returns a struct containing three elements, times10, times100 and times1000, the result of multiplying the number by 10, 100 and 1000.';
547 function v1_simpleStructReturn($req)
548 {
549     $sno = $req->getParam(0);
550     $v = $sno->scalarval();
551
552     return new PhpXmlRpc\Response(new Value(array(
553         "times10" => new Value($v * 10, "int"),
554         "times100" => new Value($v * 100, "int"),
555         "times1000" => new Value($v * 1000, "int"),),
556         "struct"
557     ));
558 }
559
560 $v1_nestedStruct_sig = array(array(Value::$xmlrpcInt, Value::$xmlrpcStruct));
561 $v1_nestedStruct_doc = 'This handler takes a single parameter, a struct, that models a daily calendar. At the top level, there is one struct for each year. Each year is broken down into months, and months into days. Most of the days are empty in the struct you receive, but the entry for April 1, 2000 contains a least three elements named moe, larry and curly, all &lt;i4&gt;s. Your handler must add the three numbers and return the result.';
562 function v1_nestedStruct($req)
563 {
564     $sno = $req->getParam(0);
565
566     $twoK = $sno->structmem("2000");
567     $april = $twoK->structmem("04");
568     $fools = $april->structmem("01");
569     $curly = $fools->structmem("curly");
570     $larry = $fools->structmem("larry");
571     $moe = $fools->structmem("moe");
572
573     return new PhpXmlRpc\Response(new Value($curly->scalarval() + $larry->scalarval() + $moe->scalarval(), "int"));
574 }
575
576 $v1_countTheEntities_sig = array(array(Value::$xmlrpcStruct, Value::$xmlrpcString));
577 $v1_countTheEntities_doc = 'This handler takes a single parameter, a string, that contains any number of predefined entities, namely &lt;, &gt;, &amp; \' and ".<BR>Your handler must return a struct that contains five fields, all numbers: ctLeftAngleBrackets, ctRightAngleBrackets, ctAmpersands, ctApostrophes, ctQuotes.';
578 function v1_countTheEntities($req)
579 {
580     $sno = $req->getParam(0);
581     $str = $sno->scalarval();
582     $gt = 0;
583     $lt = 0;
584     $ap = 0;
585     $qu = 0;
586     $amp = 0;
587     for ($i = 0; $i < strlen($str); $i++) {
588         $c = substr($str, $i, 1);
589         switch ($c) {
590             case ">":
591                 $gt++;
592                 break;
593             case "<":
594                 $lt++;
595                 break;
596             case "\"":
597                 $qu++;
598                 break;
599             case "'":
600                 $ap++;
601                 break;
602             case "&":
603                 $amp++;
604                 break;
605             default:
606                 break;
607         }
608     }
609
610     return new PhpXmlRpc\Response(new Value(array(
611         "ctLeftAngleBrackets" => new Value($lt, "int"),
612         "ctRightAngleBrackets" => new Value($gt, "int"),
613         "ctAmpersands" => new Value($amp, "int"),
614         "ctApostrophes" => new Value($ap, "int"),
615         "ctQuotes" => new Value($qu, "int"),),
616         "struct"
617     ));
618 }
619
620 // trivial interop tests
621 // http://www.xmlrpc.com/stories/storyReader$1636
622
623 $i_echoString_sig = array(array(Value::$xmlrpcString, Value::$xmlrpcString));
624 $i_echoString_doc = "Echoes string.";
625
626 $i_echoStringArray_sig = array(array(Value::$xmlrpcArray, Value::$xmlrpcArray));
627 $i_echoStringArray_doc = "Echoes string array.";
628
629 $i_echoInteger_sig = array(array(Value::$xmlrpcInt, Value::$xmlrpcInt));
630 $i_echoInteger_doc = "Echoes integer.";
631
632 $i_echoIntegerArray_sig = array(array(Value::$xmlrpcArray, Value::$xmlrpcArray));
633 $i_echoIntegerArray_doc = "Echoes integer array.";
634
635 $i_echoFloat_sig = array(array(Value::$xmlrpcDouble, Value::$xmlrpcDouble));
636 $i_echoFloat_doc = "Echoes float.";
637
638 $i_echoFloatArray_sig = array(array(Value::$xmlrpcArray, Value::$xmlrpcArray));
639 $i_echoFloatArray_doc = "Echoes float array.";
640
641 $i_echoStruct_sig = array(array(Value::$xmlrpcStruct, Value::$xmlrpcStruct));
642 $i_echoStruct_doc = "Echoes struct.";
643
644 $i_echoStructArray_sig = array(array(Value::$xmlrpcArray, Value::$xmlrpcArray));
645 $i_echoStructArray_doc = "Echoes struct array.";
646
647 $i_echoValue_doc = "Echoes any value back.";
648 $i_echoValue_sig = array(array(Value::$xmlrpcValue, Value::$xmlrpcValue));
649
650 $i_echoBase64_sig = array(array(Value::$xmlrpcBase64, Value::$xmlrpcBase64));
651 $i_echoBase64_doc = "Echoes base64.";
652
653 $i_echoDate_sig = array(array(Value::$xmlrpcDateTime, Value::$xmlrpcDateTime));
654 $i_echoDate_doc = "Echoes dateTime.";
655
656 function i_echoParam($req)
657 {
658     $s = $req->getParam(0);
659
660     return new PhpXmlRpc\Response($s);
661 }
662
663 function i_echoString($req)
664 {
665     return i_echoParam($req);
666 }
667
668 function i_echoInteger($req)
669 {
670     return i_echoParam($req);
671 }
672
673 function i_echoFloat($req)
674 {
675     return i_echoParam($req);
676 }
677
678 function i_echoStruct($req)
679 {
680     return i_echoParam($req);
681 }
682
683 function i_echoStringArray($req)
684 {
685     return i_echoParam($req);
686 }
687
688 function i_echoIntegerArray($req)
689 {
690     return i_echoParam($req);
691 }
692
693 function i_echoFloatArray($req)
694 {
695     return i_echoParam($req);
696 }
697
698 function i_echoStructArray($req)
699 {
700     return i_echoParam($req);
701 }
702
703 function i_echoValue($req)
704 {
705     return i_echoParam($req);
706 }
707
708 function i_echoBase64($req)
709 {
710     return i_echoParam($req);
711 }
712
713 function i_echoDate($req)
714 {
715     return i_echoParam($req);
716 }
717
718 $i_whichToolkit_sig = array(array(Value::$xmlrpcStruct));
719 $i_whichToolkit_doc = "Returns a struct containing the following strings: toolkitDocsUrl, toolkitName, toolkitVersion, toolkitOperatingSystem.";
720
721 function i_whichToolkit($req)
722 {
723     global $SERVER_SOFTWARE;
724     $ret = array(
725         "toolkitDocsUrl" => "http://phpxmlrpc.sourceforge.net/",
726         "toolkitName" => PhpXmlRpc\PhpXmlRpc::$xmlrpcName,
727         "toolkitVersion" => PhpXmlRpc\PhpXmlRpc::$xmlrpcVersion,
728         "toolkitOperatingSystem" => isset($SERVER_SOFTWARE) ? $SERVER_SOFTWARE : $_SERVER['SERVER_SOFTWARE'],
729     );
730
731     $encoder = new PhpXmlRpc\Encoder();
732     return new PhpXmlRpc\Response($encoder->encode($ret));
733 }
734
735 $object = new xmlrpcServerMethodsContainer();
736 $signatures = array(
737     "examples.getStateName" => array(
738         "function" => "findState",
739         "signature" => $findstate_sig,
740         "docstring" => $findstate_doc,
741     ),
742     "examples.sortByAge" => array(
743         "function" => "ageSorter",
744         "signature" => $agesorter_sig,
745         "docstring" => $agesorter_doc,
746     ),
747     "examples.addtwo" => array(
748         "function" => "addTwo",
749         "signature" => $addtwo_sig,
750         "docstring" => $addtwo_doc,
751     ),
752     "examples.addtwodouble" => array(
753         "function" => "addTwoDouble",
754         "signature" => $addtwodouble_sig,
755         "docstring" => $addtwodouble_doc,
756     ),
757     "examples.stringecho" => array(
758         "function" => "stringEcho",
759         "signature" => $stringecho_sig,
760         "docstring" => $stringecho_doc,
761     ),
762     "examples.echo" => array(
763         "function" => "echoBack",
764         "signature" => $echoback_sig,
765         "docstring" => $echoback_doc,
766     ),
767     "examples.decode64" => array(
768         "function" => "echoSixtyFour",
769         "signature" => $echosixtyfour_sig,
770         "docstring" => $echosixtyfour_doc,
771     ),
772     "examples.invertBooleans" => array(
773         "function" => "bitFlipper",
774         "signature" => $bitflipper_sig,
775         "docstring" => $bitflipper_doc,
776     ),
777     // signature omitted on purpose
778     "tests.generatePHPWarning" => array(
779         "function" => array($object, "phpWarningGenerator"),
780     ),
781     // signature omitted on purpose
782     "tests.raiseException" => array(
783         "function" => array($object, "exceptionGenerator"),
784     ),
785     // Greek word 'kosme'. NB: NOT a valid ISO8859 string!
786     // NB: we can only register this when setting internal encoding to UTF-8, or it will break system.listMethods
787     "tests.utf8methodname." . 'κόσμε' => array(
788         "function" => "stringEcho",
789         "signature" => $stringecho_sig,
790         "docstring" => $stringecho_doc,
791     ),
792     /*"tests.iso88591methodname." . chr(224) . chr(252) . chr(232) => array(
793         "function" => "stringEcho",
794         "signature" => $stringecho_sig,
795         "docstring" => $stringecho_doc,
796     ),*/
797     "examples.getallheaders" => array(
798         "function" => 'getAllHeaders_xmlrpc',
799         "signature" => $getallheaders_sig,
800         "docstring" => $getallheaders_doc,
801     ),
802     "examples.setcookies" => array(
803         "function" => 'setCookies',
804         "signature" => $setcookies_sig,
805         "docstring" => $setcookies_doc,
806     ),
807     "examples.getcookies" => array(
808         "function" => 'getCookies',
809         "signature" => $getcookies_sig,
810         "docstring" => $getcookies_doc,
811     ),
812     "mail.send" => array(
813         "function" => "mailSend",
814         "signature" => $mailsend_sig,
815         "docstring" => $mailsend_doc,
816     ),
817     "validator1.arrayOfStructsTest" => array(
818         "function" => "v1_arrayOfStructs",
819         "signature" => $v1_arrayOfStructs_sig,
820         "docstring" => $v1_arrayOfStructs_doc,
821     ),
822     "validator1.easyStructTest" => array(
823         "function" => "v1_easyStruct",
824         "signature" => $v1_easyStruct_sig,
825         "docstring" => $v1_easyStruct_doc,
826     ),
827     "validator1.echoStructTest" => array(
828         "function" => "v1_echoStruct",
829         "signature" => $v1_echoStruct_sig,
830         "docstring" => $v1_echoStruct_doc,
831     ),
832     "validator1.manyTypesTest" => array(
833         "function" => "v1_manyTypes",
834         "signature" => $v1_manyTypes_sig,
835         "docstring" => $v1_manyTypes_doc,
836     ),
837     "validator1.moderateSizeArrayCheck" => array(
838         "function" => "v1_moderateSizeArrayCheck",
839         "signature" => $v1_moderateSizeArrayCheck_sig,
840         "docstring" => $v1_moderateSizeArrayCheck_doc,
841     ),
842     "validator1.simpleStructReturnTest" => array(
843         "function" => "v1_simpleStructReturn",
844         "signature" => $v1_simpleStructReturn_sig,
845         "docstring" => $v1_simpleStructReturn_doc,
846     ),
847     "validator1.nestedStructTest" => array(
848         "function" => "v1_nestedStruct",
849         "signature" => $v1_nestedStruct_sig,
850         "docstring" => $v1_nestedStruct_doc,
851     ),
852     "validator1.countTheEntities" => array(
853         "function" => "v1_countTheEntities",
854         "signature" => $v1_countTheEntities_sig,
855         "docstring" => $v1_countTheEntities_doc,
856     ),
857     "interopEchoTests.echoString" => array(
858         "function" => "i_echoString",
859         "signature" => $i_echoString_sig,
860         "docstring" => $i_echoString_doc,
861     ),
862     "interopEchoTests.echoStringArray" => array(
863         "function" => "i_echoStringArray",
864         "signature" => $i_echoStringArray_sig,
865         "docstring" => $i_echoStringArray_doc,
866     ),
867     "interopEchoTests.echoInteger" => array(
868         "function" => "i_echoInteger",
869         "signature" => $i_echoInteger_sig,
870         "docstring" => $i_echoInteger_doc,
871     ),
872     "interopEchoTests.echoIntegerArray" => array(
873         "function" => "i_echoIntegerArray",
874         "signature" => $i_echoIntegerArray_sig,
875         "docstring" => $i_echoIntegerArray_doc,
876     ),
877     "interopEchoTests.echoFloat" => array(
878         "function" => "i_echoFloat",
879         "signature" => $i_echoFloat_sig,
880         "docstring" => $i_echoFloat_doc,
881     ),
882     "interopEchoTests.echoFloatArray" => array(
883         "function" => "i_echoFloatArray",
884         "signature" => $i_echoFloatArray_sig,
885         "docstring" => $i_echoFloatArray_doc,
886     ),
887     "interopEchoTests.echoStruct" => array(
888         "function" => "i_echoStruct",
889         "signature" => $i_echoStruct_sig,
890         "docstring" => $i_echoStruct_doc,
891     ),
892     "interopEchoTests.echoStructArray" => array(
893         "function" => "i_echoStructArray",
894         "signature" => $i_echoStructArray_sig,
895         "docstring" => $i_echoStructArray_doc,
896     ),
897     "interopEchoTests.echoValue" => array(
898         "function" => "i_echoValue",
899         "signature" => $i_echoValue_sig,
900         "docstring" => $i_echoValue_doc,
901     ),
902     "interopEchoTests.echoBase64" => array(
903         "function" => "i_echoBase64",
904         "signature" => $i_echoBase64_sig,
905         "docstring" => $i_echoBase64_doc,
906     ),
907     "interopEchoTests.echoDate" => array(
908         "function" => "i_echoDate",
909         "signature" => $i_echoDate_sig,
910         "docstring" => $i_echoDate_doc,
911     ),
912     "interopEchoTests.whichToolkit" => array(
913         "function" => "i_whichToolkit",
914         "signature" => $i_whichToolkit_sig,
915         "docstring" => $i_whichToolkit_doc,
916     ),
917
918     'tests.getStateName.2' => $findstate2_sig,
919     'tests.getStateName.3' => $findstate3_sig,
920     'tests.getStateName.4' => $findstate4_sig,
921     'tests.getStateName.5' => $findstate5_sig,
922     'tests.getStateName.6' => $findstate6_sig,
923     'tests.getStateName.7' => $findstate7_sig,
924     'tests.getStateName.8' => $findstate8_sig,
925     'tests.getStateName.9' => $findstate9_sig,
926     'tests.getStateName.10' => $findstate10_sig,
927     'tests.getStateName.11' => $findstate11_sig,
928
929     'tests.getStateName.12' => array(
930         "function" => "findStateWithNulls",
931         "signature" => $findstate12_sig,
932         "docstring" => $findstate_doc,
933     ),
934
935     'tests.returnPhpObject' => $returnObj_sig,
936 );
937
938 $signatures = array_merge($signatures, $moreSignatures);
939
940 // enable support for the NULL extension
941 PhpXmlRpc\PhpXmlRpc::$xmlrpc_null_extension = true;
942
943 $s = new PhpXmlRpc\Server($signatures, false);
944 $s->setdebug(3);
945 $s->compress_response = true;
946
947 // out-of-band information: let the client manipulate the server operations.
948 // we do this to help the testsuite script: do not reproduce in production!
949 if (isset($_GET['RESPONSE_ENCODING'])) {
950     $s->response_charset_encoding = $_GET['RESPONSE_ENCODING'];
951 }
952 if (isset($_GET['EXCEPTION_HANDLING'])) {
953     $s->exception_handling = $_GET['EXCEPTION_HANDLING'];
954 }
955 $s->service();
956 // that should do all we need!
957
958 // out-of-band information: let the client manipulate the server operations.
959 // we do this to help the testsuite script: do not reproduce in production!
960 if (isset($_COOKIE['PHPUNIT_SELENIUM_TEST_ID']) && extension_loaded('xdebug')) {
961     include_once __DIR__ . "/../../vendor/phpunit/phpunit-selenium/PHPUnit/Extensions/SeleniumCommon/append.php";
962 }