diff options
25 files changed, 4545 insertions, 8623 deletions
diff --git a/modules/xmlrpc/ChangeLog b/modules/xmlrpc/ChangeLog index f24bf866..7273f893 100644 --- a/modules/xmlrpc/ChangeLog +++ b/modules/xmlrpc/ChangeLog @@ -1,15 +1,851 @@ +2007-02-25 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * removed a couple of warnings emitted in testsuite.php + + * doc/makefile: added command for invocation of xxe to generate docs + + * better rendering of docs in xml+css format for function prototypes + + * updated documentation + + * tagged and released as 2.2 + +2007-02-22 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * debugger: workaround for case of magic_quotes_gpc being set (properly + unescape user input); fix case of user not setting msg id in jsonrpc case + when executing a remote method; allow strings, false, true and null as msg id + +2007-02-13 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * testsuite.php: added one test for automatic encoding/decoding case + +2007-02-05 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpc.inc: slightly faster encoding of UTF8 data to ascii + +2007-01-11 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpc.inc: when calling client::multicall() with an unspecified http version, + use the client default rather than the fixed 'http 1.0' + +2006-09-17 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpc.inc, xmlrpcs.inc, testsuite.php: added support for </NIL> and + system.getCapabilities, and one more testcase to go with it + +2006-09-05 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpc.inc: fix support for https through proxies; client parses debug + messages sent by client even for compressed responses; + + * testsuite.php, parse_args.php: added 3 test cases for proxy connections + +2006-09-01 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + xmlrpc_wrappers.inc: add two more options in wrap_xmlrpc_method and fix + typo to allow obj encoding + +2006-08-28 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpc_wrappers.inc: more options added to wrap_php_function and + wrap_xmlrpc_method + + * xmlrpc.inc: pave the way to support for <nil/> + + * doc/xmlrpc_php.xml documentation updated + + * tagged and released as 2.1 + +2006-08-25 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpc.inc: stricter parsing of incoming messages: detect two DATA elements + inside an ARRAY, a STRUCT or SCALAR inside an already filled VALUE + + * testsuite.php: added two testcases to check for the above cases + +2006-08-24 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpc.inc: more code optimization in xmlrpcval::serialize() and + php_xmlrpc_encode(); fixed bug where struct elements with non-ascii chars + in their name would not be properly encoded + + * testsuite.php: added a testcase for the new bug + +2006-08-23 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * remove old code left in comments across many files; many more javadoc + comments added + + * xmlrpc.inc: a bit of code optimization: reorder switch() statements of + xml parsing element handlers; inline code for xmlrpcval() - this breaks + new xmlrpcval('true') and changes error msgs on new xmlrpcval($x, 'invalid_type') + + * testsuite.php: change according to above + + * benchmark.php: basic support for xdebug 2 profiling + +2006-08-22 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpc.inc: addscalar() and addstruct() where not returning 1 when adding + data to an already formed value + +2006-08-21 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpcs.inc, xmlrpc.inc: added support for emulating the xmlrpc-extension + API (the full emulation layer is part of the extras package); + fix support for the HTTP 'deflate' encoding + + * xmlrpc.inc: better support for http compression with and without CURL; + a minor decoding speedup; added a new function: php_xmlrpc_decode_xml(), + that will convert into the appropriate object the xml representation of + either a request, response or a single value; log reception of invalid + datetime values + + * xmlrpcs.inc: add a new parameter and return type to server->service(); + let server->add_to_map() accept method definitions without parameter types + + * xmlrpc_wrappers.inc: more logging of errors; wrap_php_functions now takes + more options; better support for jsonrpc; escape quote chars when wrapping + remothe servers / remote methods + + * added cvs Id tag to files that missed it; speling fixes; updated NEWS files + +2006-08-07 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * assorted fixes to make the suite more compatible with php 4.0.5 and 5.x + +2006-07-02 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpc_warppers.inc: added new function to wrap entire remote server into + a local php class; changed default calling synopsis of wrap_remote_method, + to ease passing multiple options at a time (but old syntax still works!) + + * updated makefile, debugger/action.php in accord with the above + +2006-06-30 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * added to debugger capability to generate json-rpc code stubs + + * added to debugger capability to load and launch self correctly if + controller.php is called directly from outside processes (single url access) + +2006-06-26 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * moved wrap_php_functions and wrap_xmlrpc_method into a file of their own. + This will let us add further stub functionality without the base lib growing too much. + All of the files that reference this functionality have been modified accordingly. + + * made wrap_xmlrpc_method generate better code (with php type juggling), and + some phpdoc for the generated function, too + + * added to debugger an option to produce for the user the generated php code + for wrapping a call to a remote method into a php function + +2006-06-22 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpcs.inc: added description of parameters for system.xxx methods (useful with + html-self-documenting servers); + server->service() now returns response object, in case user has need for it... + + * xmlrpc.inc: save full response payload into xmlrpcresp obj for better debugging + +2006-06-15 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * verify_compat.php: more tests + +2006-06-09 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpcs.inc: fixed sending of compressed responses when output compression + is already enabled in php.ini + + * verify_compat.php: split tests between server and client cases + +2006-05-29 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * added new file: verify_compat.php, to help troubleshooting platform + support for the library; added it to makefile, too + +2006-05-24 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpc.inc: removed residual usage of regexp in favour of pregexps; fixed + a bug in specifying Host http header with non std ports + +2006-05-23 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpc.inc: improvements to wrap_php_function: let it deal correctly + with php functions returning xmlrpcresp objs; make it generate also + docs for single parameters (useful for documenting_xmlrpc_server class) + +2006-05-22 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpc.inc, xmlrpcs.inc: minor performance tuning updates: replaced + some explode vs. split, ereg vs. preg, single vs. double quotes + + * xmlrpc.inc: fix wrap_xmlrpc_method to NOT rebuild php objects received + from the server by default, as it might pose a security risk + +2006-04-24 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * minor fixes makefiles. Tagged and released as 2.0 final + +2006-04-22 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * debugger/*: added option to set cainfo; improve web layout + + * xmlrpc.inc: set sslverifypeer tp TRUE instaed of 1 by default + + * doc/php_xmlrpc.xml: documentation updates + +2006-04-21 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpc.inc: added option to set ca certs dir instead of single cert + (used to validate server in https connetions) + +2006-04-18 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpc.inc: fixed bug in xmlrpcval::structmemexists() + + * testsuite.php: added test case for xmlrpcval::structmemexists() + +2006-04-03 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpc.inc: add support for Digest and NTLM authentication, both to server + and to proxies (note: must use CURL for this to work) + + * debugger/*: add support for Digest/NTLM auth to remote servers + +2006-03-19 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpc.inc: fix a bug parsing of 'true' bool values; + added a new method to the client class: SetCaCertificate; + add column number in xml parsing error messages; + fix serialization of messages to ISO-8859-1 charset with php 5 (by adding + encoding to the xml prologue of generated messages) + + * xmlrpcs.inc: correct detection of charset in http headers; + add column number in xml parsing error messages; + fix serialization of responses to ISO-8859-1 charset with php 5 (by adding + encoding to the xml prologue of generated responses) + + * testsuite.php: added two more tests on charset encoding + + * NEWS: update info for impending release + +2006-03-23 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * added a new demo file: simple_call.php + +2006-02-20 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpcs.inc: more error checking and logging with regard to user-coded + method handler functions not being well behaved; + fix a case where error handler would not be reset upon user function + returning not valid xmlrpresp + + * xmlrpc.inc: fix bug in detection of php 4.3.0 + + * Makefile: fix uppercase filenames + +2006-02-15 + + * xmlrpc.inc: parse 'true' and 'false' as valid booleans, even though the + spec is quite clear on that; fix small bug w. internal_encoding = utf8; add + definition of $GLOBALS['xmlrpcNull'] for extensibility, e.g. json or + extensions to the xmlrpc spec + +2006-02-05 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpc.inc: fix bug in wrap_xmlrpc_method if client passed to function has + return_type=phpvals + + * all demo files: review code, add more comments and information + + * added 2 demo files: proxy.php (implementing an xmlrpc proxy server) and + wrap.php (showing usage of wrap_method_call) + +2006-02-04 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpc.inc: fix bug in multicall in case of no fallback and server error + +2006-01-30 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpc.inc: fix recursive serialization of xmlrpcvals loosing UTF8 charset; + correctly set type field of xmlrpcvals returned by send() calls + + * xmlrpcs.inc: add to server checks for correct return type of user-coded + method handling function; tolerate xmlrpcval instead of xmlrpcresp + + * minor change in xmlrpcresp internals, to ease subclassing (store payload + in an internal var on serialize(), same as xmlrpcclient does) + +2006-01-22 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * benchmark.php: do not run http 1.1 tests if CURL notfound + + * Released as 2.0 Rc3 + +2006-01-19 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpc.inc: make xmlrpc_client::setDebug() accept int values instead of + boolean. At level 2, the request payload is printed to screen before being + sent; fix bug with repeated sending of the same msg object and using request + compression w. php 5.1.2 (objects passed by ref by default!!!) + + * xmlrpcs.inc: fix detection of clients accepting compressed responses + + * comment.php: remove warnings due to liberal usage of $HTTP_POST/GET_VARS + + * benchmark.php: add a test using http compression of both requests and + responses + + * testsuite.php: added test for fix in xmlrpc.inc + +2006-01-17 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpcs.php: minor fix: do not raise a PHP warning when std server is + called via GET (global HTTP_RAW_POST_DATA undefined). Some might have called + it a security breach (path disclosure)... + +2006-01-15 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * testsuite.php: minor fix to expected date format in http cookie hedaer + to cope with PHP 5.1.2 + +2006-01-05 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpcs.inc: merge code from the 'extras' subclass that allows server + to register plain php functions in dispatch map instead of functions + accepting a single xmlrpcmgs obj parameter. + One step closer to the kitchen sink!!! + +2005-12-31 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpcs.inc: let the server accept 'class::method' syntax in the dispatch + map + + * testsuite.php, server.php: added new tests for the recent charset encoding + capabilities + +2005-12-24 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpc.inc: correctly serialize() string xmlrpcvals that have been + created out of non-string php variables, when internal encoding is UTF8; + serialize to '0' int and double values created out of non-string php + variables, eg. 'hello', instead of creating invalid xmlrpc; + extend the php_xmlrpc_encode function to allow serializing string values + to charsets other tha US-ASCII; + minor tweak to xml parsing to allow correct parsing of empty strings when + in 'direct to php values' mode + + * xmlrpcs.inc: advances in system.multicall with plain php values + +2005-12-17 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpcs.inc: let the functions implementing the system.* methods work + fine when called with plain php values as parameters instead of xmlrpcmsg + objects (multicall not quite finished yet...); + encode level 3 debug info as base64 data, to avoid charset encoding hell + + * xmlrpc.inc: added a new xmlrpc_2_php_type function, to get the name of + php types corresponding to xmlrpc types; + in debug mode, when detecting base64 server debug info, print it out fine + + * server.php: cosmetic fixes + +2005-12-09 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpc.inc: remove one warning emitted when received xml contains an + unknown tag; remove warnings emitted when custom error handler is set + and user calls php_xmlrpc_encode/decode without the 2nd parameter + + * xmlrpcs.inc: added a param to service(), to allow the server to parse + data other than the POST body (useful for subclassing and debugging); + reworked the implementation of server debug messages at debug level 2: + since the debug info generated has no known charset, and putting it back + into the response's xml would most likely break it, send it back to the + client as a base64 encoded comment. Clients can decode it if they need it... + Add some more javadocs + + * testsuite.php: modified the string test, to see if the server can echo + back to the client the received data without breaking the response's xml + +2005-12-05 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpc.inc, xmlrpcs.inc: let server and client objects decide if they + want to use some charset encoding other than US-ASCII for serialized data: + add a new var to both objects, and lots of parameters to function calls + that took none up to now; + refactored server method service() and parseRequest(), implementing a + new parserequestHeaders() method to explicitly deal with HTTP + +2005-12-01 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * moved the jsonrpc implementation and the new wsdl stuff to a separate + CVS module; updated the makefile to reflect it + +2005-11-24 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * modified php_xmlrpc_decode() to work on xmlrpcmessages too, besides + xmlrpcvals. To achieve this, added a new method: xmlrpcmsg::kindOf() + +2005-11-22 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * released as 2.0 RC2 + +2005-11-21 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpc.inc: fix warnings about references for PHP 4.1.X + + * Whitespace cleanup on all the lib + +2005-11-16 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpc.inc: rewritten xmlrpc_encode_entitites adding two extra parameters + that specify input and output charset encodings. This corrects the bug that + prevented native UTF-8 strings to be correctly serialized (to have them + encoded the user must set $xmlrpc_internalencoing appropriately). + + * xmlrpc.inc: added new method xmlrpcmsg::parseResponseHeaders(), refactoring + parseResponse(). This makes the code more modular and eases subclassing. + + * xmlrpc.inc: set cookies and http headers to xmlrpcresp objs even when calls + to send() do not complete correctly + + * added new file: jsonrpcs.inc, to accomodate server jsonrpc objects in the future + + * jsonrpc.inc: slow progress... + +2005-11-10 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpc.inc: fixed the xmlrpc_client send and sendpayloadhttps methods + to fix errors in calling https servers; + added a new xmlrpc_client->setkey method to allow usage of client-side ssl + certs in recent php builds; + added to xmlrpcresp objects a content_type var, to be used in HTTP headers + + * xmlrpcs.inc: separate generation of content-type http header and xml prologue + from the service() method, to ease subclassing + +2005-11-03 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpc.inc: moved the 'text/xml' mimetype string as class var of the xmlrpcmsg + object instead of having it cabled into xmlrpc_client->send(): this allows to + create subclasses of xmlrpcmsg that use a different mimetype + + * jsonrpc.inc: added a new file, with an extremely experimental set of classes, + designed to implement a json-rpc client and server, taking advantage of the + existing xml-rpc infrastructure + +2005-10-28 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpc.inc: changed constructor method for xmlrpcresp, making it smarter in + case user does not declare the type of value it is passing to it; + minor changes in serialization of xmlrpcresp with error codes, so that it + utputs LF instead of CRLF on windows boxes after an FTP transfer of the code, too + +2005-10-26 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpc.inc: added a new var of class xmlrpc_client, indicating what kind of + object will be stored in the value() of xmlrpcresp's gotten from the send() + method: xmlrpxc objects, plain php variables or raw xml. This allow the coder + to make use of xmlrpc_decode for better performances if he wishes so. + Modified creator of xmlrpcresp class to allow it to distinguish between being + created out of raw xml or a plain php string (in the former case, serialization + is still possible, opening a new world of opportunity for server-side programming: + the php function implementing a web service has to provide the xml for the + return value on its own). + Modified xmlrpc_client::multicall() to suit; also added a new parameter which + allows calls to multicall without automatic fallback to many-calls in case of + error (speeding up the process of doing a failed multicall() call quite a bit) + Fixed two bugs in guess_encoding. + Audited all regexps and fixed some. + xmlrpc_client::send() does not call xmlrpcmsg::parseresponsefile() anymore. + Shuffled parseresponse() a little bit + + * testsuite.php: added a new testcase for the modifications to multicall(): + now we test the case where xmlrpc_client returns php values, too + +2005-10-24 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpc.inc: fixed guess_encoding() to always return uppercase chars + + * added new file: benchmark.php. It contains a few tests used to evaluate + speed of the lib in common use cases + + * added file parse_args.php, containing common code for benchmark and + testsuite, and modified testsuite.php accordingly + + * modified makefile adding new files + + * testsuite.php: added a couple of new test cases; fixed one warning + emitted in php 5 E_STRICT mode + +2005-10-20 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpc.inc: modify 3d param of ParseResponse(), allowing the function to + return the raw xml received as value of the xmlrpcresponse object. + This allows eg. to have epi-xmlrpc decode the xml for faster execution. + +2005-10-09 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpc.inc: fixed error that prevented usage of HTTPS (the client + always determined that ssl support was not present) + +2005-10-03 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpc.inc, xmlrpcs.inc: revert direction of stack growth during xml + parsing for faster execution time; add support for detecting charset + encoding of received xml; add support for cookies; better parsing of + javadoc when building stub code in wrap_php_function; add a lot of + javadoc comments everywhere; rewrite most error messages + + * testsuite.php: add many tests for newly introduced features + + * server.php: add a couple of new functions to support debugging new + features + + * debugger: add switches to enable all the latest lib features; minor + improvements to layout + + * synch included phpunit with latest PEAR release + + * reorganize files included in the distribution in a new hierarchy of folders + + * bump revision number to 2.0RC1 and release + +2005-8-14 Miles Lott <milos@groupwhere.org> + + * xmlrpc.inc, xmlrpcs.inc: Remove all use of eval() to avoid potential + security hole. + + * As of this release we are no longer php3-compatible. + +2005-8-10 Miles Lott <milos@groupwhere.org> + + * xmlrpc.inc, xmlrpcs.inc: Switched to using $GLOBALS instead of calling + global $varname + +2005-07-22 Miles Lott <milos@groupwhere.org> + + * Removed: bug_* files + +2005-07-14 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * debugger: added a workaround to disable using the debugger for attacking + older versions of the lib + + * testsuite.php: added code to test wrap_xmlrpc_method; + use different wording for failed tests + + * xmlrpcs.inc: change for() with foreach() in system.* methods implementations; + remove a possible cause of php warning; + + * xmlrpc.inc: let wrap_php_function and wrap_xmlrpc_method find suitable + function names if default function names are already in use; + correct wrap_xmlrpc_method to not set http protocol to 1.0 when not asked to; + detect curl compiles without SSL + +2005-07-14 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpc.inc: more auto-fix of xmlrpc_client path: '' -> '/'; + change to the method used for detecting failed evals (php 4.0.x compatibility); + complete rework of return-by-ref functions to comply with php 4.4.0 + + * xmlrpcs.inc: change to the method used for detecting failed evals (php 4.0.x + compatibility) + + * testsuite.php: major rewrite of the multi- tests, to give better feedback on + number of failed tests; + flush html page title to screen before starting tests; + +2005-07-13 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpc.inc: let xmlrpcmsg creator be forgiving of target paths that miss the + starting '/' char; + completely reworked assign-by-ref to be compliant with php 4.4.0 stricter + warnings + + * testsuite.php: added ability to be run from cli: (really dumb) separation of + html and plain text outputs + parsing of argv parameters + +2005-07-12 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpc.inc: compatibility fixes with PHP versions 4.0.x (and remove some for + PHP 3) + + * xmlrpcs.inc: compatibility fixes for PHP 4.0.x versions + + * testsuite.php: better support for running with php versions 4.0.x; + do not generate runtime errors but finish tests anyway if some calls to + localhost fail; + correctly detect a localhost port different from 80 for running tests against + +2005-07-11 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpc.inc: preliminary building of method signature and docs in + wrap_php_function; + fix a bug in extracting function description from javadoc block in + wrap_php_function; + small fix for better compatibility with php < 4.2.0 + + * added compat subdir with extra code, taken form PEAR package Compat, to let + the lib run fine with php 4 versions < 4.1 + +2005-07-10 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpc.inc: some nazi whitespace corrections; + declared global $xmlrpcBoolean too (was the only one missing); + used @eval inside getval() to have less path disclosure security reports filed + in the future; + added new global var: $xmlrpcValue, to be used in server dispatch maps as + placeholder for a param which can be of any kind; + big chunks (but still incomplete) of javadoc parsing in wrap_php_function + + changed type of return val - now it is the complete array to be put in the + dispatch map + + * xmlrpcs.inc: let previous error handler be called by server to handle errors + even if in debug level 3; + default to compress responses if zlib installed; + added a new val useful for only checking number (not type) of params in method + calls; + let user use object methods in dispatch map using the + array($obj, 'fmethodname') format + + * server.php: Added code called by testsuite.php to exercise registration of + object methods as xmlrpc methods and auto-registration of php functions as xmlrpc + methods + + * testsuite.php: added tests to exercice server registering object methods as + xmlrpc methods and automatic registration of php functions as server methods; + added a hint to enable debug if some test goes wrong; + renamed https test for better clarity + +2005-07-07 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpc.inc: added function to be used for 'guestimating' charset encoding of + received xml (not activated yet) + + * server.php: Let server compress content by default if user asks so: it allows + testsuite to check for compressed responses + + * testsuite.php: added suite of tests for compressed responses; test CURL + (http1.1) with all possible compression combinations too + +2005-07-06 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpc.inc: Enable setting usage of keepalives on/off (for CURL cases); + implement compression of xmlrpc requests; enable new syntax of xmlrpclient + constructor: 1 - allow preferred http method to be set at creation time, + 2 - allow user to insert a single complete URL as only parameter and parse it; + try to detect if curl is present whether it has been compiled w. zlib to enable + automatically the reception of compressed responses + + * xmlrpcs.inc: do not add into logs the content of the request, if it was + received gzipped/deflated, to avoid breaking the xml sent back as response + (NB: might be investigated further: is the problem caused by windows chars in + the range 128-160 ?) + + * testsuite.php: run all localhost tests 2 more times, to stress request + compression; + run all localhost tests in a row using keepalives, to test keepalive + functionality + +2005-07-05 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpc.inc: let CURL pass back to caller function the complete PHP headers + as it did before: it enables better logging / debugging of communication; + small change to the way CURL declares its ability to receive compressed + messages (fix for the case where zlib is compiled in PHP but not in curl); + added Keep-alive (ON BY DEFAULT) for http 1.1 and https messages (had to modify + a lot of functions for that); + always make sure a 'Connection: close' header is sent with curl connections if + keep-alive is not wanted + + * phpunit.php: switched to PEAR PHPUnit (rel 1.2.3), since it is maintained a + lot more than the old version we were using + + * added new folder with code of phpunit classes + + * testsuite.php: added a new run of tests to check for compliance of client + when using http 1.1; + switched to PEAR PHPUnit classes; + divided test for client ability to do multicall() into 2 separate tests + +2005-06-30 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + tagged and released version 1.1.1, backporting security fixes from HEAD + 2005-06-28 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> - * xmlrpcs.inc: fixed security vulnerability (PHP code injection) in handling of - BASE64 vals and NAME tags + * xmlrpcs.inc: fix changes introuced yesterday in a rush; + do not list system.* methods for a server that has them explicitly disabled + + * bug_inject.xml: new test case used to check for code injection vulnerability + + * testsuite.php: added a test case for zero parameters method calls; + added two test cases for recently found code injection vulnerabilities + +2005-06-27 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpc.inc: (tentative) fix for security problem reported by + security@gulftech.org: we were not properly php-escaping xml received for + BASE64 and NAME tags; + some more patching related to junk received in xml messages/responses: if the + PHP code built from the parsed xml is broken, catch any generated errors + without echoing it to screen but take note of the error and propagate to user + code + + * xmlrpcs.inc: some more patching related to junk received in xml messages/ + responses: if the PHP code built from the parsed xml is broken, catch any + generated errors without echoing it to screen but take note of the error and + propagate to user code + +2005-06-24 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpc.inc: fixed php_xmlrpc_encode detection of php arrays (again!); + removed from wrap_php_function the part about setting a custom error handler + (it can be activated using the more general $server->setdebug(3) anyway) + + * xmlrpcs.inc: added to server the capability to trap all processing errors + during execution of user functions and add them to debug info inside responses; + return a (new) xmlrpcerr response instead of raising some obscure php execution + error if there is an undefined function in the dispatch map + + * testsuite.php: Added new testcases for recently implemented stuff + +2005-06-23 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpc.inc: added new method: xmlrpcval->structmemexists, to check for + presence of a wanted struct member without having to loop through all members; + fix wrap_php_functions: correctly return false for php internal functions, + whose param list is unknown; + let addscalar fail as it should if called on struct vals; + fix addstruct: do not fail when called for adding stuff to initialized structs; + removed a warning generated when calling addscalar with inexistent type; + massive code review for speed: replaced each() loops with foreach(), removed + lots of useless assignments and duplications of data; + added 'http11' as valid method param for xmlrpclient->send: makes use of curl + for sending http 1.1 requests; + changed a couple '=' into '=&' where objects are returned; + fixed wrap_php_function() to better detect php errors while processing wrapped + function + + * xmlrpcs.inc: Fix php warnings generated when clients requested method + signature / description for a method that had none in its dispatch map; + turned server->debug into an integer value that will change the amount of + logging going as comments into xmlrpc responses + + * server.php: set default server debug level to 2 + + * testsuite.php: removed calls to deleted functions (xmlrpc_encode, + xmlrpc_decode); + added html page title describing target servers used for tests; + added an assign-by-ref + + * phpunit.php: Do not consider as failures PHP 5 E_STRICT errors (arbitrary + choice, but lib is targeted at PHP 4) + +2005-06-22 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpc.inc: removed lottsa old code that had been left in commented + + * xmlrpc.inc: fixed setting of proxy port + + * xmlrpc.inc: removed one warning when trying to decompress junk sent as + deflated response + + * xmlrpc.inc: changed the error messages (but not the code) that will be found + in xmlrpcresponses when there are socket errors, to differentiate from HTTP + errors - * xmlrpc.inc, xmlrpcs.inc: catch errors in evaluated PHP code and return an - error to the calling code in case any are found + * xmlrpc.inc: refactored xmlrpcclient->sendpayloadHTTPS: now it calls a new + method (sendpayloadCURL) that could be used also for generating HTTP 1.1 + requests - * testsuite.php: added a test case for caling methods without params, plus - a couple to test the code injection fixes + * xmlrpc.inc: added two new methods: wrap_php_function and wrap_xmlrpc_method: + designed to let the lazy programmer automagically convert php functions to + xmlrpc methods and vice versa. Details are in the code - * bumped up rev number and released as 1.1.1 + * debugger/*: added initial revision of a 'universal xmlrpc debugger' + +2005-06-20 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpc.inc: replace usage of 'echo' with error_log when errors arise + in manipulation of xmlrpcval objects + + * xmlrpc.inc: replaced <br> with <br /> in dump function + + * xmlrpc.inc: added method structsize to xmlrpcval class (alias for arraysize) + + * xmlrpc.inc: addarray() now will add extra members to an xmlrpcval object + of array type; addstruct() can be used to add members to an xmlrpcval object + of struct type + + * xmlrpcs.inc: Added member allow_system_funcs to server: controls whether the + server accepts or not calls to system.* functions + +2005-05-10 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpc.inc: fix regression in php_xmlrpc_encode when encoding php hashes; + fix decompression of gzip/deflated xmlrpc responses; + set user agent string correctly in SSL mode (was forgetting lib name); + add allowed encoding http headers in requests; + do not pass http headers back from curl to parseresponse, to avoid re-decoding + compressed xml or http 100 headers + + * xmlrpcs.inc: added method setDebug; + renamed compress_output to compress_response; + do not try to set http headers if they have already been sent, because trying + to do so will raise a PHP error, and if headers have been sent something has + gone wrong already (shall we send a meaningful error response instead?) + +2005-05-08 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * xmlrpcs.inc, xmlrpcs.inc: reverted to usage of '=& new' for better + performance on (some) php4 installs. + NB: PHP 3 compatibility is deprecated from now on! + + * xmlrpc.inc: decode xmlrpc boolean type to native php boolean + + * xmlrpcs.inc, xmlrpcs.inc: switched $_xh[$parser] to $_xh, since indexing + an array by object will give a warning in php 5 (and we were resetting the + array of _xh elements on every call anyway) + + * xmlrpc.inc: commented unused code used originally for escaping content + + * xmlrpc.inc: commented deprecated methods xmlrpc_encode and xmlrpc_decode + + * xmlrpc.inc: php_xmlrpc_encode: encode integer-indexed php arrays as xmlrpc + arrays instead of structs; if object given to encode is an xmlrpcval return it + instead of reencoding (makes easier calling encode on an array of xmlrpcvals) + + * xmlrpcs.inc: added $debug field to server class; if false will prevent + the server from echoing debug info back to the client as xml comment + + * xmlrpcs.inc: let the server add to the debug messages the complete request + payload received and (if php installed as apache module) http headers, so that + the client in debug mode can echo a complete fingerprint of the communication + + * xmlrpcs.inc: changed API of ParseRequest method: now it cannot be called + without a 'data' parameter; added 2nd parameter (http encoding); changed the + call to this method from inside service() method + + * xmlrpc.inc, xmlrpcs.inc: enable both server and client to parse compressed xml + (if php is compiled with zlib); client should also be able to decode chunked + http encoding + + * xmlrpc.inc: add support for proxies (only basic auth supported); default port + is 8080 (if left unspecified) + + * xmlrpc.inc: use lowercase for names of http headers received (makes using + them much simpler, since servers can use any upper/lowercase combination) + + * xmlrpc.inc: bumped version number to '2.0 beta' + +2005-05-08 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> + + * release of version 1.1 2005-04-24 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> @@ -122,7 +958,7 @@ * xmlrpc.inc: set hdrs field into response object in case of XML parsing error (uniform behaviour with other responses) - + 2005-02-26 Gaetano Giunta <giunta.gaetano@sea-aeroportimilano.it> * xmlrpc.inc: use global var $xmlrpcVersion as number for user agent string @@ -166,7 +1002,7 @@ Andres Salomon on 2004-03-17: sending named html entities inside an xml chunk makes it invalid, and thus renders the lib absolutely non-interoperable with any other xmlrpc implementation; moreover the current implementation only ever - worked for non-ascii requests, while breaking client-parsing of responses + worked for non-ascii requests, while breaking client-parsing of responses containing non-ascii chars. The principle of using entities is preserved though, because it allows the client to send correct xml regardless of php internal charset encoding vs. @@ -224,7 +1060,7 @@ * xmlrpc.inc: close curl connection as soon as possible for https requests: it could save some memory / resources. - * xmlrpc.inc: added some extra info in the PHP error log message generated + * xmlrpc.inc: added some extra info in the PHP error log message generated when an invalid xmlrpc integer/float value is encountered and we try to deserialize it. @@ -288,7 +1124,7 @@ output in PRE tags. 2002-12-17 Andres Salomon <dilinger@voxel.net> - + * released 1.0.99. * Makefile: changed the tarball format/dist rule to a more conventional form, as well as normal release updates. @@ -306,7 +1142,7 @@ * testsuite.php: Add new tests 'testServerMulticall', and 'testClientMulticall'. - + * xmlrpc.inc: Added new error messages for system.multicall(). * xmlrpcs.inc: Added new procedure call system.multicall(). See http://www.xmlrpc.com/discuss/msgReader$1208 for details. @@ -376,7 +1212,7 @@ * xmlrpc.inc: merged in some changes from Dan Libby which fix up whitespace handling. - + * xmlrpcs.inc: added Content-length header on response (bug from Jan Varga <varga@utcru.sk>. This means you can no longer print during processing @@ -398,7 +1234,7 @@ * doc/xmlrpc_php.sgml: updated documentation to reflect recent changes - + 2000-07-18 Edd Dumbill <edd@usefulinc.com> @@ -424,7 +1260,7 @@ * server.php: Added validator1 suite of tests to test against validator.xmlrpc.com - + 2000-05-06 Edd Dumbill <edd@usefulinc.com> @@ -432,7 +1268,7 @@ * added test.pl and test.py, Perl and Python scripts that exercise server.php somewhat (but not a lot) - + * added extra fault condition for a non 200 OK response from the remote server. @@ -514,15 +1350,16 @@ * Improved XML parse error reporting on the server side to send it back in a faultCode packet. expat errors now begin at 100 - + 1999-07-07 Edd Dumbill <edd@usefulinc.com> * Changed the structmem and arraymem methods of xmlrpcval to always return xmlrpc vals whether they referred to scalars or complex types. - + * Added the server class and demonstrations - + * Fixed bugs in the XML parsing and reworked it -$Id: ChangeLog,v 1.26 2005/04/24 18:32:22 ggiunta Exp $ + +$Id: ChangeLog,v 1.80 2007/02/25 18:42:53 ggiunta Exp $ diff --git a/modules/xmlrpc/README b/modules/xmlrpc/README index 790bbbc6..e757a5d3 100644 --- a/modules/xmlrpc/README +++ b/modules/xmlrpc/README @@ -1,3 +1,9 @@ +NAME: XMLRPC FOR PHP + +DESCRIPTION: A php library for building xmlrpc clients and servers + + + HTML documentation can be found in the doc/ directory. Recent changes in the ChangeLog diff --git a/modules/xmlrpc/doc/Makefile b/modules/xmlrpc/doc/Makefile deleted file mode 100755 index 77a47180..00000000 --- a/modules/xmlrpc/doc/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -WEB=/var/www/xmlrpc/doc - -all: index.html - -index.html: xmlrpc_php.sgml - jade -t sgml -d custom.dsl xmlrpc_php.sgml - -clean: - rm -f *.html - -install: - mkdir -p ${WEB} - cp *.html ${WEB} - -web: - mkdir -p ${WEB} - cp *.html ${WEB} diff --git a/modules/xmlrpc/doc/apidocs.html b/modules/xmlrpc/doc/apidocs.html deleted file mode 100644 index 6178742e..00000000 --- a/modules/xmlrpc/doc/apidocs.html +++ /dev/null @@ -1,598 +0,0 @@ -<HTML -><HEAD -><TITLE ->Class documentation</TITLE -><META -NAME="GENERATOR" -CONTENT="Modular DocBook HTML Stylesheet Version 1.77+"><LINK -REV="MADE" -HREF="edd@usefulinc.com"><LINK -REL="HOME" -TITLE="XML-RPC for PHP" -HREF="index.html"><LINK -REL="PREVIOUS" -TITLE="The Jellyfish Book" -HREF="jellyfish.html"><LINK -REL="NEXT" -TITLE="xmlrpcmsg" -HREF="xmlrpcmsg.html"></HEAD -><BODY -CLASS="CHAPTER" -BGCOLOR="#FFFFFF" -TEXT="#000000" -LINK="#0000FF" -VLINK="#840084" -ALINK="#0000FF" -><DIV -CLASS="NAVHEADER" -><TABLE -SUMMARY="Header navigation table" -WIDTH="100%" -BORDER="0" -CELLPADDING="0" -CELLSPACING="0" -><TR -><TH -COLSPAN="3" -ALIGN="center" ->XML-RPC for PHP: version 1.1</TH -></TR -><TR -><TD -WIDTH="10%" -ALIGN="left" -VALIGN="bottom" -><A -HREF="jellyfish.html" -ACCESSKEY="P" ->Prev</A -></TD -><TD -WIDTH="80%" -ALIGN="center" -VALIGN="bottom" -></TD -><TD -WIDTH="10%" -ALIGN="right" -VALIGN="bottom" -><A -HREF="xmlrpcmsg.html" -ACCESSKEY="N" ->Next</A -></TD -></TR -></TABLE -><HR -ALIGN="LEFT" -WIDTH="100%"></DIV -><DIV -CLASS="CHAPTER" -><H1 -><A -NAME="APIDOCS" -></A ->Chapter 5. Class documentation</H1 -><DIV -CLASS="TOC" -><DL -><DT -><B ->Table of Contents</B -></DT -><DT -><A -HREF="apidocs.html#XMLRPC-CLIENT" ->xmlrpc_client</A -></DT -><DT -><A -HREF="xmlrpcmsg.html" ->xmlrpcmsg</A -></DT -><DT -><A -HREF="xmlrpcresp.html" ->xmlrpcresp</A -></DT -><DT -><A -HREF="xmlrpcval.html" ->xmlrpcval</A -></DT -><DT -><A -HREF="xmlrpc-server.html" ->xmlrpc_server</A -></DT -></DL -></DIV -><DIV -CLASS="SECT1" -><H1 -CLASS="SECT1" -><A -NAME="XMLRPC-CLIENT" -></A ->xmlrpc_client</H1 -><P ->This is the basic class used to represent a client of an - XML-RPC server.</P -><DIV -CLASS="SECT2" -><H2 -CLASS="SECT2" -><A -NAME="AEN174" -></A ->Creation</H2 -><P ->The constructor has the following syntax:</P -><DIV -CLASS="FUNCSYNOPSIS" -><A -NAME="AEN177" -></A -><P -></P -><P -><CODE -><CODE -CLASS="FUNCDEF" ->$client=new xmlrpc_client</CODE ->($server_path, $server_hostname, $server_port);</CODE -></P -><P -></P -></DIV -><P ->Here's an example client set up to query Userland's XML-RPC - server at <SPAN -CLASS="emphasis" -><I -CLASS="EMPHASIS" ->betty.userland.com</I -></SPAN ->:</P -><PRE -CLASS="PROGRAMLISTING" ->$client=new xmlrpc_client("/RPC2", "betty.userland.com", 80);</PRE -><P ->The <TT -CLASS="PARAMETER" -><I ->server_port</I -></TT -> parameter is - optional, and if omitted will default to 80 when using - HTTP and 443 when using HTTPS (see the "send" method below.)</P -></DIV -><DIV -CLASS="SECT2" -><H2 -CLASS="SECT2" -><A -NAME="AEN191" -></A ->Methods</H2 -><P ->This class supports the following methods.</P -><DIV -CLASS="SECT3" -><H3 -CLASS="SECT3" -><A -NAME="XMLRPC-CLIENT-SEND" -></A ->send</H3 -><P ->This method takes the form:</P -><DIV -CLASS="FUNCSYNOPSIS" -><A -NAME="AEN197" -></A -><P -></P -><P -><CODE -><CODE -CLASS="FUNCDEF" ->$response=$client->send</CODE ->($xmlrpc_message, $timeout, $server_method);</CODE -></P -><P -></P -></DIV -><P ->Where <TT -CLASS="PARAMETER" -><I ->$xmlrpc_message</I -></TT -> is an - instance of <TT -CLASS="CLASSNAME" ->xmlrpcmsg</TT -> (see <A -HREF="xmlrpcmsg.html" ->xmlrpcmsg</A ->), and - <TT -CLASS="PARAMETER" -><I ->$response</I -></TT -> is an - instance of <TT -CLASS="CLASSNAME" ->xmlrpcresp</TT -> (see <A -HREF="xmlrpcresp.html" ->xmlrpcresp</A ->).</P -><P ->The <TT -CLASS="PARAMETER" -><I ->$timeout</I -></TT -> is optional, and - will be set to <TT -CLASS="LITERAL" ->0</TT -> (wait forever) if - omitted. This timeout value is passed to - <TT -CLASS="FUNCTION" ->fsockopen()</TT ->.</P -><P ->The <TT -CLASS="PARAMETER" -><I ->server_method</I -></TT -> parameter is - optional, and if omitted will default to 'http'. The only - other valid value is 'https', which will use an SSL HTTP - connection to connect to the remote server. Note that your - PHP must have the "curl" extensions compiled in in order to - use this feature. Note that when using SSL you should - normally set your port number to 443, unless the SSL server - you are contacting runs at any other port.</P -><DIV -CLASS="WARNING" -><P -></P -><TABLE -CLASS="WARNING" -BORDER="1" -WIDTH="100%" -><TR -><TD -ALIGN="CENTER" -><B ->Warning</B -></TD -></TR -><TR -><TD -ALIGN="LEFT" -><P ->PHP 4.0.2 or greater is required for SSL - functionality. - PHP 4.0.6 has a bug which prevents SSL - working.</P -></TD -></TR -></TABLE -></DIV -><P ->If the value of <TT -CLASS="PARAMETER" -><I ->$response</I -></TT -> is - <TT -CLASS="LITERAL" ->0</TT -> rather than an - <TT -CLASS="CLASSNAME" ->xmlrpcresp</TT -> object, then this - signifies an I/O error has occured. You can find out what - the I/O error was from the values - <TT -CLASS="FUNCTION" ->$client->errno</TT -> and - <TT -CLASS="FUNCTION" ->$client->errstring</TT ->. - </P -><P ->In addition to low-level errors, the XML-RPC server you - were querying may return an error in the - <TT -CLASS="CLASSNAME" ->xmlrpcresp</TT -> object. See <A -HREF="xmlrpcresp.html" ->xmlrpcresp</A -> for details of - how to handle these errors. - </P -></DIV -><DIV -CLASS="SECT3" -><H3 -CLASS="SECT3" -><A -NAME="AEN230" -></A ->setCredentials</H3 -><DIV -CLASS="FUNCSYNOPSIS" -><A -NAME="AEN232" -></A -><P -></P -><P -><CODE -><CODE -CLASS="FUNCDEF" ->$client->setCredentials</CODE ->($username, $password);</CODE -></P -><P -></P -></DIV -><P ->This method sets the username and password for authorizing the - client to a server. With the default (HTTP) transport, this - information is used for HTTP Basic authorization. - - </P -></DIV -><DIV -CLASS="SECT3" -><H3 -CLASS="SECT3" -><A -NAME="AEN240" -></A ->setCertificate</H3 -><DIV -CLASS="FUNCSYNOPSIS" -><A -NAME="AEN242" -></A -><P -></P -><P -><CODE -><CODE -CLASS="FUNCDEF" ->$client->setCertificate</CODE ->($certificate, $passphrase);</CODE -></P -><P -></P -></DIV -><P ->This method sets the optional certificate and passphrase - used in SSL-enabled communication with a remote server - (when the <TT -CLASS="PARAMETER" -><I ->server_method</I -></TT -> is set to - 'https' in the client's construction). - </P -><P ->The <TT -CLASS="PARAMETER" -><I ->certificate</I -></TT -> parameter must - be the filename of a PEM formatted certificate. The - <TT -CLASS="PARAMETER" -><I ->passphrase</I -></TT -> parameter must contain - the password required to use the certificate.</P -><P ->This requires the "curl" extensions to be compiled - into your installation of PHP.</P -></DIV -><DIV -CLASS="SECT3" -><H3 -CLASS="SECT3" -><A -NAME="AEN255" -></A ->setSSLVerifyPeer</H3 -><DIV -CLASS="FUNCSYNOPSIS" -><A -NAME="AEN257" -></A -><P -></P -><P -><CODE -><CODE -CLASS="FUNCDEF" ->$client->setSSLVerifyPeer</CODE ->($i);</CODE -></P -><P -></P -></DIV -><P ->This method defines whether connections made to XMLRPC - backends via HTTPS should verify the remote host's SSL - certificate, and cause the connection to fail if the cert - verification fails. $i should be a boolean value. - </P -></DIV -><DIV -CLASS="SECT3" -><H3 -CLASS="SECT3" -><A -NAME="AEN263" -></A ->setSSLVerifyHost</H3 -><DIV -CLASS="FUNCSYNOPSIS" -><A -NAME="AEN265" -></A -><P -></P -><P -><CODE -><CODE -CLASS="FUNCDEF" ->$client->setSSLVerifyHost</CODE ->($i);</CODE -></P -><P -></P -></DIV -><P ->This method defines whether connections made to XMLRPC - backends via HTTPS should verify the remote host's SSL - certificate's common name (CN). By default, only the existence - of a CN is checked. $i should be an integer value; 0 to not - check the CN at all, 1 to merely check for its existence, and - 2 to check that the CN on the certificate matches the hostname - that is being connected to. - </P -></DIV -><DIV -CLASS="SECT3" -><H3 -CLASS="SECT3" -><A -NAME="AEN271" -></A ->setDebug</H3 -><DIV -CLASS="FUNCSYNOPSIS" -><A -NAME="AEN273" -></A -><P -></P -><P -><CODE -><CODE -CLASS="FUNCDEF" ->$client->setDebug</CODE ->($debugOn);</CODE -></P -><P -></P -></DIV -><P -><TT -CLASS="PARAMETER" -><I ->$debugOn</I -></TT -> is either - <TT -CLASS="LITERAL" ->0</TT -> or <TT -CLASS="LITERAL" ->1</TT -> depending on - whether you require the client to print debugging - information to the browser. The default is not to output - this information.</P -><P -> The debugging information includes the raw data returned - from the XML-RPC server it was querying, and the PHP value - the client attempts to create to represent the value - returned by the server. This option can be very useful when - debugging servers as it allows you to see exactly what the - server returns. - </P -></DIV -></DIV -></DIV -></DIV -><DIV -CLASS="NAVFOOTER" -><HR -ALIGN="LEFT" -WIDTH="100%"><TABLE -SUMMARY="Footer navigation table" -WIDTH="100%" -BORDER="0" -CELLPADDING="0" -CELLSPACING="0" -><TR -><TD -WIDTH="33%" -ALIGN="left" -VALIGN="top" -><A -HREF="jellyfish.html" -ACCESSKEY="P" ->Prev</A -></TD -><TD -WIDTH="34%" -ALIGN="center" -VALIGN="top" -><A -HREF="index.html" -ACCESSKEY="H" ->Home</A -></TD -><TD -WIDTH="33%" -ALIGN="right" -VALIGN="top" -><A -HREF="xmlrpcmsg.html" -ACCESSKEY="N" ->Next</A -></TD -></TR -><TR -><TD -WIDTH="33%" -ALIGN="left" -VALIGN="top" ->The Jellyfish Book</TD -><TD -WIDTH="34%" -ALIGN="center" -VALIGN="top" -> </TD -><TD -WIDTH="33%" -ALIGN="right" -VALIGN="top" ->xmlrpcmsg</TD -></TR -></TABLE -></DIV -></BODY -></HTML ->
\ No newline at end of file diff --git a/modules/xmlrpc/doc/arrayuse.html b/modules/xmlrpc/doc/arrayuse.html deleted file mode 100644 index e8011ed4..00000000 --- a/modules/xmlrpc/doc/arrayuse.html +++ /dev/null @@ -1,253 +0,0 @@ -<HTML -><HEAD -><TITLE ->Easy use with PHP arrays</TITLE -><META -NAME="GENERATOR" -CONTENT="Modular DocBook HTML Stylesheet Version 1.77+"><LINK -REV="MADE" -HREF="edd@usefulinc.com"><LINK -REL="HOME" -TITLE="XML-RPC for PHP" -HREF="index.html"><LINK -REL="UP" -TITLE="Helper functions" -HREF="helpers.html"><LINK -REL="PREVIOUS" -TITLE="Helper functions" -HREF="helpers.html"><LINK -REL="NEXT" -TITLE="Debugging aids" -HREF="debugging.html"></HEAD -><BODY -CLASS="SECT1" -BGCOLOR="#FFFFFF" -TEXT="#000000" -LINK="#0000FF" -VLINK="#840084" -ALINK="#0000FF" -><DIV -CLASS="NAVHEADER" -><TABLE -SUMMARY="Header navigation table" -WIDTH="100%" -BORDER="0" -CELLPADDING="0" -CELLSPACING="0" -><TR -><TH -COLSPAN="3" -ALIGN="center" ->XML-RPC for PHP: version 1.1</TH -></TR -><TR -><TD -WIDTH="10%" -ALIGN="left" -VALIGN="bottom" -><A -HREF="helpers.html" -ACCESSKEY="P" ->Prev</A -></TD -><TD -WIDTH="80%" -ALIGN="center" -VALIGN="bottom" ->Chapter 6. Helper functions</TD -><TD -WIDTH="10%" -ALIGN="right" -VALIGN="bottom" -><A -HREF="debugging.html" -ACCESSKEY="N" ->Next</A -></TD -></TR -></TABLE -><HR -ALIGN="LEFT" -WIDTH="100%"></DIV -><DIV -CLASS="SECT1" -><H1 -CLASS="SECT1" -><A -NAME="ARRAYUSE" -></A ->Easy use with PHP arrays</H1 -><P ->Dan Libby was kind enough to contribute two helper functions - that make it easier to translate to and from PHP arrays. This - makes it easier to deal with complex structures. At the moment - support is limited to <SPAN -CLASS="TYPE" ->int</SPAN ->, <SPAN -CLASS="TYPE" ->double</SPAN ->, - <SPAN -CLASS="TYPE" ->string</SPAN ->, <SPAN -CLASS="TYPE" ->array</SPAN -> and <SPAN -CLASS="TYPE" ->struct</SPAN -> - datatypes; note also that all PHP arrays are encoded as structs - due to PHP not being able to tell the difference between a hash - and a linear array.</P -><P ->These functions reside in <TT -CLASS="FILENAME" ->xmlrpc.inc</TT ->.</P -><DIV -CLASS="SECT2" -><H2 -CLASS="SECT2" -><A -NAME="XMLRPCDECODE" -></A ->xmlrpc_decode</H2 -><DIV -CLASS="FUNCSYNOPSIS" -><A -NAME="AEN791" -></A -><P -></P -><P -><CODE -><CODE -CLASS="FUNCDEF" ->$arr=xmlrpc_decode</CODE ->($xmlrpc_val);</CODE -></P -><P -></P -></DIV -><P -> Returns a PHP array stuffed with the values found in the - <SPAN -CLASS="TYPE" ->xmlrpcval</SPAN -> <TT -CLASS="PARAMETER" -><I ->$xmlrpc_val</I -></TT ->, - translated into native PHP types. - </P -></DIV -><DIV -CLASS="SECT2" -><H2 -CLASS="SECT2" -><A -NAME="XMLRPCENCODE" -></A ->xmlrpc_encode</H2 -><DIV -CLASS="FUNCSYNOPSIS" -><A -NAME="AEN801" -></A -><P -></P -><P -><CODE -><CODE -CLASS="FUNCDEF" ->$xmlrpc_val=xmlrpc_encode</CODE ->($phpval);</CODE -></P -><P -></P -></DIV -><P -> Returns an <SPAN -CLASS="TYPE" ->xmlrpcval</SPAN -> populated with the PHP - values in <TT -CLASS="PARAMETER" -><I ->$phpval</I -></TT ->. Works recursively on - arrays and structs. Note that there's no support for non-base - types like base-64 values or date-times. - </P -></DIV -></DIV -><DIV -CLASS="NAVFOOTER" -><HR -ALIGN="LEFT" -WIDTH="100%"><TABLE -SUMMARY="Footer navigation table" -WIDTH="100%" -BORDER="0" -CELLPADDING="0" -CELLSPACING="0" -><TR -><TD -WIDTH="33%" -ALIGN="left" -VALIGN="top" -><A -HREF="helpers.html" -ACCESSKEY="P" ->Prev</A -></TD -><TD -WIDTH="34%" -ALIGN="center" -VALIGN="top" -><A -HREF="index.html" -ACCESSKEY="H" ->Home</A -></TD -><TD -WIDTH="33%" -ALIGN="right" -VALIGN="top" -><A -HREF="debugging.html" -ACCESSKEY="N" ->Next</A -></TD -></TR -><TR -><TD -WIDTH="33%" -ALIGN="left" -VALIGN="top" ->Helper functions</TD -><TD -WIDTH="34%" -ALIGN="center" -VALIGN="top" -><A -HREF="helpers.html" -ACCESSKEY="U" ->Up</A -></TD -><TD -WIDTH="33%" -ALIGN="right" -VALIGN="top" ->Debugging aids</TD -></TR -></TABLE -></DIV -></BODY -></HTML ->
\ No newline at end of file diff --git a/modules/xmlrpc/doc/bugs.html b/modules/xmlrpc/doc/bugs.html deleted file mode 100644 index be925b65..00000000 --- a/modules/xmlrpc/doc/bugs.html +++ /dev/null @@ -1,159 +0,0 @@ -<HTML -><HEAD -><TITLE ->Bugs</TITLE -><META -NAME="GENERATOR" -CONTENT="Modular DocBook HTML Stylesheet Version 1.77+"><LINK -REV="MADE" -HREF="edd@usefulinc.com"><LINK -REL="HOME" -TITLE="XML-RPC for PHP" -HREF="index.html"><LINK -REL="PREVIOUS" -TITLE="Files in the distribution" -HREF="manifest.html"><LINK -REL="NEXT" -TITLE="Support" -HREF="support.html"></HEAD -><BODY -CLASS="CHAPTER" -BGCOLOR="#FFFFFF" -TEXT="#000000" -LINK="#0000FF" -VLINK="#840084" -ALINK="#0000FF" -><DIV -CLASS="NAVHEADER" -><TABLE -SUMMARY="Header navigation table" -WIDTH="100%" -BORDER="0" -CELLPADDING="0" -CELLSPACING="0" -><TR -><TH -COLSPAN="3" -ALIGN="center" ->XML-RPC for PHP: version 1.1</TH -></TR -><TR -><TD -WIDTH="10%" -ALIGN="left" -VALIGN="bottom" -><A -HREF="manifest.html" -ACCESSKEY="P" ->Prev</A -></TD -><TD -WIDTH="80%" -ALIGN="center" -VALIGN="bottom" -></TD -><TD -WIDTH="10%" -ALIGN="right" -VALIGN="bottom" -><A -HREF="support.html" -ACCESSKEY="N" ->Next</A -></TD -></TR -></TABLE -><HR -ALIGN="LEFT" -WIDTH="100%"></DIV -><DIV -CLASS="CHAPTER" -><H1 -><A -NAME="BUGS" -></A ->Chapter 3. Bugs</H1 -><P ->This is a bare framework. The "nice" bits haven't been put in - yet. Specifically, no HTTP response checking is performed, and no type - validation or coercion has been put in. PHP being a loosely-typed - language, this is going to have to be done explicitly.</P -><P ->dateTime.iso8601 is supported opaquely. It can't be done - natively as the XML-RPC specification explictly forbids passing of - timezone specifiers in ISO8601 format dates. You can, however, use - the <A -HREF="helpers.html#ISO8601ENCODE" ->iso8601_encode()</A -> and <A -HREF="helpers.html#ISO8601DECODE" ->iso8601_decode()</A -> functions to do the encoding and decoding for you.</P -><P ->If alternative character set encoding is sent in HTTP header - than it will be ignored for the moment. We speak only UTF-8...</P -><P ->If more than 32k of HTTP headers are encountered (like, why?) then the - response parsing code will break.</P -></DIV -><DIV -CLASS="NAVFOOTER" -><HR -ALIGN="LEFT" -WIDTH="100%"><TABLE -SUMMARY="Footer navigation table" -WIDTH="100%" -BORDER="0" -CELLPADDING="0" -CELLSPACING="0" -><TR -><TD -WIDTH="33%" -ALIGN="left" -VALIGN="top" -><A -HREF="manifest.html" -ACCESSKEY="P" ->Prev</A -></TD -><TD -WIDTH="34%" -ALIGN="center" -VALIGN="top" -><A -HREF="index.html" -ACCESSKEY="H" ->Home</A -></TD -><TD -WIDTH="33%" -ALIGN="right" -VALIGN="top" -><A -HREF="support.html" -ACCESSKEY="N" ->Next</A -></TD -></TR -><TR -><TD -WIDTH="33%" -ALIGN="left" -VALIGN="top" ->Files in the distribution</TD -><TD -WIDTH="34%" -ALIGN="center" -VALIGN="top" -> </TD -><TD -WIDTH="33%" -ALIGN="right" -VALIGN="top" ->Support</TD -></TR -></TABLE -></DIV -></BODY -></HTML ->
\ No newline at end of file diff --git a/modules/xmlrpc/doc/custom.dsl b/modules/xmlrpc/doc/custom.dsl deleted file mode 100644 index 24d4b4bf..00000000 --- a/modules/xmlrpc/doc/custom.dsl +++ /dev/null @@ -1,25 +0,0 @@ -<!DOCTYPE style-sheet PUBLIC "-//James Clark//DTD DSSSL Style Sheet//EN" [ -<!ENTITY dbstyle SYSTEM "/usr/lib/sgml/stylesheet/dsssl/docbook/nwalsh/html/docbook.dsl" CDATA DSSSL> -]> - -<style-sheet> -<style-specification use="docbook"> -<style-specification-body> - -(define %link-mailto-url% - "edd@usefulinc.com") - -(define %html-ext% - ".html") - -(define %use-id-as-filename% - #t) - -(define %root-filename% - "index") - - -</style-specification-body> -</style-specification> -<external-specification id="docbook" document="dbstyle"> -</style-sheet> diff --git a/modules/xmlrpc/doc/debugging.html b/modules/xmlrpc/doc/debugging.html deleted file mode 100644 index 7a0e567b..00000000 --- a/modules/xmlrpc/doc/debugging.html +++ /dev/null @@ -1,188 +0,0 @@ -<HTML -><HEAD -><TITLE ->Debugging aids</TITLE -><META -NAME="GENERATOR" -CONTENT="Modular DocBook HTML Stylesheet Version 1.77+"><LINK -REV="MADE" -HREF="edd@usefulinc.com"><LINK -REL="HOME" -TITLE="XML-RPC for PHP" -HREF="index.html"><LINK -REL="UP" -TITLE="Helper functions" -HREF="helpers.html"><LINK -REL="PREVIOUS" -TITLE="Easy use with PHP arrays" -HREF="arrayuse.html"><LINK -REL="NEXT" -TITLE="Reserved methods" -HREF="reserved.html"></HEAD -><BODY -CLASS="SECT1" -BGCOLOR="#FFFFFF" -TEXT="#000000" -LINK="#0000FF" -VLINK="#840084" -ALINK="#0000FF" -><DIV -CLASS="NAVHEADER" -><TABLE -SUMMARY="Header navigation table" -WIDTH="100%" -BORDER="0" -CELLPADDING="0" -CELLSPACING="0" -><TR -><TH -COLSPAN="3" -ALIGN="center" ->XML-RPC for PHP: version 1.1</TH -></TR -><TR -><TD -WIDTH="10%" -ALIGN="left" -VALIGN="bottom" -><A -HREF="arrayuse.html" -ACCESSKEY="P" ->Prev</A -></TD -><TD -WIDTH="80%" -ALIGN="center" -VALIGN="bottom" ->Chapter 6. Helper functions</TD -><TD -WIDTH="10%" -ALIGN="right" -VALIGN="bottom" -><A -HREF="reserved.html" -ACCESSKEY="N" ->Next</A -></TD -></TR -></TABLE -><HR -ALIGN="LEFT" -WIDTH="100%"></DIV -><DIV -CLASS="SECT1" -><H1 -CLASS="SECT1" -><A -NAME="DEBUGGING" -></A ->Debugging aids</H1 -><DIV -CLASS="SECT2" -><H2 -CLASS="SECT2" -><A -NAME="AEN811" -></A ->xmlrpc_debugmsg</H2 -><DIV -CLASS="FUNCSYNOPSIS" -><A -NAME="AEN813" -></A -><P -></P -><P -><CODE -><CODE -CLASS="FUNCDEF" ->xmlrpc_debugmsg</CODE ->($debugstring);</CODE -></P -><P -></P -></DIV -><P ->Sends the contents of <TT -CLASS="PARAMETER" -><I ->$debugstring</I -></TT -> - in XML comments in the server return payload. If a PHP client - has debugging turned on, the user will be able to see server - debug information.</P -><P ->Use this function in your methods so you can pass back - diagnostic information. It is only available from - <TT -CLASS="FILENAME" ->xmlrpcs.inc</TT ->.</P -></DIV -></DIV -><DIV -CLASS="NAVFOOTER" -><HR -ALIGN="LEFT" -WIDTH="100%"><TABLE -SUMMARY="Footer navigation table" -WIDTH="100%" -BORDER="0" -CELLPADDING="0" -CELLSPACING="0" -><TR -><TD -WIDTH="33%" -ALIGN="left" -VALIGN="top" -><A -HREF="arrayuse.html" -ACCESSKEY="P" ->Prev</A -></TD -><TD -WIDTH="34%" -ALIGN="center" -VALIGN="top" -><A -HREF="index.html" -ACCESSKEY="H" ->Home</A -></TD -><TD -WIDTH="33%" -ALIGN="right" -VALIGN="top" -><A -HREF="reserved.html" -ACCESSKEY="N" ->Next</A -></TD -></TR -><TR -><TD -WIDTH="33%" -ALIGN="left" -VALIGN="top" ->Easy use with PHP arrays</TD -><TD -WIDTH="34%" -ALIGN="center" -VALIGN="top" -><A -HREF="helpers.html" -ACCESSKEY="U" ->Up</A -></TD -><TD -WIDTH="33%" -ALIGN="right" -VALIGN="top" ->Reserved methods</TD -></TR -></TABLE -></DIV -></BODY -></HTML ->
\ No newline at end of file diff --git a/modules/xmlrpc/doc/examples.html b/modules/xmlrpc/doc/examples.html deleted file mode 100644 index e8d44415..00000000 --- a/modules/xmlrpc/doc/examples.html +++ /dev/null @@ -1,159 +0,0 @@ -<HTML -><HEAD -><TITLE ->Examples</TITLE -><META -NAME="GENERATOR" -CONTENT="Modular DocBook HTML Stylesheet Version 1.77+"><LINK -REV="MADE" -HREF="edd@usefulinc.com"><LINK -REL="HOME" -TITLE="XML-RPC for PHP" -HREF="index.html"><LINK -REL="PREVIOUS" -TITLE="system.methodHelp" -HREF="sysmethhelp.html"></HEAD -><BODY -CLASS="CHAPTER" -BGCOLOR="#FFFFFF" -TEXT="#000000" -LINK="#0000FF" -VLINK="#840084" -ALINK="#0000FF" -><DIV -CLASS="NAVHEADER" -><TABLE -SUMMARY="Header navigation table" -WIDTH="100%" -BORDER="0" -CELLPADDING="0" -CELLSPACING="0" -><TR -><TH -COLSPAN="3" -ALIGN="center" ->XML-RPC for PHP: version 1.1</TH -></TR -><TR -><TD -WIDTH="10%" -ALIGN="left" -VALIGN="bottom" -><A -HREF="sysmethhelp.html" -ACCESSKEY="P" ->Prev</A -></TD -><TD -WIDTH="80%" -ALIGN="center" -VALIGN="bottom" -></TD -><TD -WIDTH="10%" -ALIGN="right" -VALIGN="bottom" -> </TD -></TR -></TABLE -><HR -ALIGN="LEFT" -WIDTH="100%"></DIV -><DIV -CLASS="CHAPTER" -><H1 -><A -NAME="EXAMPLES" -></A ->Chapter 8. Examples</H1 -><P ->The best examples are to be found in the sample files - included with the distribution. Some are included here.</P -><DIV -CLASS="SECT1" -><H1 -CLASS="SECT1" -><A -NAME="STATENAME" -></A ->XML-RPC client: state name query</H1 -><P ->Code to get the corresponding - state name from a number (1-50) from Dave Winer's server</P -><PRE -CLASS="PROGRAMLISTING" -> $f=new xmlrpcmsg('examples.getStateName', - array(new xmlrpcval($HTTP_POST_VARS["stateno"], "int"))); - $c=new xmlrpc_client("/RPC2", "betty.userland.com", 80); - $r=$c->send($f); - $v=$r->value(); - if (!$r->faultCode()) { - print "State number ". $HTTP_POST_VARS["stateno"] . " is " . - $v->scalarval() . "<BR>"; - print "<HR>I got this value back<BR><PRE>" . - htmlentities($r->serialize()). "</PRE><HR>\n"; - } else { - print "Fault: "; - print "Code: " . $r->faultCode() . - " Reason '" .$r->faultString()."'<BR>"; - } - </PRE -></DIV -></DIV -><DIV -CLASS="NAVFOOTER" -><HR -ALIGN="LEFT" -WIDTH="100%"><TABLE -SUMMARY="Footer navigation table" -WIDTH="100%" -BORDER="0" -CELLPADDING="0" -CELLSPACING="0" -><TR -><TD -WIDTH="33%" -ALIGN="left" -VALIGN="top" -><A -HREF="sysmethhelp.html" -ACCESSKEY="P" ->Prev</A -></TD -><TD -WIDTH="34%" -ALIGN="center" -VALIGN="top" -><A -HREF="index.html" -ACCESSKEY="H" ->Home</A -></TD -><TD -WIDTH="33%" -ALIGN="right" -VALIGN="top" -> </TD -></TR -><TR -><TD -WIDTH="33%" -ALIGN="left" -VALIGN="top" ->system.methodHelp</TD -><TD -WIDTH="34%" -ALIGN="center" -VALIGN="top" -> </TD -><TD -WIDTH="33%" -ALIGN="right" -VALIGN="top" -> </TD -></TR -></TABLE -></DIV -></BODY -></HTML ->
\ No newline at end of file diff --git a/modules/xmlrpc/doc/helpers.html b/modules/xmlrpc/doc/helpers.html deleted file mode 100644 index 4f0c1319..00000000 --- a/modules/xmlrpc/doc/helpers.html +++ /dev/null @@ -1,318 +0,0 @@ -<HTML -><HEAD -><TITLE ->Helper functions</TITLE -><META -NAME="GENERATOR" -CONTENT="Modular DocBook HTML Stylesheet Version 1.77+"><LINK -REV="MADE" -HREF="edd@usefulinc.com"><LINK -REL="HOME" -TITLE="XML-RPC for PHP" -HREF="index.html"><LINK -REL="PREVIOUS" -TITLE="xmlrpc_server" -HREF="xmlrpc-server.html"><LINK -REL="NEXT" -TITLE="Easy use with PHP arrays" -HREF="arrayuse.html"></HEAD -><BODY -CLASS="CHAPTER" -BGCOLOR="#FFFFFF" -TEXT="#000000" -LINK="#0000FF" -VLINK="#840084" -ALINK="#0000FF" -><DIV -CLASS="NAVHEADER" -><TABLE -SUMMARY="Header navigation table" -WIDTH="100%" -BORDER="0" -CELLPADDING="0" -CELLSPACING="0" -><TR -><TH -COLSPAN="3" -ALIGN="center" ->XML-RPC for PHP: version 1.1</TH -></TR -><TR -><TD -WIDTH="10%" -ALIGN="left" -VALIGN="bottom" -><A -HREF="xmlrpc-server.html" -ACCESSKEY="P" ->Prev</A -></TD -><TD -WIDTH="80%" -ALIGN="center" -VALIGN="bottom" -></TD -><TD -WIDTH="10%" -ALIGN="right" -VALIGN="bottom" -><A -HREF="arrayuse.html" -ACCESSKEY="N" ->Next</A -></TD -></TR -></TABLE -><HR -ALIGN="LEFT" -WIDTH="100%"></DIV -><DIV -CLASS="CHAPTER" -><H1 -><A -NAME="HELPERS" -></A ->Chapter 6. Helper functions</H1 -><DIV -CLASS="TOC" -><DL -><DT -><B ->Table of Contents</B -></DT -><DT -><A -HREF="helpers.html#AEN739" ->Date functions</A -></DT -><DT -><A -HREF="arrayuse.html" ->Easy use with PHP arrays</A -></DT -><DT -><A -HREF="debugging.html" ->Debugging aids</A -></DT -></DL -></DIV -><P ->XML-RPC for PHP contains some helper functions which you can - use to make processing of XML-RPC requests easier.</P -><DIV -CLASS="SECT1" -><H1 -CLASS="SECT1" -><A -NAME="AEN739" -></A ->Date functions</H1 -><P ->The XML-RPC specification has this to say on dates:</P -><A -NAME="AEN742" -></A -><BLOCKQUOTE -CLASS="BLOCKQUOTE" -><P ->Don't assume a timezone. It should be specified by the server in its - documentation what assumptions it makes about timezones. </P -></BLOCKQUOTE -><P ->Unfortunately, this means that date processing isn't - straightforward. Although XML-RPC uses ISO 8601 format dates, it - doesn't use the timezone specifier.</P -><P ->We strongly recommend that in every case where you pass - dates in XML-RPC calls, you use UTC (GMT) as your timezone. Most computer - languages include routines for handling GMT times natively, and - you won't have to translate between timezones.</P -><P ->For more information about dates, see <A -HREF="http://www.uic.edu/year2000/datefmt.html" -TARGET="_top" ->ISO 8601: The Right Format for Dates</A ->, which has a handy link to a PDF of the ISO 8601 specification. Note that XML-RPC uses exactly one of the available representations: CCYYMMDDTHH:MM:SS.</P -><DIV -CLASS="SECT2" -><H2 -CLASS="SECT2" -><A -NAME="ISO8601ENCODE" -></A ->iso8601_encode</H2 -><DIV -CLASS="FUNCSYNOPSIS" -><A -NAME="AEN750" -></A -><P -></P -><P -><CODE -><CODE -CLASS="FUNCDEF" ->$isoString=iso8601_encode</CODE ->($time_t, $utc=0);</CODE -></P -><P -></P -></DIV -><P ->Returns an ISO 8601 formatted date generated from the - UNIX timestamp <TT -CLASS="PARAMETER" -><I ->$time_t</I -></TT ->, as returned by - the PHP function <TT -CLASS="FUNCTION" ->time()</TT ->. </P -><P ->The argument <TT -CLASS="PARAMETER" -><I ->$utc</I -></TT -> can be omitted, - in which case it defaults to <TT -CLASS="LITERAL" ->0</TT ->. If it is - set to <TT -CLASS="LITERAL" ->1</TT ->, then the function corrects the - time passed in for UTC. Example: if you're in the GMT-6:00 - timezone and set <TT -CLASS="PARAMETER" -><I ->$utc</I -></TT ->, you will receive - a date representation six hours ahead of your local - time.</P -><P ->The included demo program <TT -CLASS="FILENAME" ->vardemo.php</TT -> - includes a demonstration of this function.</P -></DIV -><DIV -CLASS="SECT2" -><H2 -CLASS="SECT2" -><A -NAME="ISO8601DECODE" -></A ->iso8601_decode</H2 -><DIV -CLASS="FUNCSYNOPSIS" -><A -NAME="AEN768" -></A -><P -></P -><P -><CODE -><CODE -CLASS="FUNCDEF" ->$time_t=iso8601_decode</CODE ->($isoString, $utc=0);</CODE -></P -><P -></P -></DIV -><P ->Returns a UNIX timestamp from an ISO 8601 encoded time and - date string passed in. If <TT -CLASS="PARAMETER" -><I ->$utc</I -></TT -> is - <TT -CLASS="LITERAL" ->1</TT -> then <TT -CLASS="PARAMETER" -><I ->$isoString</I -></TT -> is - assumed to be in the UTC timezone, and thus the - <TT -CLASS="PARAMETER" -><I ->$time_t</I -></TT -> result is also UTC: otherwise, - the timezone is assumed to be your local timezone and you receive a local timestamp.</P -></DIV -></DIV -></DIV -><DIV -CLASS="NAVFOOTER" -><HR -ALIGN="LEFT" -WIDTH="100%"><TABLE -SUMMARY="Footer navigation table" -WIDTH="100%" -BORDER="0" -CELLPADDING="0" -CELLSPACING="0" -><TR -><TD -WIDTH="33%" -ALIGN="left" -VALIGN="top" -><A -HREF="xmlrpc-server.html" -ACCESSKEY="P" ->Prev</A -></TD -><TD -WIDTH="34%" -ALIGN="center" -VALIGN="top" -><A -HREF="index.html" -ACCESSKEY="H" ->Home</A -></TD -><TD -WIDTH="33%" -ALIGN="right" -VALIGN="top" -><A -HREF="arrayuse.html" -ACCESSKEY="N" ->Next</A -></TD -></TR -><TR -><TD -WIDTH="33%" -ALIGN="left" -VALIGN="top" ->xmlrpc_server</TD -><TD -WIDTH="34%" -ALIGN="center" -VALIGN="top" -> </TD -><TD -WIDTH="33%" -ALIGN="right" -VALIGN="top" ->Easy use with PHP arrays</TD -></TR -></TABLE -></DIV -></BODY -></HTML ->
\ No newline at end of file diff --git a/modules/xmlrpc/doc/index.html b/modules/xmlrpc/doc/index.html deleted file mode 100644 index f2cb5762..00000000 --- a/modules/xmlrpc/doc/index.html +++ /dev/null @@ -1,6 +0,0 @@ -<html><head> - <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> - <title>XML-RPC for PHP</title><link rel="stylesheet" href="html.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.67.0"><link rel="start" href="index.html" title="XML-RPC for PHP"><link rel="next" href="ch01.html" title="Chapter 1. Introduction"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">XML-RPC for PHP</th></tr><tr><td width="20%" align="left"> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="ch01.html">Next</a></td></tr></table><hr></div><div class="book" lang="en"><div class="titlepage"><div><div><h1 class="title"><a name="d0e1"></a>XML-RPC for PHP</h1></div><div><h2 class="subtitle">version 1.1</h2></div><div><div class="authorgroup"><div class="author"><h3 class="author"><span class="firstname">Edd</span> <span class="surname">Dumbill</span></h3><div class="affiliation"><span class="orgname"><a href="http://usefulinc.com/" target="_top">Useful Information Company</a><br></span><div class="address"><p><br> - <code class="email"><<a href="mailto:edd@usefulinc.com">edd@usefulinc.com</a>></code><br> - </p></div></div></div></div></div><div><p class="copyright">Copyright © 1999,2000,2001 Edd Dumbill, Useful Information Company</p></div><div><div class="legalnotice"><a name="d0e29"></a><p>All rights reserved.</p><p>Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:</p><div class="itemizedlist"><ul type="disc"><li><p>Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.</p></li><li><p>Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.</p></li><li><p>Neither the name of the "XML-RPC for PHP" nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.</p></li></ul></div><p>THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</p></div></div></div><hr></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="chapter"><a href="ch01.html">1. Introduction</a></span></dt><dd><dl><dt><span class="sect1"><a href="ch01s01.html">1. Acknowledgements</a></span></dt></dl></dd><dt><span class="chapter"><a href="ch02.html">2. Files in the distribution</a></span></dt><dt><span class="chapter"><a href="ch03.html">3. Known bugs</a></span></dt><dt><span class="chapter"><a href="ch04.html">4. Support</a></span></dt><dd><dl><dt><span class="sect1"><a href="ch04s01.html">1. Online Support</a></span></dt><dt><span class="sect1"><a href="ch04s02.html">2. The Jellyfish Book</a></span></dt></dl></dd><dt><span class="chapter"><a href="ch05.html">5. Class documentation</a></span></dt><dd><dl><dt><span class="sect1"><a href="ch05s01.html">1. xmlrpc_client</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch05s01.html#d0e322">1.1. Creation</a></span></dt><dt><span class="sect2"><a href="ch05s01.html#d0e352">1.2. Methods</a></span></dt><dd><dl><dt><span class="sect3"><a href="ch05s01.html#xmlrpc-client-send">1.2.1. send</a></span></dt><dt><span class="sect3"><a href="ch05s01.html#d0e439">1.2.2. setCredentials</a></span></dt><dt><span class="sect3"><a href="ch05s01.html#d0e454">1.2.3. setCertificate</a></span></dt><dt><span class="sect3"><a href="ch05s01.html#d0e482">1.2.4. setSSLVerifyPeer</a></span></dt><dt><span class="sect3"><a href="ch05s01.html#d0e497">1.2.5. setSSLVerifyHost</a></span></dt><dt><span class="sect3"><a href="ch05s01.html#d0e512">1.2.6. setDebug</a></span></dt></dl></dd></dl></dd><dt><span class="sect1"><a href="ch05s02.html">2. xmlrpcmsg</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch05s02.html#d0e547">2.1. Creation</a></span></dt><dt><span class="sect2"><a href="ch05s02.html#d0e589">2.2. Methods</a></span></dt><dd><dl><dt><span class="sect3"><a href="ch05s02.html#d0e592">2.2.1. serialize</a></span></dt><dt><span class="sect3"><a href="ch05s02.html#d0e602">2.2.2. addParam</a></span></dt><dt><span class="sect3"><a href="ch05s02.html#d0e620">2.2.3. getParam</a></span></dt><dt><span class="sect3"><a href="ch05s02.html#d0e638">2.2.4. getNumParams</a></span></dt><dt><span class="sect3"><a href="ch05s02.html#d0e648">2.2.5. method</a></span></dt><dt><span class="sect3"><a href="ch05s02.html#d0e664">2.2.6. parseResponse</a></span></dt><dt><span class="sect3"><a href="ch05s02.html#d0e686">2.2.7. parseResponseFile</a></span></dt></dl></dd></dl></dd><dt><span class="sect1"><a href="ch05s03.html">3. xmlrpcresp</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch05s03.html#d0e722">3.1. Creation</a></span></dt><dt><span class="sect2"><a href="ch05s03.html#d0e764">3.2. Methods</a></span></dt><dd><dl><dt><span class="sect3"><a href="ch05s03.html#d0e767">3.2.1. faultCode</a></span></dt><dt><span class="sect3"><a href="ch05s03.html#d0e780">3.2.2. faultString</a></span></dt><dt><span class="sect3"><a href="ch05s03.html#d0e793">3.2.3. value</a></span></dt><dt><span class="sect3"><a href="ch05s03.html#d0e809">3.2.4. serialize</a></span></dt></dl></dd></dl></dd><dt><span class="sect1"><a href="ch05s04.html">4. xmlrpcval</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch05s04.html#d0e841">4.1. Notes on types</a></span></dt><dd><dl><dt><span class="sect3"><a href="ch05s04.html#d0e844">4.1.1. int</a></span></dt><dt><span class="sect3"><a href="ch05s04.html#d0e864">4.1.2. base64</a></span></dt><dt><span class="sect3"><a href="ch05s04.html#d0e869">4.1.3. boolean</a></span></dt><dt><span class="sect3"><a href="ch05s04.html#d0e886">4.1.4. string</a></span></dt></dl></dd><dt><span class="sect2"><a href="ch05s04.html#xmlrpcval-creation">4.2. Creation</a></span></dt><dt><span class="sect2"><a href="ch05s04.html#xmlrpcval-methods">4.3. Methods</a></span></dt><dd><dl><dt><span class="sect3"><a href="ch05s04.html#d0e980">4.3.1. addScalar</a></span></dt><dt><span class="sect3"><a href="ch05s04.html#d0e1027">4.3.2. addArray</a></span></dt><dt><span class="sect3"><a href="ch05s04.html#d0e1048">4.3.3. addStruct</a></span></dt><dt><span class="sect3"><a href="ch05s04.html#d0e1069">4.3.4. kindOf</a></span></dt><dt><span class="sect3"><a href="ch05s04.html#d0e1079">4.3.5. serialize</a></span></dt><dt><span class="sect3"><a href="ch05s04.html#d0e1089">4.3.6. scalarval</a></span></dt><dt><span class="sect3"><a href="ch05s04.html#d0e1102">4.3.7. scalartyp</a></span></dt><dt><span class="sect3"><a href="ch05s04.html#d0e1121">4.3.8. arraymem</a></span></dt><dt><span class="sect3"><a href="ch05s04.html#d0e1142">4.3.9. arraysize</a></span></dt><dt><span class="sect3"><a href="ch05s04.html#d0e1158">4.3.10. structmem</a></span></dt><dt><span class="sect3"><a href="ch05s04.html#d0e1179">4.3.11. structeach</a></span></dt><dt><span class="sect3"><a href="ch05s04.html#structreset">4.3.12. structreset</a></span></dt></dl></dd></dl></dd><dt><span class="sect1"><a href="ch05s05.html">5. xmlrpc_server</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch05s05.html#d0e1229">5.1. The dispatch map</a></span></dt><dt><span class="sect2"><a href="ch05s05.html#signatures">5.2. Method signatures</a></span></dt><dt><span class="sect2"><a href="ch05s05.html#d0e1280">5.3. Delaying the server response</a></span></dt><dt><span class="sect2"><a href="ch05s05.html#d0e1293">5.4. Fault reporting</a></span></dt></dl></dd></dl></dd><dt><span class="chapter"><a href="ch06.html">6. Global variables</a></span></dt><dd><dl><dt><span class="sect1"><a href="ch06s01.html">1. "Constant" variables</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch06s01.html#d0e1418">1.1. $xmlrpcerruser</a></span></dt><dt><span class="sect2"><a href="ch06s01.html#d0e1428">1.2. $xmlrpcI4, $xmlrpcInt, $xmlrpcDouble, $xmlrpcString, $xmlrpcDateTime, $xmlrpcBase64 -, $xmlrpcArray, $xmlrpcStruct</a></span></dt><dt><span class="sect2"><a href="ch06s01.html#d0e1435">1.3. $xmlrpcTypes, $xmlEntities, $xmlrpcerr, $xmlrpcstr, $xmlrpcerrxml, $xmlrpc_backslash, $_xh</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch06s02.html">2. Variables whose value can be modified</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch06s02.html#d0e1443">2.1. xmlrpc_defencoding</a></span></dt><dt><span class="sect2"><a href="ch06s02.html#d0e1463">2.2. xmlrpc_internalencoding</a></span></dt><dt><span class="sect2"><a href="ch06s02.html#d0e1473">2.3. xmlrpcName</a></span></dt><dt><span class="sect2"><a href="ch06s02.html#d0e1483">2.4. xmlrpcVersion</a></span></dt></dl></dd></dl></dd><dt><span class="chapter"><a href="ch07.html">7. Helper functions</a></span></dt><dd><dl><dt><span class="sect1"><a href="ch07s01.html">1. Date functions</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch07s01.html#iso8601encode">1.1. iso8601_encode</a></span></dt><dt><span class="sect2"><a href="ch07s01.html#iso8601decode">1.2. iso8601_decode</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch07s02.html">2. Easy use with PHP arrays</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch07s02.html#phpxmlrpcdecode">2.1. php_xmlrpc_decode</a></span></dt><dt><span class="sect2"><a href="ch07s02.html#phpxmlrpcencode">2.2. php_xmlrpc_encode</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch07s03.html">3. Deprecated functions</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch07s03.html#xmlrpcdecode">3.1. xmlrpc_decode</a></span></dt><dt><span class="sect2"><a href="ch07s03.html#xmlrpcencode">3.2. xmlrpc_encode</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch07s04.html">4. Debugging aids</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch07s04.html#d0e1694">4.1. xmlrpc_debugmsg</a></span></dt></dl></dd></dl></dd><dt><span class="chapter"><a href="ch08.html">8. Reserved methods</a></span></dt><dd><dl><dt><span class="sect1"><a href="ch08s01.html">1. system.listMethods</a></span></dt><dt><span class="sect1"><a href="ch08s02.html">2. system.methodSignature</a></span></dt><dt><span class="sect1"><a href="ch08s03.html">3. system.methodHelp</a></span></dt></dl></dd><dt><span class="chapter"><a href="ch09.html">9. Examples</a></span></dt><dd><dl><dt><span class="sect1"><a href="ch09s01.html">1. XML-RPC client: state name query</a></span></dt></dl></dd></dl></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="ch01.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top"> </td><td width="20%" align="center"> </td><td width="40%" align="right" valign="top"> Chapter 1. Introduction</td></tr></table></div></body></html>
\ No newline at end of file diff --git a/modules/xmlrpc/doc/introduction.html b/modules/xmlrpc/doc/introduction.html deleted file mode 100644 index 09b314e4..00000000 --- a/modules/xmlrpc/doc/introduction.html +++ /dev/null @@ -1,280 +0,0 @@ -<HTML -><HEAD -><TITLE ->Introduction</TITLE -><META -NAME="GENERATOR" -CONTENT="Modular DocBook HTML Stylesheet Version 1.77+"><LINK -REV="MADE" -HREF="edd@usefulinc.com"><LINK -REL="HOME" -TITLE="XML-RPC for PHP" -HREF="index.html"><LINK -REL="PREVIOUS" -TITLE="XML-RPC for PHP" -HREF="index.html"><LINK -REL="NEXT" -TITLE="Files in the distribution" -HREF="manifest.html"></HEAD -><BODY -CLASS="CHAPTER" -BGCOLOR="#FFFFFF" -TEXT="#000000" -LINK="#0000FF" -VLINK="#840084" -ALINK="#0000FF" -><DIV -CLASS="NAVHEADER" -><TABLE -SUMMARY="Header navigation table" -WIDTH="100%" -BORDER="0" -CELLPADDING="0" -CELLSPACING="0" -><TR -><TH -COLSPAN="3" -ALIGN="center" ->XML-RPC for PHP: version 1.1</TH -></TR -><TR -><TD -WIDTH="10%" -ALIGN="left" -VALIGN="bottom" -><A -HREF="index.html" -ACCESSKEY="P" ->Prev</A -></TD -><TD -WIDTH="80%" -ALIGN="center" -VALIGN="bottom" -></TD -><TD -WIDTH="10%" -ALIGN="right" -VALIGN="bottom" -><A -HREF="manifest.html" -ACCESSKEY="N" ->Next</A -></TD -></TR -></TABLE -><HR -ALIGN="LEFT" -WIDTH="100%"></DIV -><DIV -CLASS="CHAPTER" -><H1 -><A -NAME="INTRODUCTION" -></A ->Chapter 1. Introduction</H1 -><P ->XML-RPC is a format devised by <A -HREF="http://www.userland.com/" -TARGET="_top" ->Userland Software</A -> for - achieving remote procedure call via XML. XML-RPC has its own web - site, <A -HREF="http://www.xmlrpc.com/" -TARGET="_top" ->www.XmlRpc.com</A -></P -><P ->The most common implementations of XML-RPC available at the - moment use HTTP as the transport. A list of implementations for - other languages such as Perl and Python can be found on the - <A -HREF="http://www.xmlrpc.com/" -TARGET="_top" ->www.xmlrpc.com</A ->.</P -><P ->This collection of PHP classes provides a framework for - writing XML-RPC clients and servers in PHP.</P -><DIV -CLASS="WARNING" -><P -></P -><TABLE -CLASS="WARNING" -BORDER="1" -WIDTH="100%" -><TR -><TD -ALIGN="CENTER" -><B ->Warning</B -></TD -></TR -><TR -><TD -ALIGN="LEFT" -><P ->The <SPAN -CLASS="emphasis" -><I -CLASS="EMPHASIS" ->server code</I -></SPAN -> works only with versions of PHP3 - >= 3.0.12. The code is also known to work with PHP4. - </P -><P ->If you wish to use SSL to communicate with remote servers, - you need the "curl" extension compiled into your PHP - installation, this is available in PHP 4.0.2 and greater, - although 4.0.6 has a bug preventing SSL working.</P -></TD -></TR -></TABLE -></DIV -><DIV -CLASS="SECT1" -><H1 -CLASS="SECT1" -><A -NAME="AEN43" -></A ->Acknowledgements</H1 -><P ->Jim Winstead <TT -CLASS="EMAIL" -><<A -HREF="mailto:jimw@php.net" ->jimw@php.net</A ->></TT -></P -><P ->Peter Kocks <TT -CLASS="EMAIL" -><<A -HREF="mailto:peter.kocks@baygate.com" ->peter.kocks@baygate.com</A ->></TT -></P -><P ->Nicolay Mausz <TT -CLASS="EMAIL" -><<A -HREF="mailto:mausz@flying-dog.com" ->mausz@flying-dog.com</A ->></TT -></P -><P ->Ben Margolin - <TT -CLASS="EMAIL" -><<A -HREF="mailto:ben@wendy.auctionwatch.com" ->ben@wendy.auctionwatch.com</A ->></TT -></P -><P ->Dan Libby <TT -CLASS="EMAIL" -><<A -HREF="mailto:dan@libby.com" ->dan@libby.com</A ->></TT -></P -><P ->Gaetano Giunta <TT -CLASS="EMAIL" -><<A -HREF="mailto:g.giunta@libero.it" ->g.giunta@libero.it</A ->></TT -></P -><P ->Idan Sofer <TT -CLASS="EMAIL" -><<A -HREF="mailto:i_sofer@yahoo.com" ->i_sofer@yahoo.com</A ->></TT -></P -><P ->Giancarlo Pinerolo <TT -CLASS="EMAIL" -><<A -HREF="mailto:ping@alt.it" ->ping@alt.it</A ->></TT -></P -><P ->Justin Miller <TT -CLASS="EMAIL" -><<A -HREF="mailto:justin@voxel.net" ->justin@voxel.net</A ->></TT -></P -></DIV -></DIV -><DIV -CLASS="NAVFOOTER" -><HR -ALIGN="LEFT" -WIDTH="100%"><TABLE -SUMMARY="Footer navigation table" -WIDTH="100%" -BORDER="0" -CELLPADDING="0" -CELLSPACING="0" -><TR -><TD -WIDTH="33%" -ALIGN="left" -VALIGN="top" -><A -HREF="index.html" -ACCESSKEY="P" ->Prev</A -></TD -><TD -WIDTH="34%" -ALIGN="center" -VALIGN="top" -><A -HREF="index.html" -ACCESSKEY="H" ->Home</A -></TD -><TD -WIDTH="33%" -ALIGN="right" -VALIGN="top" -><A -HREF="manifest.html" -ACCESSKEY="N" ->Next</A -></TD -></TR -><TR -><TD -WIDTH="33%" -ALIGN="left" -VALIGN="top" ->XML-RPC for PHP</TD -><TD -WIDTH="34%" -ALIGN="center" -VALIGN="top" -> </TD -><TD -WIDTH="33%" -ALIGN="right" -VALIGN="top" ->Files in the distribution</TD -></TR -></TABLE -></DIV -></BODY -></HTML ->
\ No newline at end of file diff --git a/modules/xmlrpc/doc/jellyfish.html b/modules/xmlrpc/doc/jellyfish.html deleted file mode 100644 index a4154100..00000000 --- a/modules/xmlrpc/doc/jellyfish.html +++ /dev/null @@ -1,180 +0,0 @@ -<HTML -><HEAD -><TITLE ->The Jellyfish Book</TITLE -><META -NAME="GENERATOR" -CONTENT="Modular DocBook HTML Stylesheet Version 1.77+"><LINK -REV="MADE" -HREF="edd@usefulinc.com"><LINK -REL="HOME" -TITLE="XML-RPC for PHP" -HREF="index.html"><LINK -REL="UP" -TITLE="Support" -HREF="support.html"><LINK -REL="PREVIOUS" -TITLE="Support" -HREF="support.html"><LINK -REL="NEXT" -TITLE="Class documentation" -HREF="apidocs.html"></HEAD -><BODY -CLASS="SECT1" -BGCOLOR="#FFFFFF" -TEXT="#000000" -LINK="#0000FF" -VLINK="#840084" -ALINK="#0000FF" -><DIV -CLASS="NAVHEADER" -><TABLE -SUMMARY="Header navigation table" -WIDTH="100%" -BORDER="0" -CELLPADDING="0" -CELLSPACING="0" -><TR -><TH -COLSPAN="3" -ALIGN="center" ->XML-RPC for PHP: version 1.1</TH -></TR -><TR -><TD -WIDTH="10%" -ALIGN="left" -VALIGN="bottom" -><A -HREF="support.html" -ACCESSKEY="P" ->Prev</A -></TD -><TD -WIDTH="80%" -ALIGN="center" -VALIGN="bottom" ->Chapter 4. Support</TD -><TD -WIDTH="10%" -ALIGN="right" -VALIGN="bottom" -><A -HREF="apidocs.html" -ACCESSKEY="N" ->Next</A -></TD -></TR -></TABLE -><HR -ALIGN="LEFT" -WIDTH="100%"></DIV -><DIV -CLASS="SECT1" -><H1 -CLASS="SECT1" -><A -NAME="JELLYFISH" -></A ->The Jellyfish Book</H1 -><P -> - <P -><IMG -SRC="http://www.oreilly.com/catalog/covers/progxmlrpc.s.gif" -ALIGN="RIGHT" -WIDTH="145" -HEIGHT="190"></P -> - Together with Simon St.Laurent and Joe Johnston, I wrote a - book on XML-RPC for O'Reilly and Associates on XML-RPC. It - features a rather fetching jellyfish on the cover. - </P -><P ->Complete details of the book are - <A -HREF="http://www.oreilly.com/catalog/progxmlrpc/" -TARGET="_top" ->available - from O'Reilly's web site.</A -> - </P -><P ->I'm responsible for the chapter on PHP, which includes a - worked example of creating a forum server, and hooking it up - the O'Reilly's <A -HREF="http://meerkat.oreillynet.com/" -TARGET="_top" ->Meerkat</A -> service - in order to allow commenting on news stories from around the - Web.</P -><P ->If you've benefitted from the effort I've put into writing - this software, then please consider buying the book!</P -></DIV -><DIV -CLASS="NAVFOOTER" -><HR -ALIGN="LEFT" -WIDTH="100%"><TABLE -SUMMARY="Footer navigation table" -WIDTH="100%" -BORDER="0" -CELLPADDING="0" -CELLSPACING="0" -><TR -><TD -WIDTH="33%" -ALIGN="left" -VALIGN="top" -><A -HREF="support.html" -ACCESSKEY="P" ->Prev</A -></TD -><TD -WIDTH="34%" -ALIGN="center" -VALIGN="top" -><A -HREF="index.html" -ACCESSKEY="H" ->Home</A -></TD -><TD -WIDTH="33%" -ALIGN="right" -VALIGN="top" -><A -HREF="apidocs.html" -ACCESSKEY="N" ->Next</A -></TD -></TR -><TR -><TD -WIDTH="33%" -ALIGN="left" -VALIGN="top" ->Support</TD -><TD -WIDTH="34%" -ALIGN="center" -VALIGN="top" -><A -HREF="support.html" -ACCESSKEY="U" ->Up</A -></TD -><TD -WIDTH="33%" -ALIGN="right" -VALIGN="top" ->Class documentation</TD -></TR -></TABLE -></DIV -></BODY -></HTML ->
\ No newline at end of file diff --git a/modules/xmlrpc/doc/manifest.html b/modules/xmlrpc/doc/manifest.html deleted file mode 100644 index 1586e41c..00000000 --- a/modules/xmlrpc/doc/manifest.html +++ /dev/null @@ -1,310 +0,0 @@ -<HTML -><HEAD -><TITLE ->Files in the distribution</TITLE -><META -NAME="GENERATOR" -CONTENT="Modular DocBook HTML Stylesheet Version 1.77+"><LINK -REV="MADE" -HREF="edd@usefulinc.com"><LINK -REL="HOME" -TITLE="XML-RPC for PHP" -HREF="index.html"><LINK -REL="PREVIOUS" -TITLE="Introduction" -HREF="introduction.html"><LINK -REL="NEXT" -TITLE="Bugs" -HREF="bugs.html"></HEAD -><BODY -CLASS="CHAPTER" -BGCOLOR="#FFFFFF" -TEXT="#000000" -LINK="#0000FF" -VLINK="#840084" -ALINK="#0000FF" -><DIV -CLASS="NAVHEADER" -><TABLE -SUMMARY="Header navigation table" -WIDTH="100%" -BORDER="0" -CELLPADDING="0" -CELLSPACING="0" -><TR -><TH -COLSPAN="3" -ALIGN="center" ->XML-RPC for PHP: version 1.1</TH -></TR -><TR -><TD -WIDTH="10%" -ALIGN="left" -VALIGN="bottom" -><A -HREF="introduction.html" -ACCESSKEY="P" ->Prev</A -></TD -><TD -WIDTH="80%" -ALIGN="center" -VALIGN="bottom" -></TD -><TD -WIDTH="10%" -ALIGN="right" -VALIGN="bottom" -><A -HREF="bugs.html" -ACCESSKEY="N" ->Next</A -></TD -></TR -></TABLE -><HR -ALIGN="LEFT" -WIDTH="100%"></DIV -><DIV -CLASS="CHAPTER" -><H1 -><A -NAME="MANIFEST" -></A ->Chapter 2. Files in the distribution</H1 -><DIV -CLASS="GLOSSLIST" -><DL -><DT -><B ->xmlrpc.inc</B -></DT -><DD -><P ->the XML-RPC classes. <TT -CLASS="FUNCTION" ->include()</TT -> this in - your PHP files to use the classes.</P -></DD -><DT -><B ->xmlrpcs.inc</B -></DT -><DD -><P ->the XML-RPC server class. <TT -CLASS="FUNCTION" ->include()</TT -> - this in addition to xmlrpc.inc to get server - functionality</P -></DD -><DT -><B ->bettydemo.php</B -></DT -><DD -><P ->demo which retrieves a state name from a number using Dave - Winer's XML-RPC server at betty.userland.com</P -></DD -><DT -><B ->server.php</B -></DT -><DD -><P ->a sample server hosting three functions: a US State lookup - tool, a struct sorter and an echo function.</P -></DD -><DT -><B ->client.php, agesort.php, echotest.php</B -></DT -><DD -><P ->client code to exercise the various functions in - server.php</P -></DD -><DT -><B ->base64test.php, stringtest.php</B -></DT -><DD -><P -> Tests to verify that encoding and decoding of base 64 and - entities is functioning correctly. - </P -></DD -><DT -><B ->vardemo.php</B -></DT -><DD -><P ->examples of how to construct xmlrpcval types</P -></DD -><DT -><B ->demo1.txt, demo2.txt, demo3.txt</B -></DT -><DD -><P ->XML-RPC responses captured in a file for testing purposes (you - can use these to test the - <TT -CLASS="FUNCTION" ->xmlrpcmsg->parseResponse()</TT -> - method).</P -></DD -><DT -><B ->httptest.php</B -></DT -><DD -><P ->Testing that HTTP response detection works OK.</P -></DD -><DT -><B ->test.pl, test.py</B -></DT -><DD -><P ->Perl and Python programs to exercise server.php to test - that some of the methods work. - Make sure you point these at your server, not mine!</P -></DD -><DT -><B ->workspace.testPhpServer.fttb</B -></DT -><DD -><P ->Frontier scripts to exercise the demo server. Thanks to Dave - Winer for permission to include these. See <A -HREF="http://www.xmlrpc.com/discuss/msgReader$853" -TARGET="_top" ->Dave's announcement of these.</A -></P -></DD -><DT -><B ->phpunit.php</B -></DT -><DD -><P ->Fred Yankowski's unit test framework for PHP.</P -></DD -><DT -><B ->testsuite.php</B -></DT -><DD -><P ->Start of a unit test suite for this software - package. If you do development on this software, please - consider submitting tests for this suite.</P -></DD -><DT -><B ->which.php</B -></DT -><DD -><P ->A demo of the - <TT -CLASS="FUNCTION" ->interopEchoTests.whichToolkit</TT -> - method.</P -></DD -><DT -><B ->discuss.php, comment.php</B -></DT -><DD -><P ->Software used in the PHP chapter of <A -HREF="jellyfish.html" ->The Jellyfish Book</A -> to - provide a comment server and allow the attachment of - comments to stories from Meerkat's data store.</P -></DD -><DT -><B ->rsakey.pem</B -></DT -><DD -><P ->A test certificate for the SSL support. It has the - passphrase "test."</P -></DD -></DL -></DIV -></DIV -><DIV -CLASS="NAVFOOTER" -><HR -ALIGN="LEFT" -WIDTH="100%"><TABLE -SUMMARY="Footer navigation table" -WIDTH="100%" -BORDER="0" -CELLPADDING="0" -CELLSPACING="0" -><TR -><TD -WIDTH="33%" -ALIGN="left" -VALIGN="top" -><A -HREF="introduction.html" -ACCESSKEY="P" ->Prev</A -></TD -><TD -WIDTH="34%" -ALIGN="center" -VALIGN="top" -><A -HREF="index.html" -ACCESSKEY="H" ->Home</A -></TD -><TD -WIDTH="33%" -ALIGN="right" -VALIGN="top" -><A -HREF="bugs.html" -ACCESSKEY="N" ->Next</A -></TD -></TR -><TR -><TD -WIDTH="33%" -ALIGN="left" -VALIGN="top" ->Introduction</TD -><TD -WIDTH="34%" -ALIGN="center" -VALIGN="top" -> </TD -><TD -WIDTH="33%" -ALIGN="right" -VALIGN="top" ->Bugs</TD -></TR -></TABLE -></DIV -></BODY -></HTML ->
\ No newline at end of file diff --git a/modules/xmlrpc/doc/reserved.html b/modules/xmlrpc/doc/reserved.html deleted file mode 100644 index d5525d6a..00000000 --- a/modules/xmlrpc/doc/reserved.html +++ /dev/null @@ -1,191 +0,0 @@ -<HTML -><HEAD -><TITLE ->Reserved methods</TITLE -><META -NAME="GENERATOR" -CONTENT="Modular DocBook HTML Stylesheet Version 1.77+"><LINK -REV="MADE" -HREF="edd@usefulinc.com"><LINK -REL="HOME" -TITLE="XML-RPC for PHP" -HREF="index.html"><LINK -REL="PREVIOUS" -TITLE="Debugging aids" -HREF="debugging.html"><LINK -REL="NEXT" -TITLE="system.methodSignature" -HREF="sysmethodsig.html"></HEAD -><BODY -CLASS="CHAPTER" -BGCOLOR="#FFFFFF" -TEXT="#000000" -LINK="#0000FF" -VLINK="#840084" -ALINK="#0000FF" -><DIV -CLASS="NAVHEADER" -><TABLE -SUMMARY="Header navigation table" -WIDTH="100%" -BORDER="0" -CELLPADDING="0" -CELLSPACING="0" -><TR -><TH -COLSPAN="3" -ALIGN="center" ->XML-RPC for PHP: version 1.1</TH -></TR -><TR -><TD -WIDTH="10%" -ALIGN="left" -VALIGN="bottom" -><A -HREF="debugging.html" -ACCESSKEY="P" ->Prev</A -></TD -><TD -WIDTH="80%" -ALIGN="center" -VALIGN="bottom" -></TD -><TD -WIDTH="10%" -ALIGN="right" -VALIGN="bottom" -><A -HREF="sysmethodsig.html" -ACCESSKEY="N" ->Next</A -></TD -></TR -></TABLE -><HR -ALIGN="LEFT" -WIDTH="100%"></DIV -><DIV -CLASS="CHAPTER" -><H1 -><A -NAME="RESERVED" -></A ->Chapter 7. Reserved methods</H1 -><DIV -CLASS="TOC" -><DL -><DT -><B ->Table of Contents</B -></DT -><DT -><A -HREF="reserved.html#AEN827" ->system.listMethods</A -></DT -><DT -><A -HREF="sysmethodsig.html" ->system.methodSignature</A -></DT -><DT -><A -HREF="sysmethhelp.html" ->system.methodHelp</A -></DT -></DL -></DIV -><P ->In order to extend the functionality offered by XML-RPC - servers without impacting on the protocol, I've included - experimental support in this release for reserved methods.</P -><P ->All methods starting with <TT -CLASS="FUNCTION" ->system.</TT -> are - considered reserved by the server. PHP for XML-RPC itself provides - three special methods, detailed in this chapter.</P -><DIV -CLASS="SECT1" -><H1 -CLASS="SECT1" -><A -NAME="AEN827" -></A ->system.listMethods</H1 -><P ->This method may be used to enumerate the methods implemented - by the XML-RPC server.</P -><P ->The <TT -CLASS="FUNCTION" ->system.listMethods</TT -> method requires - no parameters. It returns an array of strings, each of which is - the name of a method implemented by the server.</P -></DIV -></DIV -><DIV -CLASS="NAVFOOTER" -><HR -ALIGN="LEFT" -WIDTH="100%"><TABLE -SUMMARY="Footer navigation table" -WIDTH="100%" -BORDER="0" -CELLPADDING="0" -CELLSPACING="0" -><TR -><TD -WIDTH="33%" -ALIGN="left" -VALIGN="top" -><A -HREF="debugging.html" -ACCESSKEY="P" ->Prev</A -></TD -><TD -WIDTH="34%" -ALIGN="center" -VALIGN="top" -><A -HREF="index.html" -ACCESSKEY="H" ->Home</A -></TD -><TD -WIDTH="33%" -ALIGN="right" -VALIGN="top" -><A -HREF="sysmethodsig.html" -ACCESSKEY="N" ->Next</A -></TD -></TR -><TR -><TD -WIDTH="33%" -ALIGN="left" -VALIGN="top" ->Debugging aids</TD -><TD -WIDTH="34%" -ALIGN="center" -VALIGN="top" -> </TD -><TD -WIDTH="33%" -ALIGN="right" -VALIGN="top" ->system.methodSignature</TD -></TR -></TABLE -></DIV -></BODY -></HTML ->
\ No newline at end of file diff --git a/modules/xmlrpc/doc/support.html b/modules/xmlrpc/doc/support.html deleted file mode 100644 index 6c60c9cb..00000000 --- a/modules/xmlrpc/doc/support.html +++ /dev/null @@ -1,209 +0,0 @@ -<HTML -><HEAD -><TITLE ->Support</TITLE -><META -NAME="GENERATOR" -CONTENT="Modular DocBook HTML Stylesheet Version 1.77+"><LINK -REV="MADE" -HREF="edd@usefulinc.com"><LINK -REL="HOME" -TITLE="XML-RPC for PHP" -HREF="index.html"><LINK -REL="PREVIOUS" -TITLE="Bugs" -HREF="bugs.html"><LINK -REL="NEXT" -TITLE="The Jellyfish Book" -HREF="jellyfish.html"></HEAD -><BODY -CLASS="CHAPTER" -BGCOLOR="#FFFFFF" -TEXT="#000000" -LINK="#0000FF" -VLINK="#840084" -ALINK="#0000FF" -><DIV -CLASS="NAVHEADER" -><TABLE -SUMMARY="Header navigation table" -WIDTH="100%" -BORDER="0" -CELLPADDING="0" -CELLSPACING="0" -><TR -><TH -COLSPAN="3" -ALIGN="center" ->XML-RPC for PHP: version 1.1</TH -></TR -><TR -><TD -WIDTH="10%" -ALIGN="left" -VALIGN="bottom" -><A -HREF="bugs.html" -ACCESSKEY="P" ->Prev</A -></TD -><TD -WIDTH="80%" -ALIGN="center" -VALIGN="bottom" -></TD -><TD -WIDTH="10%" -ALIGN="right" -VALIGN="bottom" -><A -HREF="jellyfish.html" -ACCESSKEY="N" ->Next</A -></TD -></TR -></TABLE -><HR -ALIGN="LEFT" -WIDTH="100%"></DIV -><DIV -CLASS="CHAPTER" -><H1 -><A -NAME="SUPPORT" -></A ->Chapter 4. Support</H1 -><DIV -CLASS="TOC" -><DL -><DT -><B ->Table of Contents</B -></DT -><DT -><A -HREF="support.html#AEN146" ->Online Support</A -></DT -><DT -><A -HREF="jellyfish.html" ->The Jellyfish Book</A -></DT -></DL -></DIV -><DIV -CLASS="SECT1" -><H1 -CLASS="SECT1" -><A -NAME="AEN146" -></A ->Online Support</H1 -><P ->XML-RPC for PHP is offered "as-is" without any warranty or - commitment to support. However, informal advice and help is - available via the XML-RPC for PHP mailing list and XML-RPC.com. - </P -><P -></P -><UL -><LI -><P ->The <SPAN -CLASS="emphasis" -><I -CLASS="EMPHASIS" ->PHP XML-RPC interest mailing list</I -></SPAN -> - is run by the author. More details <A -HREF="http://www.usefulinc.com/xmlrpc/list.html" -TARGET="_top" ->can be found - here</A ->.</P -></LI -><LI -><P ->For more general XML-RPC questions, there is a - Yahoo! Groups <A -HREF="http://groups.yahoo.com/group/xml-rpc/" -TARGET="_top" ->XML-RPC mailing list</A ->.</P -></LI -><LI -><P ->The <A -HREF="http://www.xmlrpc.com/discuss" -TARGET="_top" ->XML-RPC.com</A -> - discussion group is a useful place to get help with using - XML-RPC. This group is also gatewayed into the Yahoo! Groups mailing list.</P -></LI -></UL -></DIV -></DIV -><DIV -CLASS="NAVFOOTER" -><HR -ALIGN="LEFT" -WIDTH="100%"><TABLE -SUMMARY="Footer navigation table" -WIDTH="100%" -BORDER="0" -CELLPADDING="0" -CELLSPACING="0" -><TR -><TD -WIDTH="33%" -ALIGN="left" -VALIGN="top" -><A -HREF="bugs.html" -ACCESSKEY="P" ->Prev</A -></TD -><TD -WIDTH="34%" -ALIGN="center" -VALIGN="top" -><A -HREF="index.html" -ACCESSKEY="H" ->Home</A -></TD -><TD -WIDTH="33%" -ALIGN="right" -VALIGN="top" -><A -HREF="jellyfish.html" -ACCESSKEY="N" ->Next</A -></TD -></TR -><TR -><TD -WIDTH="33%" -ALIGN="left" -VALIGN="top" ->Bugs</TD -><TD -WIDTH="34%" -ALIGN="center" -VALIGN="top" -> </TD -><TD -WIDTH="33%" -ALIGN="right" -VALIGN="top" ->The Jellyfish Book</TD -></TR -></TABLE -></DIV -></BODY -></HTML ->
\ No newline at end of file diff --git a/modules/xmlrpc/doc/sysmethhelp.html b/modules/xmlrpc/doc/sysmethhelp.html deleted file mode 100644 index 151d8d16..00000000 --- a/modules/xmlrpc/doc/sysmethhelp.html +++ /dev/null @@ -1,155 +0,0 @@ -<HTML -><HEAD -><TITLE ->system.methodHelp</TITLE -><META -NAME="GENERATOR" -CONTENT="Modular DocBook HTML Stylesheet Version 1.77+"><LINK -REV="MADE" -HREF="edd@usefulinc.com"><LINK -REL="HOME" -TITLE="XML-RPC for PHP" -HREF="index.html"><LINK -REL="UP" -TITLE="Reserved methods" -HREF="reserved.html"><LINK -REL="PREVIOUS" -TITLE="system.methodSignature" -HREF="sysmethodsig.html"><LINK -REL="NEXT" -TITLE="Examples" -HREF="examples.html"></HEAD -><BODY -CLASS="SECT1" -BGCOLOR="#FFFFFF" -TEXT="#000000" -LINK="#0000FF" -VLINK="#840084" -ALINK="#0000FF" -><DIV -CLASS="NAVHEADER" -><TABLE -SUMMARY="Header navigation table" -WIDTH="100%" -BORDER="0" -CELLPADDING="0" -CELLSPACING="0" -><TR -><TH -COLSPAN="3" -ALIGN="center" ->XML-RPC for PHP: version 1.1</TH -></TR -><TR -><TD -WIDTH="10%" -ALIGN="left" -VALIGN="bottom" -><A -HREF="sysmethodsig.html" -ACCESSKEY="P" ->Prev</A -></TD -><TD -WIDTH="80%" -ALIGN="center" -VALIGN="bottom" ->Chapter 7. Reserved methods</TD -><TD -WIDTH="10%" -ALIGN="right" -VALIGN="bottom" -><A -HREF="examples.html" -ACCESSKEY="N" ->Next</A -></TD -></TR -></TABLE -><HR -ALIGN="LEFT" -WIDTH="100%"></DIV -><DIV -CLASS="SECT1" -><H1 -CLASS="SECT1" -><A -NAME="SYSMETHHELP" -></A ->system.methodHelp</H1 -><P ->This method takes one parameter, the name of a method - implemented by the XML-RPC server.</P -><P -> It returns a documentation string describing the use of that - method. If no such string is available, an empty string is returned. - </P -><P -> The documentation string may contain HTML markup. - </P -></DIV -><DIV -CLASS="NAVFOOTER" -><HR -ALIGN="LEFT" -WIDTH="100%"><TABLE -SUMMARY="Footer navigation table" -WIDTH="100%" -BORDER="0" -CELLPADDING="0" -CELLSPACING="0" -><TR -><TD -WIDTH="33%" -ALIGN="left" -VALIGN="top" -><A -HREF="sysmethodsig.html" -ACCESSKEY="P" ->Prev</A -></TD -><TD -WIDTH="34%" -ALIGN="center" -VALIGN="top" -><A -HREF="index.html" -ACCESSKEY="H" ->Home</A -></TD -><TD -WIDTH="33%" -ALIGN="right" -VALIGN="top" -><A -HREF="examples.html" -ACCESSKEY="N" ->Next</A -></TD -></TR -><TR -><TD -WIDTH="33%" -ALIGN="left" -VALIGN="top" ->system.methodSignature</TD -><TD -WIDTH="34%" -ALIGN="center" -VALIGN="top" -><A -HREF="reserved.html" -ACCESSKEY="U" ->Up</A -></TD -><TD -WIDTH="33%" -ALIGN="right" -VALIGN="top" ->Examples</TD -></TR -></TABLE -></DIV -></BODY -></HTML ->
\ No newline at end of file diff --git a/modules/xmlrpc/doc/sysmethodsig.html b/modules/xmlrpc/doc/sysmethodsig.html deleted file mode 100644 index bb0bb7ca..00000000 --- a/modules/xmlrpc/doc/sysmethodsig.html +++ /dev/null @@ -1,191 +0,0 @@ -<HTML -><HEAD -><TITLE ->system.methodSignature</TITLE -><META -NAME="GENERATOR" -CONTENT="Modular DocBook HTML Stylesheet Version 1.77+"><LINK -REV="MADE" -HREF="edd@usefulinc.com"><LINK -REL="HOME" -TITLE="XML-RPC for PHP" -HREF="index.html"><LINK -REL="UP" -TITLE="Reserved methods" -HREF="reserved.html"><LINK -REL="PREVIOUS" -TITLE="Reserved methods" -HREF="reserved.html"><LINK -REL="NEXT" -TITLE="system.methodHelp" -HREF="sysmethhelp.html"></HEAD -><BODY -CLASS="SECT1" -BGCOLOR="#FFFFFF" -TEXT="#000000" -LINK="#0000FF" -VLINK="#840084" -ALINK="#0000FF" -><DIV -CLASS="NAVHEADER" -><TABLE -SUMMARY="Header navigation table" -WIDTH="100%" -BORDER="0" -CELLPADDING="0" -CELLSPACING="0" -><TR -><TH -COLSPAN="3" -ALIGN="center" ->XML-RPC for PHP: version 1.1</TH -></TR -><TR -><TD -WIDTH="10%" -ALIGN="left" -VALIGN="bottom" -><A -HREF="reserved.html" -ACCESSKEY="P" ->Prev</A -></TD -><TD -WIDTH="80%" -ALIGN="center" -VALIGN="bottom" ->Chapter 7. Reserved methods</TD -><TD -WIDTH="10%" -ALIGN="right" -VALIGN="bottom" -><A -HREF="sysmethhelp.html" -ACCESSKEY="N" ->Next</A -></TD -></TR -></TABLE -><HR -ALIGN="LEFT" -WIDTH="100%"></DIV -><DIV -CLASS="SECT1" -><H1 -CLASS="SECT1" -><A -NAME="SYSMETHODSIG" -></A ->system.methodSignature</H1 -><P ->This method takes one parameter, the name of a method - implemented by the XML-RPC server.</P -><P ->It returns an array of possible signatures for this - method. A signature is an array of types. The first of these - types is the return type of the method, the rest are parameters.</P -><P ->Multiple signatures (ie. overloading) are permitted: this is - the reason that an array of signatures are returned by this - method.</P -><P ->Signatures themselves are restricted to the top level - parameters expected by a method. For instance if a method - expects one array of structs as a parameter, and it returns a - string, its signature is simply "string, array". If it expects - three integers, its signature is "string, int, int, - int".</P -><P -> If no signature is defined for the method, a none-array value is - returned. Therefore this is the way to test for a non-signature, - if <TT -CLASS="PARAMETER" -><I ->$resp</I -></TT -> below is the response object - from a method call to <TT -CLASS="FUNCTION" ->system.methodSignature</TT ->: - </P -><PRE -CLASS="PROGRAMLISTING" ->$v=$resp->value(); -if ($v->kindOf()!="array") { - // then the method did not have a signature defined -} - </PRE -><P -> See the <TT -CLASS="FILENAME" ->introspect.php</TT -> demo included in - this distribution for an example of using this method. - </P -></DIV -><DIV -CLASS="NAVFOOTER" -><HR -ALIGN="LEFT" -WIDTH="100%"><TABLE -SUMMARY="Footer navigation table" -WIDTH="100%" -BORDER="0" -CELLPADDING="0" -CELLSPACING="0" -><TR -><TD -WIDTH="33%" -ALIGN="left" -VALIGN="top" -><A -HREF="reserved.html" -ACCESSKEY="P" ->Prev</A -></TD -><TD -WIDTH="34%" -ALIGN="center" -VALIGN="top" -><A -HREF="index.html" -ACCESSKEY="H" ->Home</A -></TD -><TD -WIDTH="33%" -ALIGN="right" -VALIGN="top" -><A -HREF="sysmethhelp.html" -ACCESSKEY="N" ->Next</A -></TD -></TR -><TR -><TD -WIDTH="33%" -ALIGN="left" -VALIGN="top" ->Reserved methods</TD -><TD -WIDTH="34%" -ALIGN="center" -VALIGN="top" -><A -HREF="reserved.html" -ACCESSKEY="U" ->Up</A -></TD -><TD -WIDTH="33%" -ALIGN="right" -VALIGN="top" ->system.methodHelp</TD -></TR -></TABLE -></DIV -></BODY -></HTML ->
\ No newline at end of file diff --git a/modules/xmlrpc/doc/xmlrpc-server.html b/modules/xmlrpc/doc/xmlrpc-server.html deleted file mode 100644 index da18e0f7..00000000 --- a/modules/xmlrpc/doc/xmlrpc-server.html +++ /dev/null @@ -1,487 +0,0 @@ -<HTML -><HEAD -><TITLE ->xmlrpc_server</TITLE -><META -NAME="GENERATOR" -CONTENT="Modular DocBook HTML Stylesheet Version 1.77+"><LINK -REV="MADE" -HREF="edd@usefulinc.com"><LINK -REL="HOME" -TITLE="XML-RPC for PHP" -HREF="index.html"><LINK -REL="UP" -TITLE="Class documentation" -HREF="apidocs.html"><LINK -REL="PREVIOUS" -TITLE="xmlrpcval" -HREF="xmlrpcval.html"><LINK -REL="NEXT" -TITLE="Helper functions" -HREF="helpers.html"></HEAD -><BODY -CLASS="SECT1" -BGCOLOR="#FFFFFF" -TEXT="#000000" -LINK="#0000FF" -VLINK="#840084" -ALINK="#0000FF" -><DIV -CLASS="NAVHEADER" -><TABLE -SUMMARY="Header navigation table" -WIDTH="100%" -BORDER="0" -CELLPADDING="0" -CELLSPACING="0" -><TR -><TH -COLSPAN="3" -ALIGN="center" ->XML-RPC for PHP: version 1.1</TH -></TR -><TR -><TD -WIDTH="10%" -ALIGN="left" -VALIGN="bottom" -><A -HREF="xmlrpcval.html" -ACCESSKEY="P" ->Prev</A -></TD -><TD -WIDTH="80%" -ALIGN="center" -VALIGN="bottom" ->Chapter 5. Class documentation</TD -><TD -WIDTH="10%" -ALIGN="right" -VALIGN="bottom" -><A -HREF="helpers.html" -ACCESSKEY="N" ->Next</A -></TD -></TR -></TABLE -><HR -ALIGN="LEFT" -WIDTH="100%"></DIV -><DIV -CLASS="SECT1" -><H1 -CLASS="SECT1" -><A -NAME="XMLRPC-SERVER" -></A ->xmlrpc_server</H1 -><P ->The current implementation of this class has been - kept as simple as possible. The constructor for the server - basically does all the work. Here's a minimal example:</P -><PRE -CLASS="PROGRAMLISTING" -> function foo ($params) { - ... - } - - $s=new xmlrpc_server( array("examples.myFunc" => - array("function" => "foo"))); - </PRE -><P -> This performs everything you need to do with a server. The single - argument is an associative array from method names to function - names. The request is parsed and despatched to the relevant function, - which is reponsible for returning a - <TT -CLASS="CLASSNAME" ->xmlrpcresp</TT -> - object, which gets - serialized back to the caller. See server.php in this distribution for - examples of how to do this. - </P -><P ->Here is a more detailed look at what the handler function - <TT -CLASS="FUNCTION" ->foo</TT -> may do:</P -><PRE -CLASS="PROGRAMLISTING" -> function foo ($params) { - global $xmlrpcerruser; // import user errcode value - - // $params is an Array of xmlrpcval objects - - if ($err) { - // this is an error condition - return new xmlrpcresp(0, $xmlrpcerruser+1, // user error 1 - "There's a problem, Captain"); - } else { - // this is a successful value being returned - return new xmlrpcresp(new xmlrpcval("All's fine!", "string")); - } - } - </PRE -><DIV -CLASS="SECT2" -><H2 -CLASS="SECT2" -><A -NAME="AEN658" -></A ->The dispatch map</H2 -><P ->The first argument to the - <TT -CLASS="FUNCTION" ->xmlrpc_server</TT -> constructor is an array, - called the <SPAN -CLASS="emphasis" -><I -CLASS="EMPHASIS" ->dispatch map</I -></SPAN ->. In this array is the - information the server needs to service the XML-RPC methods - you define.</P -><P -> The dispatch map takes the form of an associative array of - associative arrays: the outer array has one entry for each - method, the key being the method name. The corresponding value - is another associative array, which can have the following members: - </P -><P -></P -><UL -><LI -><P -><TT -CLASS="FUNCTION" ->function</TT -> - this entry is - mandatory. It must be a name of a function in the - global scope which services the XML-RPC method.</P -></LI -><LI -><P -><TT -CLASS="FUNCTION" ->signature</TT -> - this entry is an - array containg the possible signatures (see <A -HREF="xmlrpc-server.html#SIGNATURES" ->Signatures</A ->) for the method. If - this entry is present then the server will check that the - correct number and type of parameters have been sent for - this method before dispatching it. - </P -></LI -><LI -><P -> <TT -CLASS="FUNCTION" ->docstring</TT -> - this entry is a string - containing documentation for the method. The - documentation may contain HTML markup. - </P -></LI -></UL -><P ->Look at the <TT -CLASS="FILENAME" ->server.php</TT -> example in the - distribution to see what a dispatch map looks like.</P -></DIV -><DIV -CLASS="SECT2" -><H2 -CLASS="SECT2" -><A -NAME="SIGNATURES" -></A ->Method signatures</H2 -><P ->A signature is a description of a method's return type and - its parameter types. A method may have more than one - signature.</P -><P ->Within a server's dispatch map, each method has an array - of possible signatures. Each signature is an array of - types. The first entry is the return type. For instance, the - method <PRE -CLASS="PROGRAMLISTING" ->string examples.getStateName(int)</PRE -> has the signature -<PRE -CLASS="PROGRAMLISTING" ->array($xmlrpcString, $xmlrpcInt)</PRE -> and, assuming that it the only possible signature for - the method, might be used like this in server creation: -<PRE -CLASS="PROGRAMLISTING" ->$findstate_sig=array(array($xmlrpcString, $xmlrpcInt)); - -$findstate_doc='When passed an integer between 1 and 51 returns the -name of a US state, where the integer is the index of that state name -in an alphabetic order.'; - -$s=new xmlrpc_server( array( "examples.getStateName" => - array("function" => "findstate", - "signature" => $findstate_sig, - "docstring" => $findstate_doc)));</PRE -> - - </P -><P ->For convenience the strings representing the XML-RPC types - have been encoded as global variables:<PRE -CLASS="PROGRAMLISTING" ->$xmlrpcI4="i4"; -$xmlrpcInt="int"; -$xmlrpcBoolean="boolean"; -$xmlrpcDouble="double"; -$xmlrpcString="string"; -$xmlrpcDateTime="dateTime.iso8601"; -$xmlrpcBase64="base64"; -$xmlrpcArray="array"; -$xmlrpcStruct="struct";</PRE -></P -></DIV -><DIV -CLASS="SECT2" -><H2 -CLASS="SECT2" -><A -NAME="AEN686" -></A ->Delaying the server response</H2 -><P ->You may want to construct the server, but for some reason - not fulfill the request immediately (security verification, for - instance). If you pass the constructor a second argument of - <TT -CLASS="LITERAL" ->0</TT -> this will have the desired effect. You - can then use the <TT -CLASS="FUNCTION" ->service()</TT -> method of the - server class to service the request. For example:</P -><PRE -CLASS="PROGRAMLISTING" ->$s=new xmlrpc_server($myDispMap, 0); - -// ... some code that does other stuff here - -$s->service();</PRE -></DIV -><DIV -CLASS="SECT2" -><H2 -CLASS="SECT2" -><A -NAME="AEN692" -></A ->Fault reporting</H2 -><P ->Fault codes for your servers should start at the - value indicated by - the global <TT -CLASS="LITERAL" ->$xmlrpcerruser</TT -> + 1.</P -><P ->Standard errors returned by the server include:</P -><P -></P -><DIV -CLASS="VARIABLELIST" -><DL -><DT -><TT -CLASS="LITERAL" ->1</TT -> <SPAN -CLASS="phrase" -><SPAN -CLASS="PHRASE" ->Unknown method</SPAN -></SPAN -></DT -><DD -><P ->Returned if the server was asked to dispatch a - method it didn't know about</P -></DD -><DT -><TT -CLASS="LITERAL" ->2</TT -> <SPAN -CLASS="phrase" -><SPAN -CLASS="PHRASE" ->Invalid return payload</SPAN -></SPAN -></DT -><DD -><P ->This error is actually generated by the client, not - server, code, but signifies that a server returned - something it couldn't understand.</P -></DD -><DT -><TT -CLASS="LITERAL" ->3</TT -> <SPAN -CLASS="phrase" -><SPAN -CLASS="PHRASE" ->Incorrect parameters</SPAN -></SPAN -></DT -><DD -><P ->This error is generated when the server has signature(s) - defined for a method, and the parameters passed by the - client do not match any of signatures.</P -></DD -><DT -><TT -CLASS="LITERAL" ->4</TT -> <SPAN -CLASS="phrase" -><SPAN -CLASS="PHRASE" ->Can't introspect: method unknown</SPAN -></SPAN -></DT -><DD -><P ->This error is generated by the builtin - <TT -CLASS="FUNCTION" ->system.*</TT -> methods when any kind of - introspection is attempted on a method undefined by the - server.</P -></DD -><DT -><TT -CLASS="LITERAL" ->5</TT -> <SPAN -CLASS="phrase" -><SPAN -CLASS="PHRASE" ->Didn't receive 200 OK from remote server</SPAN -></SPAN -></DT -><DD -><P ->This error is generated by the client when a remote server - doesn't return HTTP/1.1 200 OK in response to a - request. A more detailed error report is added onto the - end of the phrase above.</P -></DD -><DT -><TT -CLASS="LITERAL" ->100-</TT -> <SPAN -CLASS="phrase" -><SPAN -CLASS="PHRASE" ->XML parse errors</SPAN -></SPAN -></DT -><DD -><P ->Returns 100 plus the XML parser error code for the - fault that occurred. The - <TT -CLASS="FUNCTION" ->faultString</TT -> returned explains where - the parse error was in the incoming XML stream.</P -></DD -></DL -></DIV -></DIV -></DIV -><DIV -CLASS="NAVFOOTER" -><HR -ALIGN="LEFT" -WIDTH="100%"><TABLE -SUMMARY="Footer navigation table" -WIDTH="100%" -BORDER="0" -CELLPADDING="0" -CELLSPACING="0" -><TR -><TD -WIDTH="33%" -ALIGN="left" -VALIGN="top" -><A -HREF="xmlrpcval.html" -ACCESSKEY="P" ->Prev</A -></TD -><TD -WIDTH="34%" -ALIGN="center" -VALIGN="top" -><A -HREF="index.html" -ACCESSKEY="H" ->Home</A -></TD -><TD -WIDTH="33%" -ALIGN="right" -VALIGN="top" -><A -HREF="helpers.html" -ACCESSKEY="N" ->Next</A -></TD -></TR -><TR -><TD -WIDTH="33%" -ALIGN="left" -VALIGN="top" ->xmlrpcval</TD -><TD -WIDTH="34%" -ALIGN="center" -VALIGN="top" -><A -HREF="apidocs.html" -ACCESSKEY="U" ->Up</A -></TD -><TD -WIDTH="33%" -ALIGN="right" -VALIGN="top" ->Helper functions</TD -></TR -></TABLE -></DIV -></BODY -></HTML ->
\ No newline at end of file diff --git a/modules/xmlrpc/doc/xmlrpc_php.sgml b/modules/xmlrpc/doc/xmlrpc_php.sgml deleted file mode 100644 index 4f9bc7b2..00000000 --- a/modules/xmlrpc/doc/xmlrpc_php.sgml +++ /dev/null @@ -1,1487 +0,0 @@ -<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3//EN" []> -<book> - <bookinfo> - <title>XML-RPC for PHP</title> - <subtitle>version 1.1</subtitle> - <date>December 17, 2002</date> - <authorgroup> - <author> - <firstname>Edd</firstname> - <surname>Dumbill</surname> - <affiliation> - <orgname><ulink url="http://usefulinc.com/">Useful - Information Company</ulink></orgname> - <address> - <email>edd@usefulinc.com</email> - </address> - </affiliation> - </author> - </authorgroup> - <copyright> - <year>1999,2000,2001</year> - <holder>Edd Dumbill, Useful Information Company</holder> - </copyright> - <legalnotice> - <para> - All rights reserved. - </para> - <para> - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - </para> - - <para> - <itemizedlist> - <listitem> - <para> - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - </para> - </listitem> - - <listitem><para> - Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - </para></listitem> - - <listitem><para> - Neither the name of the "XML-RPC for PHP" nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - </para></listitem> - </itemizedlist> - </para> - <para> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - OF SUCH DAMAGE.</para> - - </legalnotice> - </bookinfo> - <toc> - </toc> - <chapter id="introduction"> - - <title>Introduction</title> - - <para>XML-RPC is a format devised by <ulink - url="http://www.userland.com/">Userland Software</ulink> for - achieving remote procedure call via XML. XML-RPC has its own web - site, <ulink - url="http://www.xmlrpc.com/">www.XmlRpc.com</ulink></para> - <para>The most common implementations of XML-RPC available at the - moment use HTTP as the transport. A list of implementations for - other languages such as Perl and Python can be found on the - <ulink - url="http://www.xmlrpc.com/">www.xmlrpc.com</ulink>.</para> - <para>This collection of PHP classes provides a framework for - writing XML-RPC clients and servers in PHP.</para> - <warning> - <para>The <emphasis>server code</emphasis> works only with versions of PHP3 - >= 3.0.12. The code is also known to work with PHP4. - </para> - <para>If you wish to use SSL to communicate with remote servers, - you need the "curl" extension compiled into your PHP - installation, this is available in PHP 4.0.2 and greater, - although 4.0.6 has a bug preventing SSL working.</para> - </warning> - - <sect1> - <title>Acknowledgements</title> - <para>Jim Winstead <email>jimw@php.net</email></para> - <para>Peter Kocks <email>peter.kocks@baygate.com</email></para> - <para>Nicolay Mausz <email>mausz@flying-dog.com</email></para> - <para>Ben Margolin - <email>ben@wendy.auctionwatch.com</email></para> - <para>Dan Libby <email>dan@libby.com</email></para> - <para>Gaetano Giunta <email>g.giunta@libero.it</email></para> - <para>Idan Sofer <email>i_sofer@yahoo.com</email></para> - <para>Giancarlo Pinerolo <email>ping@alt.it</email></para> - <para>Justin Miller <email>justin@voxel.net</email></para> - </sect1> - </chapter> - - <chapter id="manifest"> - <title>Files in the distribution</title> - - <glosslist> - <glossentry> - <glossterm>xmlrpc.inc</glossterm> - <glossdef> - <para>the XML-RPC classes. <function>include()</function> this in - your PHP files to use the classes.</para> - </glossdef> - </glossentry> - - <glossentry> - <glossterm>xmlrpcs.inc</glossterm> - <glossdef> - <para>the XML-RPC server class. <function>include()</function> - this in addition to xmlrpc.inc to get server - functionality</para> - </glossdef> - </glossentry> - - <glossentry> - <glossterm>bettydemo.php</glossterm> - <glossdef> - <para>demo which retrieves a state name from a number using Dave - Winer's XML-RPC server at betty.userland.com</para> - </glossdef> - </glossentry> - - <glossentry> - <glossterm>server.php</glossterm> - <glossdef> - <para>a sample server hosting three functions: a US State lookup - tool, a struct sorter and an echo function.</para> - </glossdef> - </glossentry> - - <glossentry> - <glossterm>client.php, agesort.php, echotest.php</glossterm> - <glossdef> - <para>client code to exercise the various functions in - server.php</para> - </glossdef> - </glossentry> - - <glossentry> - <glossterm>base64test.php, stringtest.php</glossterm> - <glossdef> - <para> - Tests to verify that encoding and decoding of base 64 and - entities is functioning correctly. - </para> - </glossdef> - </glossentry> - - <glossentry> - <glossterm>vardemo.php</glossterm> - <glossdef> - <para>examples of how to construct xmlrpcval types</para> - </glossdef> - </glossentry> - - <glossentry> - <glossterm>demo1.txt, demo2.txt, demo3.txt</glossterm> - <glossdef> - <para>XML-RPC responses captured in a file for testing purposes (you - can use these to test the - <function>xmlrpcmsg->parseResponse()</function> - method).</para> - </glossdef> - </glossentry> - - <glossentry> - <glossterm>httptest.php</glossterm> - <glossdef> - <para>Testing that HTTP response detection works OK.</para> - </glossdef> - </glossentry> - <glossentry> - <glossterm>test.pl, test.py</glossterm> - <glossdef> - <para>Perl and Python programs to exercise server.php to test - that some of the methods work. - Make sure you point these at your server, not mine!</para> - </glossdef> - </glossentry> - <glossentry> - <glossterm>workspace.testPhpServer.fttb</glossterm> - <glossdef> - <para>Frontier scripts to exercise the demo server. Thanks to Dave - Winer for permission to include these. See <ulink - url="http://www.xmlrpc.com/discuss/msgReader$853">Dave's announcement of these.</ulink></para> - - </glossdef> - </glossentry> - - <glossentry> - <glossterm>phpunit.php</glossterm> - <glossdef> - <para>Fred Yankowski's unit test framework for PHP.</para> - </glossdef> - </glossentry> - - <glossentry> - <glossterm>testsuite.php</glossterm> - <glossdef> - <para>Start of a unit test suite for this software - package. If you do development on this software, please - consider submitting tests for this suite.</para> - </glossdef> - </glossentry> - <glossentry> - <glossterm>which.php</glossterm> - <glossdef> - <para>A demo of the - <function>interopEchoTests.whichToolkit</function> - method.</para> - </glossdef> - </glossentry> - <glossentry> - <glossterm>discuss.php, comment.php</glossterm> - <glossdef> - <para>Software used in the PHP chapter of <xref linkend="jellyfish"> to - provide a comment server and allow the attachment of - comments to stories from Meerkat's data store.</para> - </glossdef> - </glossentry> - - <glossentry> - <glossterm>rsakey.pem</glossterm> - <glossdef> - <para>A test certificate for the SSL support. It has the - passphrase "test."</para> - </glossdef> - </glossentry> - </glosslist> - </chapter> - <chapter id="bugs"> - <title>Bugs</title> - <para>This is a bare framework. The "nice" bits haven't been put in - yet. Specifically, no HTTP response checking is performed, and no type - validation or coercion has been put in. PHP being a loosely-typed - language, this is going to have to be done explicitly.</para> - <para>dateTime.iso8601 is supported opaquely. It can't be done - natively as the XML-RPC specification explictly forbids passing of - timezone specifiers in ISO8601 format dates. You can, however, use - the <xref linkend="iso8601encode"> and <xref - linkend="iso8601decode"> functions to do the encoding and decoding for you.</para> - <para>If alternative character set encoding is sent in HTTP header - than it will be ignored for the moment. We speak only UTF-8...</para> - <para>If more than 32k of HTTP headers are encountered (like, why?) then the - response parsing code will break.</para> - - </chapter> - <chapter id="support"> - <title>Support</title> - <sect1> - <title>Online Support</title> - - <para>XML-RPC for PHP is offered "as-is" without any warranty or - commitment to support. However, informal advice and help is - available via the XML-RPC for PHP mailing list and XML-RPC.com. - </para> - <itemizedlist> - <listitem> - <para>The <emphasis>PHP XML-RPC interest mailing list</emphasis> - is run by the author. More details <ulink - url="http://www.usefulinc.com/xmlrpc/list.html">can be found - here</ulink>.</para> - </listitem> - <listitem><para>For more general XML-RPC questions, there is a - Yahoo! Groups <ulink - url="http://groups.yahoo.com/group/xml-rpc/">XML-RPC mailing list</ulink>.</para> - <listitem> - <para>The <ulink - url="http://www.xmlrpc.com/discuss">XML-RPC.com</ulink> - discussion group is a useful place to get help with using - XML-RPC. This group is also gatewayed into the Yahoo! Groups mailing list.</para> - </listitem> - </itemizedlist> - </sect1> - <sect1 id="jellyfish" xreflabel="The - Jellyfish Book"> - <title>The Jellyfish Book</title> - <para> - <graphic - fileref="http://www.oreilly.com/catalog/covers/progxmlrpc.s.gif" - format="gif" width="145" depth="190" align="right"></graphic> - Together with Simon St.Laurent and Joe Johnston, I wrote a - book on XML-RPC for O'Reilly and Associates on XML-RPC. It - features a rather fetching jellyfish on the cover. - </para> - <para>Complete details of the book are - <ulink - url="http://www.oreilly.com/catalog/progxmlrpc/">available - from O'Reilly's web site.</ulink> - </para> - <para>I'm responsible for the chapter on PHP, which includes a - worked example of creating a forum server, and hooking it up - the O'Reilly's <ulink - url="http://meerkat.oreillynet.com/">Meerkat</ulink> service - in order to allow commenting on news stories from around the - Web.</para> - <para>If you've benefitted from the effort I've put into writing - this software, then please consider buying the book!</para> - </sect1> - </chapter> - <chapter id="apidocs"> - <title>Class documentation</title> - <sect1 id="xmlrpc-client" xreflabel="xmlrpc_client"> - <title>xmlrpc_client</title> - <para>This is the basic class used to represent a client of an - XML-RPC server.</para> - <sect2> - <title>Creation</title> - <para>The constructor has the following syntax:</para> - <funcsynopsis> - <funcprototype> - <funcdef>$client=new xmlrpc_client</funcdef> - <paramdef><parameter>$server_path</parameter></paramdef> - <paramdef><parameter>$server_hostname</parameter></paramdef> - <paramdef><parameter>$server_port</parameter></paramdef> - </funcprototype> - </funcsynopsis> - <para>Here's an example client set up to query Userland's XML-RPC - server at <emphasis>betty.userland.com</emphasis>:</para> - <programlisting> -$client=new xmlrpc_client("/RPC2", "betty.userland.com", 80);</programlisting> - <para>The <parameter>server_port</parameter> parameter is - optional, and if omitted will default to 80 when using - HTTP and 443 when using HTTPS (see the "send" method below.)</para> - - </sect2> - <sect2> - <title>Methods</title> - <para>This class supports the following methods.</para> - <sect3 id="xmlrpc-client-send" xreflabel="xmlrpc_client->send"> - <title>send</title> - <para>This method takes the form:</para> - <funcsynopsis> - <funcprototype> - <funcdef>$response=$client->send</funcdef> - <paramdef><parameter>$xmlrpc_message</parameter></paramdef> - <paramdef><parameter>$timeout</parameter></paramdef> - <paramdef><parameter>$server_method</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <para>Where <parameter>$xmlrpc_message</parameter> is an - instance of <classname>xmlrpcmsg</classname> (see <xref - linkend="xmlrpcmsg">), and - <parameter>$response</parameter> is an - instance of <classname>xmlrpcresp</classname> (see <xref - linkend="xmlrpcresp">).</para> - - <para>The <parameter>$timeout</parameter> is optional, and - will be set to <literal>0</literal> (wait forever) if - omitted. This timeout value is passed to - <function>fsockopen()</function>.</para> - - <para>The <parameter>server_method</parameter> parameter is - optional, and if omitted will default to 'http'. The only - other valid value is 'https', which will use an SSL HTTP - connection to connect to the remote server. Note that your - PHP must have the "curl" extensions compiled in in order to - use this feature. Note that when using SSL you should - normally set your port number to 443, unless the SSL server - you are contacting runs at any other port.</para> - <warning> - <para>PHP 4.0.2 or greater is required for SSL - functionality. - PHP 4.0.6 has a bug which prevents SSL - working.</para> - </warning> - <para>If the value of <parameter>$response</parameter> is - <literal>0</literal> rather than an - <classname>xmlrpcresp</classname> object, then this - signifies an I/O error has occured. You can find out what - the I/O error was from the values - <function>$client->errno</function> and - <function>$client->errstring</function>. - </para> - <para>In addition to low-level errors, the XML-RPC server you - were querying may return an error in the - <classname>xmlrpcresp</classname> object. See <xref - linkend="xmlrpcresp"> for details of - how to handle these errors. - </para> - </sect3> - - <sect3> - <title>setCredentials</title> - <funcsynopsis> - <funcprototype> - <funcdef>$client->setCredentials</funcdef> - <paramdef><parameter>$username</parameter></paramdef> - <paramdef><parameter>$password</parameter></paramdef> - </funcprototype> - </funcsynopsis> - <para>This method sets the username and password for authorizing the - client to a server. With the default (HTTP) transport, this - information is used for HTTP Basic authorization. - - </para> - </sect3> - <sect3> - <title>setCertificate</title> - <funcsynopsis> - <funcprototype> - <funcdef>$client->setCertificate</funcdef> - <paramdef><parameter>$certificate</parameter></paramdef> - <paramdef><parameter>$passphrase</parameter></paramdef> - </funcprototype> - </funcsynopsis> - <para>This method sets the optional certificate and passphrase - used in SSL-enabled communication with a remote server - (when the <parameter>server_method</parameter> is set to - 'https' in the client's construction). - </para> - <para>The <parameter>certificate</parameter> parameter must - be the filename of a PEM formatted certificate. The - <parameter>passphrase</parameter> parameter must contain - the password required to use the certificate.</para> - <para>This requires the "curl" extensions to be compiled - into your installation of PHP.</para> - </sect3> - <sect3> - <title>setSSLVerifyPeer</title> - <funcsynopsis> - <funcprototype> - <funcdef>$client->setSSLVerifyPeer</funcdef> - <paramdef><parameter>$i</parameter></paramdef> - </funcprototype> - </funcsynopsis> - <para>This method defines whether connections made to XMLRPC - backends via HTTPS should verify the remote host's SSL - certificate, and cause the connection to fail if the cert - verification fails. $i should be a boolean value. - </para> - </sect3> - <sect3> - <title>setSSLVerifyHost</title> - <funcsynopsis> - <funcprototype> - <funcdef>$client->setSSLVerifyHost</funcdef> - <paramdef><parameter>$i</parameter></paramdef> - </funcprototype> - </funcsynopsis> - <para>This method defines whether connections made to XMLRPC - backends via HTTPS should verify the remote host's SSL - certificate's common name (CN). By default, only the existence - of a CN is checked. $i should be an integer value; 0 to not - check the CN at all, 1 to merely check for its existence, and - 2 to check that the CN on the certificate matches the hostname - that is being connected to. - </para> - </sect3> - - - <sect3> - <title>setDebug</title> - <funcsynopsis> - <funcprototype> - <funcdef>$client->setDebug</funcdef> - <paramdef><parameter>$debugOn</parameter></paramdef> - </funcprototype> - </funcsynopsis> - <para><parameter>$debugOn</parameter> is either - <literal>0</literal> or <literal>1</literal> depending on - whether you require the client to print debugging - information to the browser. The default is not to output - this information.</para> - <para> - The debugging information includes the raw data returned - from the XML-RPC server it was querying, and the PHP value - the client attempts to create to represent the value - returned by the server. This option can be very useful when - debugging servers as it allows you to see exactly what the - server returns. - </para> - </sect3> - </sect2> - </sect1> - <sect1 id="xmlrpcmsg" xreflabel="xmlrpcmsg"> - <title>xmlrpcmsg</title> - <para>This class provides a representation for a request to an - XML-RPC server. A client sends an - <classname>xmlrpcmsg</classname> to a server, and receives back - an <classname>xmlrpcresp</classname> (see <xref - linkend="xmlrpc-client-send">).</para> - <sect2> - <title>Creation</title> - <para>The constructor takes the following form:</para> - <funcsynopsis> - <!-- one of (funcprototype funcdef) --> - <funcprototype> - <funcdef>$msg=new xmlrpcmsg</funcdef> - <paramdef><parameter>$methodName</parameter></paramdef> - <paramdef><parameter>$parameterArray</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <para>Where <parameter>$methodName</parameter> is a string - indicating the name of the method you wish to invoke, and - <parameter>$parameterArray</parameter> is a simple - <classname>Array</classname> of - <classname>xmlrpcval</classname> objects. Here's an example - message to the <emphasis>US state name</emphasis> server: - </para> - <programlisting> -$msg=new xmlrpcmsg("examples.getStateName", - array(new xmlrpcval(23, "int"))); - </programlisting> - <para> - This example requests the name of state number 23. For more - information on <classname>xmlrpcval</classname> objects, see - <xref linkend="xmlrpcval">. - </para> - </sect2> - <sect2> - <title>Methods</title> - <sect3> - <title>serialize</title> - <funcsynopsis> - <funcprototype> - <funcdef>$outString=$msg->serialize</funcdef> - <paramdef></paramdef> - </funcprototype> - </funcsynopsis> - <para>Returns the an XML string representing the XML-RPC - message.</para> - </sect3> - <sect3> - <title>addParam</title> - <funcsynopsis> - <funcprototype> - <funcdef>$msg->addParam</funcdef> - <paramdef><parameter>$xmlrpcVal</parameter></paramdef> - </funcprototype> - </funcsynopsis> - <para>Adds the <classname>xmlrpcval</classname> - <parameter>$xmlrpcVal</parameter> to the parameter list for - this method call.</para> - </sect3> - <sect3> - <title>getParam</title> - <funcsynopsis> - <funcprototype> - <funcdef>$xmlrpcVal=$msg->getParam</funcdef> - <paramdef><parameter>$n</parameter></paramdef> - </funcprototype> - </funcsynopsis> - <para>Gets the <parameter>$n</parameter>th parameter in the - message. Use this method in server implementations. Returns - the <literal>undef</literal> value if no such parameter - exists.</para> - </sect3> - <sect3> - <title>getNumParams</title> - <funcsynopsis> - <funcprototype> - <funcdef>$n=$msg->getNumParams</funcdef> - <paramdef></paramdef> - </funcprototype> - </funcsynopsis> - <para> - Returns the number of parameters attached to this message. - </para> - </sect3> - <sect3> - <title>method</title> - <funcsynopsis> - <funcprototype> - <funcdef>$methName=$msg->method</funcdef> - <paramdef></paramdef> - </funcprototype> - <funcprototype> - <funcdef>$msg->method</funcdef> - <paramdef><parameter>$methName</parameter></paramdef> - </funcprototype> - </funcsynopsis> - <para>Gets or sets the method contained in the XML-RPC message.</para> - </sect3> - <sect3> - <title>parseResponse</title> - <funcsynopsis> - - <funcprototype> - <funcdef>$response=$msg->parseResponse</funcdef> - <paramdef><parameter>$xmlString</parameter></paramdef> - </funcprototype> - </funcsynopsis> - <para>Given an incoming XML-RPC server response contained in - the string - <parameter>$xmlString</parameter>, this method constructs - an <classname>xmlrpcresp</classname> response object and - returns it, setting error codes as appropriate (see <xref - linkend="xmlrpc-client-send">). - </para> - <para> - This method processes any HTTP/MIME headers it finds. - </para> - </sect3> - <sect3> - <title>parseResponseFile</title> - <funcsynopsis> - <funcprototype> - <funcdef>$response=$msg->parseResponseFile</funcdef> - <paramdef><parameter>$fileHandle</parameter></paramdef> - </funcprototype> - </funcsynopsis> - <para>Given an incoming XML-RPC server response on the file handle - <parameter>$fileHandle</parameter>, this method reads the - data and passes it to <function>parseResponse</function> - </para> - <para> - This method is useful to construct responses from - pre-prepared files (see files <literal>demo1.txt, demo2.txt, - demo3.txt</literal> in this distribution). It processes - any HTTP headers it finds. - </para> - </sect3> - </sect2> - </sect1> - <sect1 id="xmlrpcresp" xreflabel="xmlrpcresp"> - <title>xmlrpcresp</title> - <para>This class is used to contain responses to XML-RPC - requests. A server method handler will construct an - <classname>xmlrpcresp</classname> and pass it as a return value. - This same value will be returned by the result of an invocation of - the <function>send</function> method of the - <classname>xmlrpc_client</classname> class.</para> - <sect2> - <title>Creation</title> - <funcsynopsis> - <!-- one of (funcprototype funcdef) --> - <funcprototype> - <funcdef>$resp=new xmlrpcresp</funcdef> - <!-- one of (paramdef varargs void) --> - <paramdef><parameter>$xmlrpcval</parameter></paramdef> - </funcprototype> - <funcprototype> - <funcdef>$resp=new xmlrpcresp</funcdef> - <paramdef><parameter>0</parameter></paramdef> - <paramdef><parameter - >$errcode</parameter></paramdef> - <paramdef><parameter - >$errstring</parameter></paramdef> - </funcprototype> - </funcsynopsis> - <para>The first instance is used when execution has happened - without difficulty: <parameter>$xmlrpcval</parameter> is an - <classname>xmlrpcval</classname> value with the result of the - method execution contained in it.</para> - <para> - The second type of constructor is used in case of - failure. <parameter>$errcode</parameter> and - <parameter>$errstring</parameter> are used to provide - indication of what has gone wrong. See <xref - linkend="xmlrpc-server"> for more information on passing - error codes. - </para> - </sect2> - <sect2> - <title>Methods</title> - <sect3> - <title>faultCode</title> - <funcsynopsis> - <funcprototype> - <funcdef>$fn=$resp->faultCode</funcdef> - <paramdef></paramdef> - </funcprototype> - </funcsynopsis> - <para>Returns the integer fault code return from the XML-RPC - response <parameter>$resp</parameter>. - A zero value indicates success, any other value - indicates a failure response.</para> - </sect3> - <sect3> - <title>faultString</title> - <funcsynopsis> - <funcprototype> - <funcdef>$fs=$resp->faultString</funcdef> - <paramdef></paramdef> - </funcprototype> - </funcsynopsis> - <para> - Returns the human readable explanation of the fault - indicated by <function>$resp->faultCode</function>. - </para> - </sect3> - <sect3> - <title>value</title> - <funcsynopsis> - <funcprototype> - <funcdef>$xmlrpcVal=$resp->value</funcdef> - <paramdef></paramdef> - </funcprototype> - </funcsynopsis> - <para> - Returns an <classname>xmlrpcval</classname> object - containing the return value sent by the server. If the - response's <function>faultCode</function> is non-zero then - the value returned by this method should not be used (it may - not even be an object). - </para> - </sect3> - <sect3> - <title>serialize</title><para></para> - <funcsynopsis> - <funcprototype> - <funcdef>$outString=$resp->serialize</funcdef> - <paramdef></paramdef> - </funcprototype> - </funcsynopsis> - <para>Returns an XML string representation of the response.</para> - </sect3> - </sect2> - </sect1> - <sect1 id="xmlrpcval" xreflabel="xmlrpcval"> - <title>xmlrpcval</title> - <para>This is where a lot of the hard work gets done. This class - enables the creation and encapsulation of values for XML-RPC. - </para> - <para> - Ensure you've read the XML-RPC spec at <ulink - url="http://www.xmlrpc.com/stories/storyReader$7">http://www.xmlrpc.com/stories/storyReader$7</ulink> - before reading on as it will make things clearer. - </para> - <para>The <classname>xmlrpcval</classname> class can store - arbitrarily complicated values using the following types: - <literal>i4 int boolean string double dateTime.iso8601 base64 - array struct</literal>. You should refer to the <ulink - url="http://www.xmlrpc.com/stories/storyReader$7">spec</ulink> - for more information on what each of these types mean. - </para> - <sect2> - <title>Notes on types</title> - <sect3> - <title>int</title> - <para>The type <classname>i4</classname> is accepted as a - synonym for <classname>int</classname>. The value parsing - code will always convert <classname>i4</classname> to - <classname>int</classname>: <classname>int</classname> - is regarded by this implementation as the canonical name for - this type.</para> - </sect3> - <sect3> - <title>base64</title> - <para>Base 64 encoding is performed transparently to the - caller when using this type. Therefore you ought to - consider it as a "binary" data type, for use when you want - to pass none 7-bit clean data. Decoding is also - transparent. - </para> - </sect3> - <sect3> - <title>boolean</title> - <para>The values <literal>true</literal> and - <literal>1</literal> map to <literal>true</literal>. All - other values (including the empty string) - are converted to <literal>false</literal>. - </para> - </sect3> - <sect3> - <title>string</title> - <para> - The characters <literal>< > "</literal> and - <literal>&</literal> are converted to their entity - equivalents <literal>&lt; &gt; - &quot;</literal> and <literal>&amp;</literal> - for transport through XML-RPC. The current XML-RPC spec - recommends only encoding <literal>< &</literal> but - this implementation goes further, for reasons explained by - <ulink url="http://www.w3.org/TR/REC-xml#syntax">the XML 1.0 - recommendation</ulink>. - </para><para>TODO: <literal> &apos;</literal> entity not - yet supported</para> - </sect3> - </sect2> - <sect2 id="xmlrpcval-creation" xreflabel="xmlrpcval constructors"> - <title>Creation</title> - <para>The constructor is the normal way to create an - <classname>xmlrpcval</classname>. The constructor can take - these forms: - </para> - <funcsynopsis> - <!-- one of (funcprototype funcdef) --> - <funcprototype> - <funcdef>$myVal=new xmlrpcval</funcdef> - <!-- one of (paramdef varargs void) --> - <paramdef></paramdef> - </funcprototype> - <funcprototype> - <funcdef>$myVal=new xmlrpcval</funcdef> - <!-- one of (paramdef varargs void) --> - <paramdef><parameter>$stringVal</parameter></paramdef> - </funcprototype> - <funcprototype> - <funcdef>$myVal=new xmlrpcval</funcdef> - <!-- one of (paramdef varargs void) --> - <paramdef><parameter>$scalarVal</parameter></paramdef> - <paramdef><parameter>"int" | "boolean" | "string" | "double" | "dateTime.iso8601" | "base64"</parameter></paramdef> - </funcprototype> - <funcprototype> - <funcdef>$myVal=new xmlrpcval</funcdef> - <!-- one of (paramdef varargs void) --> - <paramdef><parameter>$arrayVal</parameter></paramdef> - <paramdef><parameter>"array" | "struct"</parameter></paramdef> - </funcprototype> - </funcsynopsis> - <para>The first constructor creates an empty value, which must - be altered using the methods <function>addScalar</function>, - <function>addArray</function> or - <function>addStruct</function> before it can be used. - </para> - <para> - The second constructor creates a simple string value. - </para> - <para> - The third constructor is used to create a scalar value. The - second parameter must be a name of an XML-RPC type. Examples: - </para> - <programlisting> - $myInt=new xmlrpcvalue(1267, "int"); - $myString=new xmlrpcvalue("Hello, World!", "string"); - $myBool=new xmlrpcvalue(1, "boolean"); - </programlisting> - - <para> - The fourth constructor form can be used to compose complex - XML-RPC values. The first argument is either a simple array in - the case of an XML-RPC <classname>array</classname> or - an associative array in the case of a - <classname>struct</classname>. The elements of the array - <emphasis>must be <classname>xmlrpcval</classname> objects - themselves</emphasis>. - Examples:</para> - <programlisting> - $myArray=new xmlrpcval(array( - new xmlrpcval("Tom"), new xmlrpcval("Dick"), - new xmlrpcval("Harry")), "array"); - - $myStruct=new xmlrpcval(array( - "name" => new xmlrpcval("Tom"), - "age" => new xmlrpcval(34, "int"), - "geek" => new xmlrpcval(1, "boolean")), "struct"); - </programlisting> - <para>See the file <literal>vardemo.php</literal> in this - distribution for more examples.</para> - </sect2> - <sect2 id="xmlrpcval-methods" xreflabel="xmlrpcval methods"> - <title>Methods</title> - <sect3> - <title>addScalar</title> - <funcsynopsis> - <!-- one of (funcprototype funcdef) --> - <funcprototype> - <funcdef>$ok=$val->addScalar</funcdef> - <!-- one of (paramdef varargs void) --> - <paramdef><parameter>$stringVal</parameter></paramdef> - </funcprototype> - <funcprototype> - <funcdef>$ok=$val->addScalar</funcdef> - <!-- one of (paramdef varargs void) --> - <paramdef><parameter>$scalarVal</parameter></paramdef> - <paramdef><parameter>"int" | "boolean" | "string" | "double" | "dateTime.iso8601" | "base64"</parameter></paramdef> - </funcprototype> - - </funcsynopsis> - <para> - If <parameter>$val</parameter> is an empty - <classname>xmlrpcval</classname> this method makes it a - scalar value, and sets that value. If - <parameter>$val</parameter> is already a scalar value, then - no more scalars can be added and <literal>0</literal> is - returned. If all went OK, <literal>1</literal> is returned. - </para> - <para>There is a special case if <parameter>$val</parameter> - is an <classname>array</classname>: the scalar value passed - is appended to the array.</para> - </sect3> - <sect3> - <title>addArray</title> - <funcsynopsis> - <funcprototype> - <funcdef>$ok=$val->addArray</funcdef> - <paramdef><parameter>$arrayVal</parameter></paramdef> - </funcprototype> - </funcsynopsis> - <para>Turns an empty <classname>xmlrpcval</classname> into an - <classname>array</classname> with contents as specified by - <parameter>$arrayVal</parameter>. See the fourth - constructor form for more information.</para> - </sect3> - <sect3> - <title>addStruct</title> - <funcsynopsis> - <funcprototype> - <funcdef>$ok=$val->addArray</funcdef> - <paramdef><parameter>$assocArrayVal</parameter></paramdef> - </funcprototype> - </funcsynopsis> - <para>Turns an empty <classname>xmlrpcval</classname> into a - <classname>struct</classname> with contents as specified by - <parameter>$assocArrayVal</parameter>. See the fourth - constructor form for more information.</para> - </sect3> - <sect3> - <title>kindOf</title> - <funcsynopsis> - <funcprototype> - <funcdef>$kind=$val->kindOf</funcdef> - <paramdef></paramdef> - </funcprototype> - </funcsynopsis> - <para> - Returns a string containing "struct", "array" or "scalar" - describing the base type of the value. If it returns - "undef" it means that the value hasn't been initialised. - </para> - </sect3> - <sect3> - <title>serialize</title> - <funcsynopsis> - <funcprototype> - <funcdef>$outString=$val->serialize</funcdef> - <paramdef></paramdef> - </funcprototype> - </funcsynopsis> - <para> - Returns a string containing the XML-RPC representation of - this value. - </para> - </sect3> - <sect3> - <title>scalarval</title> - <funcsynopsis> - <funcprototype> - <funcdef>$scalarVal=$val->scalarval</funcdef> - <paramdef></paramdef> - </funcprototype> - </funcsynopsis> - <para> - If <function>$val->kindOf()=="scalar"</function>, this - method returns the actual PHP-language value of the scalar - (base 64 decoding is automatically handled here). - </para> - </sect3> - <sect3> - <title>scalartyp</title> - <funcsynopsis> - <funcprototype> - <funcdef>$typeName=$val->scalartyp</funcdef> - <paramdef></paramdef> - </funcprototype> - </funcsynopsis> - <para> - If <function>$val->kindOf()=="scalar"</function>, this - method returns a string denoting the type of the scalar. - As mentioned before, - <literal>i4</literal> is always coerced to <literal>int</literal>. - </para> - </sect3> - <sect3> - <title>arraymem</title> - <funcsynopsis> - <funcprototype> - <funcdef>$xmlrpcVal=$val->arraymem</funcdef> - <paramdef><parameter>$n</parameter></paramdef> - </funcprototype> - </funcsynopsis> - <para> - Returns the <parameter>$n</parameter>th element in the array - represented by the value <parameter>$val</parameter>. The - value returned is an <classname>xmlrpcval</classname> object. - </para> - </sect3> - <sect3> - <title>arraysize</title> - <funcsynopsis> - <funcprototype> - <funcdef>$len=$val->arraysize</funcdef> - <paramdef></paramdef> - </funcprototype> - </funcsynopsis> - <para>If <parameter>$val</parameter> is an - <classname>array</classname>, returns the number of elements - in that array. - </para> - </sect3> - <sect3> - <title>structmem</title> - <funcsynopsis> - <funcprototype> - <funcdef>$xmlrpcVal=$val->structmem</funcdef> - <paramdef><parameter>$memberName</parameter></paramdef> - </funcprototype> - </funcsynopsis> - <para> - Returns the element called - <parameter>$memberName</parameter> from the struct - represented by the value <parameter>$val</parameter>. The - value returned is an <classname>xmlrpcval</classname> object. - </para> - </sect3> - <sect3> - <title>structeach</title> - <funcsynopsis> - <funcprototype> - <funcdef>list($key,$value)=$val->structeach</funcdef> - <paramdef></paramdef> - </funcprototype> - </funcsynopsis> - <para> - Returns the next (key,value) pair from the struct, when - <parameter>$val</parameter> is a struct. See also - <xref linkend="structreset">. - </para> - </sect3> - - <sect3 id="structreset" xreflabel="structreset()"> - <title>structreset</title> - <funcsynopsis> - <funcprototype> - <funcdef>$val->structreset</funcdef> - <paramdef></paramdef> - </funcprototype> - </funcsynopsis> - <para> - Resets the internal pointer for - <function>structeach()</function> to the beginning of the - struct, where <parameter>$val</parameter> is a struct. - </para> - </sect3> - - </sect2> - </sect1> - <sect1 id="xmlrpc-server" xreflabel="xmlrpc_server"> - <title>xmlrpc_server</title> - <para>The current implementation of this class has been - kept as simple as possible. The constructor for the server - basically does all the work. Here's a minimal example:</para> - <programlisting> - function foo ($params) { - ... - } - - $s=new xmlrpc_server( array("examples.myFunc" => - array("function" => "foo"))); - </programlisting> - <para> - This performs everything you need to do with a server. The single - argument is an associative array from method names to function - names. The request is parsed and despatched to the relevant function, - which is reponsible for returning a - <classname>xmlrpcresp</classname> - object, which gets - serialized back to the caller. See server.php in this distribution for - examples of how to do this. - </para> - <para>Here is a more detailed look at what the handler function - <function>foo</function> may do:</para> - <programlisting> - - function foo ($params) { - global $xmlrpcerruser; // import user errcode value - - // $params is an Array of xmlrpcval objects - - if ($err) { - // this is an error condition - return new xmlrpcresp(0, $xmlrpcerruser+1, // user error 1 - "There's a problem, Captain"); - } else { - // this is a successful value being returned - return new xmlrpcresp(new xmlrpcval("All's fine!", "string")); - } - } - </programlisting> - <sect2> - <title>The dispatch map</title> - <para>The first argument to the - <function>xmlrpc_server</function> constructor is an array, - called the <emphasis>dispatch map</emphasis>. In this array is the - information the server needs to service the XML-RPC methods - you define.</para> - <para> - The dispatch map takes the form of an associative array of - associative arrays: the outer array has one entry for each - method, the key being the method name. The corresponding value - is another associative array, which can have the following members: - </para> - <itemizedlist> - <listitem> - <para><function>function</function> - this entry is - mandatory. It must be a name of a function in the - global scope which services the XML-RPC method.</para> - </listitem> - <listitem> - <para><function>signature</function> - this entry is an - array containg the possible signatures (see <xref - linkend="signatures">) for the method. If - this entry is present then the server will check that the - correct number and type of parameters have been sent for - this method before dispatching it. - </para> - </listitem> - <listitem> - <para> - <function>docstring</function> - this entry is a string - containing documentation for the method. The - documentation may contain HTML markup. - </para> - </listitem> - </itemizedlist> - <para>Look at the <filename>server.php</filename> example in the - distribution to see what a dispatch map looks like.</para> - </sect2> - <sect2 id="signatures" xreflabel="Signatures"><title>Method signatures</title> - <para>A signature is a description of a method's return type and - its parameter types. A method may have more than one - signature.</para> - <para>Within a server's dispatch map, each method has an array - of possible signatures. Each signature is an array of - types. The first entry is the return type. For instance, the - method <programlisting> -string examples.getStateName(int) -</programlisting> has the signature -<programlisting> -array($xmlrpcString, $xmlrpcInt) -</programlisting> and, assuming that it the only possible signature for - the method, might be used like this in server creation: -<programlisting> -$findstate_sig=array(array($xmlrpcString, $xmlrpcInt)); - -$findstate_doc='When passed an integer between 1 and 51 returns the -name of a US state, where the integer is the index of that state name -in an alphabetic order.'; - -$s=new xmlrpc_server( array( "examples.getStateName" => - array("function" => "findstate", - "signature" => $findstate_sig, - "docstring" => $findstate_doc))); -</programlisting> - - </para> - <para>For convenience the strings representing the XML-RPC types - have been encoded as global variables:<programlisting> -$xmlrpcI4="i4"; -$xmlrpcInt="int"; -$xmlrpcBoolean="boolean"; -$xmlrpcDouble="double"; -$xmlrpcString="string"; -$xmlrpcDateTime="dateTime.iso8601"; -$xmlrpcBase64="base64"; -$xmlrpcArray="array"; -$xmlrpcStruct="struct"; -</programlisting></para> - </sect2> - <sect2> - <title>Delaying the server response</title> - <para>You may want to construct the server, but for some reason - not fulfill the request immediately (security verification, for - instance). If you pass the constructor a second argument of - <literal>0</literal> this will have the desired effect. You - can then use the <function>service()</function> method of the - server class to service the request. For example:</para> - <programlisting> -$s=new xmlrpc_server($myDispMap, 0); - -// ... some code that does other stuff here - -$s->service(); -</programlisting> - </sect2> - <sect2> - <title>Fault reporting</title> - <para>Fault codes for your servers should start at the - value indicated by - the global <literal>$xmlrpcerruser</literal> + 1.</para> - <para>Standard errors returned by the server include:</para> - <variablelist> - <varlistentry> - <term><literal>1</literal> <phrase>Unknown method</phrase></term> - <listitem> - <para>Returned if the server was asked to dispatch a - method it didn't know about</para> - </listitem> - </varlistentry> - <varlistentry> - <term><literal>2</literal> <phrase>Invalid return payload</phrase></term> - <listitem> - <para>This error is actually generated by the client, not - server, code, but signifies that a server returned - something it couldn't understand.</para> - </listitem> - </varlistentry> - <varlistentry> - <term><literal>3</literal> <phrase>Incorrect parameters</phrase></term> - <listitem> - <para>This error is generated when the server has signature(s) - defined for a method, and the parameters passed by the - client do not match any of signatures.</para> - </listitem> - </varlistentry> - <varlistentry> - <term><literal>4</literal> <phrase>Can't introspect: method unknown</phrase></term> - <listitem> - <para>This error is generated by the builtin - <function>system.*</function> methods when any kind of - introspection is attempted on a method undefined by the - server.</para> - </listitem> - </varlistentry> -<varlistentry> - <term><literal>5</literal> <phrase>Didn't receive 200 OK from remote server</phrase></term> - <listitem> - <para>This error is generated by the client when a remote server - doesn't return HTTP/1.1 200 OK in response to a - request. A more detailed error report is added onto the - end of the phrase above.</para> - </listitem> - </varlistentry> - - <varlistentry> - <term><literal>100-</literal> <phrase>XML parse errors</phrase></term> - <listitem> - <para>Returns 100 plus the XML parser error code for the - fault that occurred. The - <function>faultString</function> returned explains where - the parse error was in the incoming XML stream.</para> - </listitem> - </varlistentry> - </variablelist> - </sect2> - </sect1> - </chapter> - - <chapter id="helpers"> - <title>Helper functions</title> - <para>XML-RPC for PHP contains some helper functions which you can - use to make processing of XML-RPC requests easier.</para> - <sect1> - <title>Date functions</title> - <para>The XML-RPC specification has this to say on dates:</para> - <blockquote> - <para>Don't assume a timezone. It should be specified by the server in its - documentation what assumptions it makes about timezones. </para> - </blockquote> - <para>Unfortunately, this means that date processing isn't - straightforward. Although XML-RPC uses ISO 8601 format dates, it - doesn't use the timezone specifier.</para> - <para>We strongly recommend that in every case where you pass - dates in XML-RPC calls, you use UTC (GMT) as your timezone. Most computer - languages include routines for handling GMT times natively, and - you won't have to translate between timezones.</para> - <para>For more information about dates, see <ulink - url="http://www.uic.edu/year2000/datefmt.html">ISO 8601: The Right Format for Dates</ulink>, which has a handy link to a PDF of the ISO 8601 specification. Note that XML-RPC uses exactly one of the available representations: CCYYMMDDTHH:MM:SS.</para> - - <sect2 id="iso8601encode" xreflabel="iso8601_encode()"> - <title>iso8601_encode</title> - <funcsynopsis> - <funcprototype> - <funcdef>$isoString=iso8601_encode</funcdef> - <paramdef><parameter>$time_t</parameter><parameter>$utc=0</parameter></paramdef> - </funcprototype> - </funcsynopsis> - <para>Returns an ISO 8601 formatted date generated from the - UNIX timestamp <parameter>$time_t</parameter>, as returned by - the PHP function <function>time()</function>. </para> - <para>The argument <parameter>$utc</parameter> can be omitted, - in which case it defaults to <literal>0</literal>. If it is - set to <literal>1</literal>, then the function corrects the - time passed in for UTC. Example: if you're in the GMT-6:00 - timezone and set <parameter>$utc</parameter>, you will receive - a date representation six hours ahead of your local - time.</para> - <para>The included demo program <filename>vardemo.php</filename> - includes a demonstration of this function.</para> - </sect2> - <sect2 id="iso8601decode" xreflabel="iso8601_decode()"> - <title>iso8601_decode</title> - <funcsynopsis> - <funcprototype> - <funcdef>$time_t=iso8601_decode</funcdef> - <paramdef><parameter>$isoString</parameter><parameter>$utc=0</parameter></paramdef> - </funcprototype> - </funcsynopsis> - <para>Returns a UNIX timestamp from an ISO 8601 encoded time and - date string passed in. If <parameter>$utc</parameter> is - <literal>1</literal> then <parameter>$isoString</parameter> is - assumed to be in the UTC timezone, and thus the - <parameter>$time_t</parameter> result is also UTC: otherwise, - the timezone is assumed to be your local timezone and you receive a local timestamp.</para> - </sect2> - </sect1> - - <sect1 id="arrayuse"> - <title>Easy use with PHP arrays</title> - <para>Dan Libby was kind enough to contribute two helper functions - that make it easier to translate to and from PHP arrays. This - makes it easier to deal with complex structures. At the moment - support is limited to <type>int</type>, <type>double</type>, - <type>string</type>, <type>array</type> and <type>struct</type> - datatypes; note also that all PHP arrays are encoded as structs - due to PHP not being able to tell the difference between a hash - and a linear array.</para> - <para>These functions reside in <filename>xmlrpc.inc</filename>.</para> - <sect2 id="xmlrpcdecode"> - <title>xmlrpc_decode</title> - <funcsynopsis> - <funcprototype> - <funcdef>$arr=xmlrpc_decode</funcdef> - <paramdef><parameter>$xmlrpc_val</parameter></paramdef> - </funcprototype> - </funcsynopsis> - <para> - Returns a PHP array stuffed with the values found in the - <type>xmlrpcval</type> <parameter>$xmlrpc_val</parameter>, - translated into native PHP types. - </para> - </sect2> - <sect2 id="xmlrpcencode"> - <title>xmlrpc_encode</title> - <funcsynopsis> - <funcprototype> - <funcdef>$xmlrpc_val=xmlrpc_encode</funcdef> - <paramdef><parameter>$phpval</parameter></paramdef> - </funcprototype> - </funcsynopsis> - <para> - Returns an <type>xmlrpcval</type> populated with the PHP - values in <parameter>$phpval</parameter>. Works recursively on - arrays and structs. Note that there's no support for non-base - types like base-64 values or date-times. - </para> - </sect2> - </sect1> - - <sect1 id="debugging"> - <title>Debugging aids</title> - <sect2> - <title>xmlrpc_debugmsg</title> - <funcsynopsis> - <funcprototype> - <funcdef>xmlrpc_debugmsg</funcdef> - <paramdef><parameter>$debugstring</parameter></paramdef> - </funcprototype> - </funcsynopsis> - <para>Sends the contents of <parameter>$debugstring</parameter> - in XML comments in the server return payload. If a PHP client - has debugging turned on, the user will be able to see server - debug information.</para> - <para>Use this function in your methods so you can pass back - diagnostic information. It is only available from - <filename>xmlrpcs.inc</filename>.</para> - </sect2> - </sect1> - - </chapter> - - <chapter id="reserved" xreflabel="Reserved methods"> - <title>Reserved methods</title> - <para>In order to extend the functionality offered by XML-RPC - servers without impacting on the protocol, I've included - experimental support in this release for reserved methods.</para> - <para>All methods starting with <function>system.</function> are - considered reserved by the server. PHP for XML-RPC itself provides - three special methods, detailed in this chapter.</para> - <sect1> - <title>system.listMethods</title> - <para>This method may be used to enumerate the methods implemented - by the XML-RPC server.</para> - <para>The <function>system.listMethods</function> method requires - no parameters. It returns an array of strings, each of which is - the name of a method implemented by the server.</para> - </sect1> - <sect1 id="sysmethodsig"> - <title>system.methodSignature</title> - <para>This method takes one parameter, the name of a method - implemented by the XML-RPC server.</para> - <para>It returns an array of possible signatures for this - method. A signature is an array of types. The first of these - types is the return type of the method, the rest are parameters.</para> - <para>Multiple signatures (ie. overloading) are permitted: this is - the reason that an array of signatures are returned by this - method.</para> - <para>Signatures themselves are restricted to the top level - parameters expected by a method. For instance if a method - expects one array of structs as a parameter, and it returns a - string, its signature is simply "string, array". If it expects - three integers, its signature is "string, int, int, - int".</para> - <para> - If no signature is defined for the method, a none-array value is - returned. Therefore this is the way to test for a non-signature, - if <parameter>$resp</parameter> below is the response object - from a method call to <function>system.methodSignature</function>: - </para> - - <programlisting> -$v=$resp->value(); -if ($v->kindOf()!="array") { - // then the method did not have a signature defined -} - </programlisting> - <para> - See the <filename>introspect.php</filename> demo included in - this distribution for an example of using this method. - </para> - </sect1> - <sect1 id="sysmethhelp"> - <title>system.methodHelp</title> - <para>This method takes one parameter, the name of a method - implemented by the XML-RPC server.</para> - <para> - It returns a documentation string describing the use of that - method. If no such string is available, an empty string is returned. - </para> - <para> - The documentation string may contain HTML markup. - </para> - </sect1> - </chapter> - - - <chapter id="examples" xreflabel="Examples"> - <title>Examples</title> - <para>The best examples are to be found in the sample files - included with the distribution. Some are included here.</para> - <sect1 id="statename"> - <title>XML-RPC client: state name query</title> - <para>Code to get the corresponding - state name from a number (1-50) from Dave Winer's server</para> - <programlisting> - $f=new xmlrpcmsg('examples.getStateName', - array(new xmlrpcval($HTTP_POST_VARS["stateno"], "int"))); - $c=new xmlrpc_client("/RPC2", "betty.userland.com", 80); - $r=$c->send($f); - $v=$r->value(); - if (!$r->faultCode()) { - print "State number ". $HTTP_POST_VARS["stateno"] . " is " . - $v->scalarval() . "<BR>"; - print "<HR>I got this value back<BR><PRE>" . - htmlentities($r->serialize()). "</PRE><HR>\n"; - } else { - print "Fault: "; - print "Code: " . $r->faultCode() . - " Reason '" .$r->faultString()."'<BR>"; - } - </programlisting> - </sect1> - </chapter> -</book> -<!-- Keep this comment at the end of the file -Local variables: -mode: sgml -sgml-omittag:nil -sgml-shorttag:t -sgml-minimize-attributes:nil -sgml-always-quote-attributes:t -sgml-indent-step:2 -sgml-indent-data:t -sgml-parent-document:nil -sgml-exposed-tags:nil -sgml-local-catalogs:nil -sgml-local-ecat-files:nil -sgml-namecase-general:t -sgml-general-insert-case:lower -End: ---> diff --git a/modules/xmlrpc/doc/xmlrpcmsg.html b/modules/xmlrpc/doc/xmlrpcmsg.html deleted file mode 100644 index 958ff3a2..00000000 --- a/modules/xmlrpc/doc/xmlrpcmsg.html +++ /dev/null @@ -1,507 +0,0 @@ -<HTML -><HEAD -><TITLE ->xmlrpcmsg</TITLE -><META -NAME="GENERATOR" -CONTENT="Modular DocBook HTML Stylesheet Version 1.77+"><LINK -REV="MADE" -HREF="edd@usefulinc.com"><LINK -REL="HOME" -TITLE="XML-RPC for PHP" -HREF="index.html"><LINK -REL="UP" -TITLE="Class documentation" -HREF="apidocs.html"><LINK -REL="PREVIOUS" -TITLE="Class documentation" -HREF="apidocs.html"><LINK -REL="NEXT" -TITLE="xmlrpcresp" -HREF="xmlrpcresp.html"></HEAD -><BODY -CLASS="SECT1" -BGCOLOR="#FFFFFF" -TEXT="#000000" -LINK="#0000FF" -VLINK="#840084" -ALINK="#0000FF" -><DIV -CLASS="NAVHEADER" -><TABLE -SUMMARY="Header navigation table" -WIDTH="100%" -BORDER="0" -CELLPADDING="0" -CELLSPACING="0" -><TR -><TH -COLSPAN="3" -ALIGN="center" ->XML-RPC for PHP: version 1.1</TH -></TR -><TR -><TD -WIDTH="10%" -ALIGN="left" -VALIGN="bottom" -><A -HREF="apidocs.html" -ACCESSKEY="P" ->Prev</A -></TD -><TD -WIDTH="80%" -ALIGN="center" -VALIGN="bottom" ->Chapter 5. Class documentation</TD -><TD -WIDTH="10%" -ALIGN="right" -VALIGN="bottom" -><A -HREF="xmlrpcresp.html" -ACCESSKEY="N" ->Next</A -></TD -></TR -></TABLE -><HR -ALIGN="LEFT" -WIDTH="100%"></DIV -><DIV -CLASS="SECT1" -><H1 -CLASS="SECT1" -><A -NAME="XMLRPCMSG" -></A ->xmlrpcmsg</H1 -><P ->This class provides a representation for a request to an - XML-RPC server. A client sends an - <TT -CLASS="CLASSNAME" ->xmlrpcmsg</TT -> to a server, and receives back - an <TT -CLASS="CLASSNAME" ->xmlrpcresp</TT -> (see <A -HREF="apidocs.html#XMLRPC-CLIENT-SEND" ->xmlrpc_client->send</A ->).</P -><DIV -CLASS="SECT2" -><H2 -CLASS="SECT2" -><A -NAME="AEN289" -></A ->Creation</H2 -><P ->The constructor takes the following form:</P -><DIV -CLASS="FUNCSYNOPSIS" -><A -NAME="AEN292" -></A -><P -></P -><P -><CODE -><CODE -CLASS="FUNCDEF" ->$msg=new xmlrpcmsg</CODE ->($methodName, $parameterArray);</CODE -></P -><P -></P -></DIV -><P ->Where <TT -CLASS="PARAMETER" -><I ->$methodName</I -></TT -> is a string - indicating the name of the method you wish to invoke, and - <TT -CLASS="PARAMETER" -><I ->$parameterArray</I -></TT -> is a simple - <TT -CLASS="CLASSNAME" ->Array</TT -> of - <TT -CLASS="CLASSNAME" ->xmlrpcval</TT -> objects. Here's an example - message to the <SPAN -CLASS="emphasis" -><I -CLASS="EMPHASIS" ->US state name</I -></SPAN -> server: - </P -><PRE -CLASS="PROGRAMLISTING" ->$msg=new xmlrpcmsg("examples.getStateName", - array(new xmlrpcval(23, "int"))); - </PRE -><P -> This example requests the name of state number 23. For more - information on <TT -CLASS="CLASSNAME" ->xmlrpcval</TT -> objects, see - <A -HREF="xmlrpcval.html" ->xmlrpcval</A ->. - </P -></DIV -><DIV -CLASS="SECT2" -><H2 -CLASS="SECT2" -><A -NAME="AEN309" -></A ->Methods</H2 -><DIV -CLASS="SECT3" -><H3 -CLASS="SECT3" -><A -NAME="AEN311" -></A ->serialize</H3 -><DIV -CLASS="FUNCSYNOPSIS" -><A -NAME="AEN313" -></A -><P -></P -><P -><CODE -><CODE -CLASS="FUNCDEF" ->$outString=$msg->serialize</CODE ->();</CODE -></P -><P -></P -></DIV -><P ->Returns the an XML string representing the XML-RPC - message.</P -></DIV -><DIV -CLASS="SECT3" -><H3 -CLASS="SECT3" -><A -NAME="AEN318" -></A ->addParam</H3 -><DIV -CLASS="FUNCSYNOPSIS" -><A -NAME="AEN320" -></A -><P -></P -><P -><CODE -><CODE -CLASS="FUNCDEF" ->$msg->addParam</CODE ->($xmlrpcVal);</CODE -></P -><P -></P -></DIV -><P ->Adds the <TT -CLASS="CLASSNAME" ->xmlrpcval</TT -> - <TT -CLASS="PARAMETER" -><I ->$xmlrpcVal</I -></TT -> to the parameter list for - this method call.</P -></DIV -><DIV -CLASS="SECT3" -><H3 -CLASS="SECT3" -><A -NAME="AEN328" -></A ->getParam</H3 -><DIV -CLASS="FUNCSYNOPSIS" -><A -NAME="AEN330" -></A -><P -></P -><P -><CODE -><CODE -CLASS="FUNCDEF" ->$xmlrpcVal=$msg->getParam</CODE ->($n);</CODE -></P -><P -></P -></DIV -><P ->Gets the <TT -CLASS="PARAMETER" -><I ->$n</I -></TT ->th parameter in the - message. Use this method in server implementations. Returns - the <TT -CLASS="LITERAL" ->undef</TT -> value if no such parameter - exists.</P -></DIV -><DIV -CLASS="SECT3" -><H3 -CLASS="SECT3" -><A -NAME="AEN338" -></A ->getNumParams</H3 -><DIV -CLASS="FUNCSYNOPSIS" -><A -NAME="AEN340" -></A -><P -></P -><P -><CODE -><CODE -CLASS="FUNCDEF" ->$n=$msg->getNumParams</CODE ->();</CODE -></P -><P -></P -></DIV -><P -> Returns the number of parameters attached to this message. - </P -></DIV -><DIV -CLASS="SECT3" -><H3 -CLASS="SECT3" -><A -NAME="AEN345" -></A ->method</H3 -><DIV -CLASS="FUNCSYNOPSIS" -><A -NAME="AEN347" -></A -><P -></P -><P -><CODE -><CODE -CLASS="FUNCDEF" ->$methName=$msg->method</CODE ->();</CODE -></P -><P -><CODE -><CODE -CLASS="FUNCDEF" ->$msg->method</CODE ->($methName);</CODE -></P -><P -></P -></DIV -><P ->Gets or sets the method contained in the XML-RPC message.</P -></DIV -><DIV -CLASS="SECT3" -><H3 -CLASS="SECT3" -><A -NAME="AEN356" -></A ->parseResponse</H3 -><DIV -CLASS="FUNCSYNOPSIS" -><A -NAME="AEN358" -></A -><P -></P -><P -><CODE -><CODE -CLASS="FUNCDEF" ->$response=$msg->parseResponse</CODE ->($xmlString);</CODE -></P -><P -></P -></DIV -><P ->Given an incoming XML-RPC server response contained in - the string - <TT -CLASS="PARAMETER" -><I ->$xmlString</I -></TT ->, this method constructs - an <TT -CLASS="CLASSNAME" ->xmlrpcresp</TT -> response object and - returns it, setting error codes as appropriate (see <A -HREF="apidocs.html#XMLRPC-CLIENT-SEND" ->xmlrpc_client->send</A ->). - </P -><P -> This method processes any HTTP/MIME headers it finds. - </P -></DIV -><DIV -CLASS="SECT3" -><H3 -CLASS="SECT3" -><A -NAME="AEN368" -></A ->parseResponseFile</H3 -><DIV -CLASS="FUNCSYNOPSIS" -><A -NAME="AEN370" -></A -><P -></P -><P -><CODE -><CODE -CLASS="FUNCDEF" ->$response=$msg->parseResponseFile</CODE ->($fileHandle);</CODE -></P -><P -></P -></DIV -><P ->Given an incoming XML-RPC server response on the file handle - <TT -CLASS="PARAMETER" -><I ->$fileHandle</I -></TT ->, this method reads the - data and passes it to <TT -CLASS="FUNCTION" ->parseResponse</TT -> - </P -><P -> This method is useful to construct responses from - pre-prepared files (see files <TT -CLASS="LITERAL" ->demo1.txt, demo2.txt, - demo3.txt</TT -> in this distribution). It processes - any HTTP headers it finds. - </P -></DIV -></DIV -></DIV -><DIV -CLASS="NAVFOOTER" -><HR -ALIGN="LEFT" -WIDTH="100%"><TABLE -SUMMARY="Footer navigation table" -WIDTH="100%" -BORDER="0" -CELLPADDING="0" -CELLSPACING="0" -><TR -><TD -WIDTH="33%" -ALIGN="left" -VALIGN="top" -><A -HREF="apidocs.html" -ACCESSKEY="P" ->Prev</A -></TD -><TD -WIDTH="34%" -ALIGN="center" -VALIGN="top" -><A -HREF="index.html" -ACCESSKEY="H" ->Home</A -></TD -><TD -WIDTH="33%" -ALIGN="right" -VALIGN="top" -><A -HREF="xmlrpcresp.html" -ACCESSKEY="N" ->Next</A -></TD -></TR -><TR -><TD -WIDTH="33%" -ALIGN="left" -VALIGN="top" ->Class documentation</TD -><TD -WIDTH="34%" -ALIGN="center" -VALIGN="top" -><A -HREF="apidocs.html" -ACCESSKEY="U" ->Up</A -></TD -><TD -WIDTH="33%" -ALIGN="right" -VALIGN="top" ->xmlrpcresp</TD -></TR -></TABLE -></DIV -></BODY -></HTML ->
\ No newline at end of file diff --git a/modules/xmlrpc/doc/xmlrpcresp.html b/modules/xmlrpc/doc/xmlrpcresp.html deleted file mode 100644 index d48216e3..00000000 --- a/modules/xmlrpc/doc/xmlrpcresp.html +++ /dev/null @@ -1,374 +0,0 @@ -<HTML -><HEAD -><TITLE ->xmlrpcresp</TITLE -><META -NAME="GENERATOR" -CONTENT="Modular DocBook HTML Stylesheet Version 1.77+"><LINK -REV="MADE" -HREF="edd@usefulinc.com"><LINK -REL="HOME" -TITLE="XML-RPC for PHP" -HREF="index.html"><LINK -REL="UP" -TITLE="Class documentation" -HREF="apidocs.html"><LINK -REL="PREVIOUS" -TITLE="xmlrpcmsg" -HREF="xmlrpcmsg.html"><LINK -REL="NEXT" -TITLE="xmlrpcval" -HREF="xmlrpcval.html"></HEAD -><BODY -CLASS="SECT1" -BGCOLOR="#FFFFFF" -TEXT="#000000" -LINK="#0000FF" -VLINK="#840084" -ALINK="#0000FF" -><DIV -CLASS="NAVHEADER" -><TABLE -SUMMARY="Header navigation table" -WIDTH="100%" -BORDER="0" -CELLPADDING="0" -CELLSPACING="0" -><TR -><TH -COLSPAN="3" -ALIGN="center" ->XML-RPC for PHP: version 1.1</TH -></TR -><TR -><TD -WIDTH="10%" -ALIGN="left" -VALIGN="bottom" -><A -HREF="xmlrpcmsg.html" -ACCESSKEY="P" ->Prev</A -></TD -><TD -WIDTH="80%" -ALIGN="center" -VALIGN="bottom" ->Chapter 5. Class documentation</TD -><TD -WIDTH="10%" -ALIGN="right" -VALIGN="bottom" -><A -HREF="xmlrpcval.html" -ACCESSKEY="N" ->Next</A -></TD -></TR -></TABLE -><HR -ALIGN="LEFT" -WIDTH="100%"></DIV -><DIV -CLASS="SECT1" -><H1 -CLASS="SECT1" -><A -NAME="XMLRPCRESP" -></A ->xmlrpcresp</H1 -><P ->This class is used to contain responses to XML-RPC - requests. A server method handler will construct an - <TT -CLASS="CLASSNAME" ->xmlrpcresp</TT -> and pass it as a return value. - This same value will be returned by the result of an invocation of - the <TT -CLASS="FUNCTION" ->send</TT -> method of the - <TT -CLASS="CLASSNAME" ->xmlrpc_client</TT -> class.</P -><DIV -CLASS="SECT2" -><H2 -CLASS="SECT2" -><A -NAME="AEN386" -></A ->Creation</H2 -><DIV -CLASS="FUNCSYNOPSIS" -><A -NAME="AEN388" -></A -><P -></P -><P -><CODE -><CODE -CLASS="FUNCDEF" ->$resp=new xmlrpcresp</CODE ->($xmlrpcval);</CODE -></P -><P -><CODE -><CODE -CLASS="FUNCDEF" ->$resp=new xmlrpcresp</CODE ->(0, $errcode, $errstring);</CODE -></P -><P -></P -></DIV -><P ->The first instance is used when execution has happened - without difficulty: <TT -CLASS="PARAMETER" -><I ->$xmlrpcval</I -></TT -> is an - <TT -CLASS="CLASSNAME" ->xmlrpcval</TT -> value with the result of the - method execution contained in it.</P -><P -> The second type of constructor is used in case of - failure. <TT -CLASS="PARAMETER" -><I ->$errcode</I -></TT -> and - <TT -CLASS="PARAMETER" -><I ->$errstring</I -></TT -> are used to provide - indication of what has gone wrong. See <A -HREF="xmlrpc-server.html" ->xmlrpc_server</A -> for more information on passing - error codes. - </P -></DIV -><DIV -CLASS="SECT2" -><H2 -CLASS="SECT2" -><A -NAME="AEN408" -></A ->Methods</H2 -><DIV -CLASS="SECT3" -><H3 -CLASS="SECT3" -><A -NAME="AEN410" -></A ->faultCode</H3 -><DIV -CLASS="FUNCSYNOPSIS" -><A -NAME="AEN412" -></A -><P -></P -><P -><CODE -><CODE -CLASS="FUNCDEF" ->$fn=$resp->faultCode</CODE ->();</CODE -></P -><P -></P -></DIV -><P ->Returns the integer fault code return from the XML-RPC - response <TT -CLASS="PARAMETER" -><I ->$resp</I -></TT ->. - A zero value indicates success, any other value - indicates a failure response.</P -></DIV -><DIV -CLASS="SECT3" -><H3 -CLASS="SECT3" -><A -NAME="AEN418" -></A ->faultString</H3 -><DIV -CLASS="FUNCSYNOPSIS" -><A -NAME="AEN420" -></A -><P -></P -><P -><CODE -><CODE -CLASS="FUNCDEF" ->$fs=$resp->faultString</CODE ->();</CODE -></P -><P -></P -></DIV -><P -> Returns the human readable explanation of the fault - indicated by <TT -CLASS="FUNCTION" ->$resp->faultCode</TT ->. - </P -></DIV -><DIV -CLASS="SECT3" -><H3 -CLASS="SECT3" -><A -NAME="AEN426" -></A ->value</H3 -><DIV -CLASS="FUNCSYNOPSIS" -><A -NAME="AEN428" -></A -><P -></P -><P -><CODE -><CODE -CLASS="FUNCDEF" ->$xmlrpcVal=$resp->value</CODE ->();</CODE -></P -><P -></P -></DIV -><P -> Returns an <TT -CLASS="CLASSNAME" ->xmlrpcval</TT -> object - containing the return value sent by the server. If the - response's <TT -CLASS="FUNCTION" ->faultCode</TT -> is non-zero then - the value returned by this method should not be used (it may - not even be an object). - </P -></DIV -><DIV -CLASS="SECT3" -><H3 -CLASS="SECT3" -><A -NAME="AEN435" -></A ->serialize</H3 -><P -></P -><DIV -CLASS="FUNCSYNOPSIS" -><A -NAME="AEN438" -></A -><P -></P -><P -><CODE -><CODE -CLASS="FUNCDEF" ->$outString=$resp->serialize</CODE ->();</CODE -></P -><P -></P -></DIV -><P ->Returns an XML string representation of the response.</P -></DIV -></DIV -></DIV -><DIV -CLASS="NAVFOOTER" -><HR -ALIGN="LEFT" -WIDTH="100%"><TABLE -SUMMARY="Footer navigation table" -WIDTH="100%" -BORDER="0" -CELLPADDING="0" -CELLSPACING="0" -><TR -><TD -WIDTH="33%" -ALIGN="left" -VALIGN="top" -><A -HREF="xmlrpcmsg.html" -ACCESSKEY="P" ->Prev</A -></TD -><TD -WIDTH="34%" -ALIGN="center" -VALIGN="top" -><A -HREF="index.html" -ACCESSKEY="H" ->Home</A -></TD -><TD -WIDTH="33%" -ALIGN="right" -VALIGN="top" -><A -HREF="xmlrpcval.html" -ACCESSKEY="N" ->Next</A -></TD -></TR -><TR -><TD -WIDTH="33%" -ALIGN="left" -VALIGN="top" ->xmlrpcmsg</TD -><TD -WIDTH="34%" -ALIGN="center" -VALIGN="top" -><A -HREF="apidocs.html" -ACCESSKEY="U" ->Up</A -></TD -><TD -WIDTH="33%" -ALIGN="right" -VALIGN="top" ->xmlrpcval</TD -></TR -></TABLE -></DIV -></BODY -></HTML ->
\ No newline at end of file diff --git a/modules/xmlrpc/doc/xmlrpcval.html b/modules/xmlrpc/doc/xmlrpcval.html deleted file mode 100644 index 68489699..00000000 --- a/modules/xmlrpc/doc/xmlrpcval.html +++ /dev/null @@ -1,933 +0,0 @@ -<HTML -><HEAD -><TITLE ->xmlrpcval</TITLE -><META -NAME="GENERATOR" -CONTENT="Modular DocBook HTML Stylesheet Version 1.77+"><LINK -REV="MADE" -HREF="edd@usefulinc.com"><LINK -REL="HOME" -TITLE="XML-RPC for PHP" -HREF="index.html"><LINK -REL="UP" -TITLE="Class documentation" -HREF="apidocs.html"><LINK -REL="PREVIOUS" -TITLE="xmlrpcresp" -HREF="xmlrpcresp.html"><LINK -REL="NEXT" -TITLE="xmlrpc_server" -HREF="xmlrpc-server.html"></HEAD -><BODY -CLASS="SECT1" -BGCOLOR="#FFFFFF" -TEXT="#000000" -LINK="#0000FF" -VLINK="#840084" -ALINK="#0000FF" -><DIV -CLASS="NAVHEADER" -><TABLE -SUMMARY="Header navigation table" -WIDTH="100%" -BORDER="0" -CELLPADDING="0" -CELLSPACING="0" -><TR -><TH -COLSPAN="3" -ALIGN="center" ->XML-RPC for PHP: version 1.1</TH -></TR -><TR -><TD -WIDTH="10%" -ALIGN="left" -VALIGN="bottom" -><A -HREF="xmlrpcresp.html" -ACCESSKEY="P" ->Prev</A -></TD -><TD -WIDTH="80%" -ALIGN="center" -VALIGN="bottom" ->Chapter 5. Class documentation</TD -><TD -WIDTH="10%" -ALIGN="right" -VALIGN="bottom" -><A -HREF="xmlrpc-server.html" -ACCESSKEY="N" ->Next</A -></TD -></TR -></TABLE -><HR -ALIGN="LEFT" -WIDTH="100%"></DIV -><DIV -CLASS="SECT1" -><H1 -CLASS="SECT1" -><A -NAME="XMLRPCVAL" -></A ->xmlrpcval</H1 -><P ->This is where a lot of the hard work gets done. This class - enables the creation and encapsulation of values for XML-RPC. - </P -><P -> Ensure you've read the XML-RPC spec at <A -HREF="http://www.xmlrpc.com/stories/storyReader$7" -TARGET="_top" ->http://www.xmlrpc.com/stories/storyReader$7</A -> - before reading on as it will make things clearer. - </P -><P ->The <TT -CLASS="CLASSNAME" ->xmlrpcval</TT -> class can store - arbitrarily complicated values using the following types: - <TT -CLASS="LITERAL" ->i4 int boolean string double dateTime.iso8601 base64 - array struct</TT ->. You should refer to the <A -HREF="http://www.xmlrpc.com/stories/storyReader$7" -TARGET="_top" ->spec</A -> - for more information on what each of these types mean. - </P -><DIV -CLASS="SECT2" -><H2 -CLASS="SECT2" -><A -NAME="AEN452" -></A ->Notes on types</H2 -><DIV -CLASS="SECT3" -><H3 -CLASS="SECT3" -><A -NAME="AEN454" -></A ->int</H3 -><P ->The type <TT -CLASS="CLASSNAME" ->i4</TT -> is accepted as a - synonym for <TT -CLASS="CLASSNAME" ->int</TT ->. The value parsing - code will always convert <TT -CLASS="CLASSNAME" ->i4</TT -> to - <TT -CLASS="CLASSNAME" ->int</TT ->: <TT -CLASS="CLASSNAME" ->int</TT -> - is regarded by this implementation as the canonical name for - this type.</P -></DIV -><DIV -CLASS="SECT3" -><H3 -CLASS="SECT3" -><A -NAME="AEN462" -></A ->base64</H3 -><P ->Base 64 encoding is performed transparently to the - caller when using this type. Therefore you ought to - consider it as a "binary" data type, for use when you want - to pass none 7-bit clean data. Decoding is also - transparent. - </P -></DIV -><DIV -CLASS="SECT3" -><H3 -CLASS="SECT3" -><A -NAME="AEN465" -></A ->boolean</H3 -><P ->The values <TT -CLASS="LITERAL" ->true</TT -> and - <TT -CLASS="LITERAL" ->1</TT -> map to <TT -CLASS="LITERAL" ->true</TT ->. All - other values (including the empty string) - are converted to <TT -CLASS="LITERAL" ->false</TT ->. - </P -></DIV -><DIV -CLASS="SECT3" -><H3 -CLASS="SECT3" -><A -NAME="AEN472" -></A ->string</H3 -><P -> The characters <TT -CLASS="LITERAL" ->< > "</TT -> and - <TT -CLASS="LITERAL" ->&</TT -> are converted to their entity - equivalents <TT -CLASS="LITERAL" ->&lt; &gt; - &quot;</TT -> and <TT -CLASS="LITERAL" ->&amp;</TT -> - for transport through XML-RPC. The current XML-RPC spec - recommends only encoding <TT -CLASS="LITERAL" ->< &</TT -> but - this implementation goes further, for reasons explained by - <A -HREF="http://www.w3.org/TR/REC-xml#syntax" -TARGET="_top" ->the XML 1.0 - recommendation</A ->. - </P -><P ->TODO: <TT -CLASS="LITERAL" -> &apos;</TT -> entity not - yet supported</P -></DIV -></DIV -><DIV -CLASS="SECT2" -><H2 -CLASS="SECT2" -><A -NAME="XMLRPCVAL-CREATION" -></A ->Creation</H2 -><P ->The constructor is the normal way to create an - <TT -CLASS="CLASSNAME" ->xmlrpcval</TT ->. The constructor can take - these forms: - </P -><DIV -CLASS="FUNCSYNOPSIS" -><A -NAME="AEN487" -></A -><P -></P -><P -><CODE -><CODE -CLASS="FUNCDEF" ->$myVal=new xmlrpcval</CODE ->();</CODE -></P -><P -><CODE -><CODE -CLASS="FUNCDEF" ->$myVal=new xmlrpcval</CODE ->($stringVal);</CODE -></P -><P -><CODE -><CODE -CLASS="FUNCDEF" ->$myVal=new xmlrpcval</CODE ->($scalarVal, "int" | "boolean" | "string" | "double" | "dateTime.iso8601" | "base64");</CODE -></P -><P -><CODE -><CODE -CLASS="FUNCDEF" ->$myVal=new xmlrpcval</CODE ->($arrayVal, "array" | "struct");</CODE -></P -><P -></P -></DIV -><P ->The first constructor creates an empty value, which must - be altered using the methods <TT -CLASS="FUNCTION" ->addScalar</TT ->, - <TT -CLASS="FUNCTION" ->addArray</TT -> or - <TT -CLASS="FUNCTION" ->addStruct</TT -> before it can be used. - </P -><P -> The second constructor creates a simple string value. - </P -><P -> The third constructor is used to create a scalar value. The - second parameter must be a name of an XML-RPC type. Examples: - </P -><PRE -CLASS="PROGRAMLISTING" -> $myInt=new xmlrpcvalue(1267, "int"); - $myString=new xmlrpcvalue("Hello, World!", "string"); - $myBool=new xmlrpcvalue(1, "boolean"); - </PRE -><P -> The fourth constructor form can be used to compose complex - XML-RPC values. The first argument is either a simple array in - the case of an XML-RPC <TT -CLASS="CLASSNAME" ->array</TT -> or - an associative array in the case of a - <TT -CLASS="CLASSNAME" ->struct</TT ->. The elements of the array - <SPAN -CLASS="emphasis" -><I -CLASS="EMPHASIS" ->must be <TT -CLASS="CLASSNAME" ->xmlrpcval</TT -> objects - themselves</I -></SPAN ->. - Examples:</P -><PRE -CLASS="PROGRAMLISTING" -> $myArray=new xmlrpcval(array( - new xmlrpcval("Tom"), new xmlrpcval("Dick"), - new xmlrpcval("Harry")), "array"); - - $myStruct=new xmlrpcval(array( - "name" => new xmlrpcval("Tom"), - "age" => new xmlrpcval(34, "int"), - "geek" => new xmlrpcval(1, "boolean")), "struct"); - </PRE -><P ->See the file <TT -CLASS="LITERAL" ->vardemo.php</TT -> in this - distribution for more examples.</P -></DIV -><DIV -CLASS="SECT2" -><H2 -CLASS="SECT2" -><A -NAME="XMLRPCVAL-METHODS" -></A ->Methods</H2 -><DIV -CLASS="SECT3" -><H3 -CLASS="SECT3" -><A -NAME="AEN524" -></A ->addScalar</H3 -><DIV -CLASS="FUNCSYNOPSIS" -><A -NAME="AEN526" -></A -><P -></P -><P -><CODE -><CODE -CLASS="FUNCDEF" ->$ok=$val->addScalar</CODE ->($stringVal);</CODE -></P -><P -><CODE -><CODE -CLASS="FUNCDEF" ->$ok=$val->addScalar</CODE ->($scalarVal, "int" | "boolean" | "string" | "double" | "dateTime.iso8601" | "base64");</CODE -></P -><P -></P -></DIV -><P -> If <TT -CLASS="PARAMETER" -><I ->$val</I -></TT -> is an empty - <TT -CLASS="CLASSNAME" ->xmlrpcval</TT -> this method makes it a - scalar value, and sets that value. If - <TT -CLASS="PARAMETER" -><I ->$val</I -></TT -> is already a scalar value, then - no more scalars can be added and <TT -CLASS="LITERAL" ->0</TT -> is - returned. If all went OK, <TT -CLASS="LITERAL" ->1</TT -> is returned. - </P -><P ->There is a special case if <TT -CLASS="PARAMETER" -><I ->$val</I -></TT -> - is an <TT -CLASS="CLASSNAME" ->array</TT ->: the scalar value passed - is appended to the array.</P -></DIV -><DIV -CLASS="SECT3" -><H3 -CLASS="SECT3" -><A -NAME="AEN546" -></A ->addArray</H3 -><DIV -CLASS="FUNCSYNOPSIS" -><A -NAME="AEN548" -></A -><P -></P -><P -><CODE -><CODE -CLASS="FUNCDEF" ->$ok=$val->addArray</CODE ->($arrayVal);</CODE -></P -><P -></P -></DIV -><P ->Turns an empty <TT -CLASS="CLASSNAME" ->xmlrpcval</TT -> into an - <TT -CLASS="CLASSNAME" ->array</TT -> with contents as specified by - <TT -CLASS="PARAMETER" -><I ->$arrayVal</I -></TT ->. See the fourth - constructor form for more information.</P -></DIV -><DIV -CLASS="SECT3" -><H3 -CLASS="SECT3" -><A -NAME="AEN557" -></A ->addStruct</H3 -><DIV -CLASS="FUNCSYNOPSIS" -><A -NAME="AEN559" -></A -><P -></P -><P -><CODE -><CODE -CLASS="FUNCDEF" ->$ok=$val->addArray</CODE ->($assocArrayVal);</CODE -></P -><P -></P -></DIV -><P ->Turns an empty <TT -CLASS="CLASSNAME" ->xmlrpcval</TT -> into a - <TT -CLASS="CLASSNAME" ->struct</TT -> with contents as specified by - <TT -CLASS="PARAMETER" -><I ->$assocArrayVal</I -></TT ->. See the fourth - constructor form for more information.</P -></DIV -><DIV -CLASS="SECT3" -><H3 -CLASS="SECT3" -><A -NAME="AEN568" -></A ->kindOf</H3 -><DIV -CLASS="FUNCSYNOPSIS" -><A -NAME="AEN570" -></A -><P -></P -><P -><CODE -><CODE -CLASS="FUNCDEF" ->$kind=$val->kindOf</CODE ->();</CODE -></P -><P -></P -></DIV -><P -> Returns a string containing "struct", "array" or "scalar" - describing the base type of the value. If it returns - "undef" it means that the value hasn't been initialised. - </P -></DIV -><DIV -CLASS="SECT3" -><H3 -CLASS="SECT3" -><A -NAME="AEN575" -></A ->serialize</H3 -><DIV -CLASS="FUNCSYNOPSIS" -><A -NAME="AEN577" -></A -><P -></P -><P -><CODE -><CODE -CLASS="FUNCDEF" ->$outString=$val->serialize</CODE ->();</CODE -></P -><P -></P -></DIV -><P -> Returns a string containing the XML-RPC representation of - this value. - </P -></DIV -><DIV -CLASS="SECT3" -><H3 -CLASS="SECT3" -><A -NAME="AEN582" -></A ->scalarval</H3 -><DIV -CLASS="FUNCSYNOPSIS" -><A -NAME="AEN584" -></A -><P -></P -><P -><CODE -><CODE -CLASS="FUNCDEF" ->$scalarVal=$val->scalarval</CODE ->();</CODE -></P -><P -></P -></DIV -><P -> If <TT -CLASS="FUNCTION" ->$val->kindOf()=="scalar"</TT ->, this - method returns the actual PHP-language value of the scalar - (base 64 decoding is automatically handled here). - </P -></DIV -><DIV -CLASS="SECT3" -><H3 -CLASS="SECT3" -><A -NAME="AEN590" -></A ->scalartyp</H3 -><DIV -CLASS="FUNCSYNOPSIS" -><A -NAME="AEN592" -></A -><P -></P -><P -><CODE -><CODE -CLASS="FUNCDEF" ->$typeName=$val->scalartyp</CODE ->();</CODE -></P -><P -></P -></DIV -><P -> If <TT -CLASS="FUNCTION" ->$val->kindOf()=="scalar"</TT ->, this - method returns a string denoting the type of the scalar. - As mentioned before, - <TT -CLASS="LITERAL" ->i4</TT -> is always coerced to <TT -CLASS="LITERAL" ->int</TT ->. - </P -></DIV -><DIV -CLASS="SECT3" -><H3 -CLASS="SECT3" -><A -NAME="AEN600" -></A ->arraymem</H3 -><DIV -CLASS="FUNCSYNOPSIS" -><A -NAME="AEN602" -></A -><P -></P -><P -><CODE -><CODE -CLASS="FUNCDEF" ->$xmlrpcVal=$val->arraymem</CODE ->($n);</CODE -></P -><P -></P -></DIV -><P -> Returns the <TT -CLASS="PARAMETER" -><I ->$n</I -></TT ->th element in the array - represented by the value <TT -CLASS="PARAMETER" -><I ->$val</I -></TT ->. The - value returned is an <TT -CLASS="CLASSNAME" ->xmlrpcval</TT -> object. - </P -></DIV -><DIV -CLASS="SECT3" -><H3 -CLASS="SECT3" -><A -NAME="AEN611" -></A ->arraysize</H3 -><DIV -CLASS="FUNCSYNOPSIS" -><A -NAME="AEN613" -></A -><P -></P -><P -><CODE -><CODE -CLASS="FUNCDEF" ->$len=$val->arraysize</CODE ->();</CODE -></P -><P -></P -></DIV -><P ->If <TT -CLASS="PARAMETER" -><I ->$val</I -></TT -> is an - <TT -CLASS="CLASSNAME" ->array</TT ->, returns the number of elements - in that array. - </P -></DIV -><DIV -CLASS="SECT3" -><H3 -CLASS="SECT3" -><A -NAME="AEN620" -></A ->structmem</H3 -><DIV -CLASS="FUNCSYNOPSIS" -><A -NAME="AEN622" -></A -><P -></P -><P -><CODE -><CODE -CLASS="FUNCDEF" ->$xmlrpcVal=$val->structmem</CODE ->($memberName);</CODE -></P -><P -></P -></DIV -><P -> Returns the element called - <TT -CLASS="PARAMETER" -><I ->$memberName</I -></TT -> from the struct - represented by the value <TT -CLASS="PARAMETER" -><I ->$val</I -></TT ->. The - value returned is an <TT -CLASS="CLASSNAME" ->xmlrpcval</TT -> object. - </P -></DIV -><DIV -CLASS="SECT3" -><H3 -CLASS="SECT3" -><A -NAME="AEN631" -></A ->structeach</H3 -><DIV -CLASS="FUNCSYNOPSIS" -><A -NAME="AEN633" -></A -><P -></P -><P -><CODE -><CODE -CLASS="FUNCDEF" ->list($key,$value)=$val->structeach</CODE ->();</CODE -></P -><P -></P -></DIV -><P -> Returns the next (key,value) pair from the struct, when - <TT -CLASS="PARAMETER" -><I ->$val</I -></TT -> is a struct. See also - <A -HREF="xmlrpcval.html#STRUCTRESET" ->structreset()</A ->. - </P -></DIV -><DIV -CLASS="SECT3" -><H3 -CLASS="SECT3" -><A -NAME="STRUCTRESET" -></A ->structreset</H3 -><DIV -CLASS="FUNCSYNOPSIS" -><A -NAME="AEN642" -></A -><P -></P -><P -><CODE -><CODE -CLASS="FUNCDEF" ->$val->structreset</CODE ->();</CODE -></P -><P -></P -></DIV -><P -> Resets the internal pointer for - <TT -CLASS="FUNCTION" ->structeach()</TT -> to the beginning of the - struct, where <TT -CLASS="PARAMETER" -><I ->$val</I -></TT -> is a struct. - </P -></DIV -></DIV -></DIV -><DIV -CLASS="NAVFOOTER" -><HR -ALIGN="LEFT" -WIDTH="100%"><TABLE -SUMMARY="Footer navigation table" -WIDTH="100%" -BORDER="0" -CELLPADDING="0" -CELLSPACING="0" -><TR -><TD -WIDTH="33%" -ALIGN="left" -VALIGN="top" -><A -HREF="xmlrpcresp.html" -ACCESSKEY="P" ->Prev</A -></TD -><TD -WIDTH="34%" -ALIGN="center" -VALIGN="top" -><A -HREF="index.html" -ACCESSKEY="H" ->Home</A -></TD -><TD -WIDTH="33%" -ALIGN="right" -VALIGN="top" -><A -HREF="xmlrpc-server.html" -ACCESSKEY="N" ->Next</A -></TD -></TR -><TR -><TD -WIDTH="33%" -ALIGN="left" -VALIGN="top" ->xmlrpcresp</TD -><TD -WIDTH="34%" -ALIGN="center" -VALIGN="top" -><A -HREF="apidocs.html" -ACCESSKEY="U" ->Up</A -></TD -><TD -WIDTH="33%" -ALIGN="right" -VALIGN="top" ->xmlrpc_server</TD -></TR -></TABLE -></DIV -></BODY -></HTML ->
\ No newline at end of file diff --git a/modules/xmlrpc/xmlrpc.inc b/modules/xmlrpc/xmlrpc.inc index e8b6aedd..0c3702e9 100755 --- a/modules/xmlrpc/xmlrpc.inc +++ b/modules/xmlrpc/xmlrpc.inc @@ -1,8 +1,7 @@ -<?php // -*-c++-*- +<?php // by Edd Dumbill (C) 1999-2002 // <edd@usefulinc.com> -// $Id: xmlrpc.inc,v 1.40 2005/04/24 18:17:18 ggiunta Exp $ - +// $Id: xmlrpc.inc,v 1.158 2007/03/01 21:21:02 ggiunta Exp $ // Copyright (c) 1999,2000,2002 Edd Dumbill. // All rights reserved. @@ -36,71 +35,67 @@ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED // OF THE POSSIBILITY OF SUCH DAMAGE. - if (!function_exists('xml_parser_create')) + if(!function_exists('xml_parser_create')) { - // Win 32 fix. From: 'Leo West' <lwest@imaginet.fr> - if($WINDIR) + // For PHP 4 onward, XML functionality is always compiled-in on windows: + // no more need to dl-open it. It might have been compiled out on *nix... + if(strtoupper(substr(PHP_OS, 0, 3) != 'WIN')) { - dl('php3_xml.dll'); + dl('xml.so'); } - else + } + + // Try to be backward compat with php < 4.2 (are we not being nice ?) + $phpversion = phpversion(); + if($phpversion[0] == '4' && $phpversion[2] < 2) + { + // give an opportunity to user to specify where to include other files from + if(!defined('PHP_XMLRPC_COMPAT_DIR')) { - dl('xml.so'); + define('PHP_XMLRPC_COMPAT_DIR',dirname(__FILE__).'/compat/'); } + if($phpversion[2] == '0') + { + if($phpversion[4] < 6) + { + include(PHP_XMLRPC_COMPAT_DIR.'is_callable.php'); + } + include(PHP_XMLRPC_COMPAT_DIR.'is_scalar.php'); + include(PHP_XMLRPC_COMPAT_DIR.'array_key_exists.php'); + include(PHP_XMLRPC_COMPAT_DIR.'version_compare.php'); + } + include(PHP_XMLRPC_COMPAT_DIR.'var_export.php'); + include(PHP_XMLRPC_COMPAT_DIR.'is_a.php'); } // G. Giunta 2005/01/29: declare global these variables, // so that xmlrpc.inc will work even if included from within a function - // NB: it will give warnings in PHP3, so we comment it out - // Milosch: Next round, maybe we should explicitly request these via $GLOBALS where used. - if (phpversion() >= '4') - { - global $xmlrpcI4; - global $xmlrpcInt; - global $xmlrpcDouble; - global $xmlrpcBoolean; - global $xmlrpcString; - global $xmlrpcDateTime; - global $xmlrpcBase64; - global $xmlrpcArray; - global $xmlrpcStruct; - - global $xmlrpcTypes; - global $xmlEntities; - global $xmlrpcerr; - global $xmlrpcstr; - global $xmlrpc_defencoding; - global $xmlrpc_internalencoding; - global $xmlrpcName; - global $xmlrpcVersion; - global $xmlrpcerruser; - global $xmlrpcerrxml; - global $xmlrpc_backslash; - global $_xh; - } - $xmlrpcI4='i4'; - $xmlrpcInt='int'; - $xmlrpcBoolean='boolean'; - $xmlrpcDouble='double'; - $xmlrpcString='string'; - $xmlrpcDateTime='dateTime.iso8601'; - $xmlrpcBase64='base64'; - $xmlrpcArray='array'; - $xmlrpcStruct='struct'; - - $xmlrpcTypes=array( - $xmlrpcI4 => 1, - $xmlrpcInt => 1, - $xmlrpcBoolean => 1, - $xmlrpcString => 1, - $xmlrpcDouble => 1, - $xmlrpcDateTime => 1, - $xmlrpcBase64 => 1, - $xmlrpcArray => 2, - $xmlrpcStruct => 3 + // Milosch: 2005/08/07 - explicitly request these via $GLOBALS where used. + $GLOBALS['xmlrpcI4']='i4'; + $GLOBALS['xmlrpcInt']='int'; + $GLOBALS['xmlrpcBoolean']='boolean'; + $GLOBALS['xmlrpcDouble']='double'; + $GLOBALS['xmlrpcString']='string'; + $GLOBALS['xmlrpcDateTime']='dateTime.iso8601'; + $GLOBALS['xmlrpcBase64']='base64'; + $GLOBALS['xmlrpcArray']='array'; + $GLOBALS['xmlrpcStruct']='struct'; + $GLOBALS['xmlrpcValue']='undefined'; + + $GLOBALS['xmlrpcTypes']=array( + $GLOBALS['xmlrpcI4'] => 1, + $GLOBALS['xmlrpcInt'] => 1, + $GLOBALS['xmlrpcBoolean'] => 1, + $GLOBALS['xmlrpcString'] => 1, + $GLOBALS['xmlrpcDouble'] => 1, + $GLOBALS['xmlrpcDateTime'] => 1, + $GLOBALS['xmlrpcBase64'] => 1, + $GLOBALS['xmlrpcArray'] => 2, + $GLOBALS['xmlrpcStruct'] => 3 ); - $xmlrpc_valid_parents = array( + $GLOBALS['xmlrpc_valid_parents'] = array( + 'VALUE' => array('MEMBER', 'DATA', 'PARAM', 'FAULT'), 'BOOLEAN' => array('VALUE'), 'I4' => array('VALUE'), 'INT' => array('VALUE'), @@ -108,19 +103,25 @@ 'DOUBLE' => array('VALUE'), 'DATETIME.ISO8601' => array('VALUE'), 'BASE64' => array('VALUE'), + 'MEMBER' => array('STRUCT'), + 'NAME' => array('MEMBER'), + 'DATA' => array('ARRAY'), 'ARRAY' => array('VALUE'), 'STRUCT' => array('VALUE'), 'PARAM' => array('PARAMS'), - 'METHODNAME' => array('METHODCALL'), + 'METHODNAME' => array('METHODCALL'), 'PARAMS' => array('METHODCALL', 'METHODRESPONSE'), - 'MEMBER' => array('STRUCT'), - 'NAME' => array('MEMBER'), - 'DATA' => array('ARRAY'), 'FAULT' => array('METHODRESPONSE'), - 'VALUE' => array('MEMBER', 'DATA', 'PARAM', 'FAULT'), + 'NIL' => array('VALUE') // only used when extension activated ); - $xmlEntities=array( + // define extra types for supporting NULL (useful for json or <NIL/>) + $GLOBALS['xmlrpcNull']='null'; + $GLOBALS['xmlrpcTypes']['null']=1; + + // Not in use anymore since 2.0. Shall we remove it? + /// @deprecated + $GLOBALS['xmlEntities']=array( 'amp' => '&', 'quot' => '"', 'lt' => '<', @@ -128,1227 +129,1897 @@ 'apos' => "'" ); - $xmlrpcerr['unknown_method']=1; - $xmlrpcstr['unknown_method']='Unknown method'; - $xmlrpcerr['invalid_return']=2; - $xmlrpcstr['invalid_return']='Invalid return payload: enable debugging to examine incoming payload'; - $xmlrpcerr['incorrect_params']=3; - $xmlrpcstr['incorrect_params']='Incorrect parameters passed to method'; - $xmlrpcerr['introspect_unknown']=4; - $xmlrpcstr['introspect_unknown']="Can't introspect: method unknown"; - $xmlrpcerr['http_error']=5; - $xmlrpcstr['http_error']="Didn't receive 200 OK from remote server."; - $xmlrpcerr['no_data']=6; - $xmlrpcstr['no_data']='No data received from server.'; - $xmlrpcerr['no_ssl']=7; - $xmlrpcstr['no_ssl']='No SSL support compiled in.'; - $xmlrpcerr['curl_fail']=8; - $xmlrpcstr['curl_fail']='CURL error'; - $xmlrpcerr['invalid_request']=15; - $xmlrpcstr['invalid_request']='Invalid request payload'; - - $xmlrpcerr['multicall_notstruct'] = 9; - $xmlrpcstr['multicall_notstruct'] = 'system.multicall expected struct'; - $xmlrpcerr['multicall_nomethod'] = 10; - $xmlrpcstr['multicall_nomethod'] = 'missing methodName'; - $xmlrpcerr['multicall_notstring'] = 11; - $xmlrpcstr['multicall_notstring'] = 'methodName is not a string'; - $xmlrpcerr['multicall_recursion'] = 12; - $xmlrpcstr['multicall_recursion'] = 'recursive system.multicall forbidden'; - $xmlrpcerr['multicall_noparams'] = 13; - $xmlrpcstr['multicall_noparams'] = 'missing params'; - $xmlrpcerr['multicall_notarray'] = 14; - $xmlrpcstr['multicall_notarray'] = 'params is not an array'; - - // The charset encoding expected by the server for received messages and - // by the client for received responses - $xmlrpc_defencoding='UTF-8'; - // The encoding used by PHP. - // String values received will be converted to this. - $xmlrpc_internalencoding='ISO-8859-1'; - - $xmlrpcName='XML-RPC for PHP'; - $xmlrpcVersion='1.2'; + // tables used for transcoding different charsets into us-ascii xml + + $GLOBALS['xml_iso88591_Entities']=array(); + $GLOBALS['xml_iso88591_Entities']['in'] = array(); + $GLOBALS['xml_iso88591_Entities']['out'] = array(); + for ($i = 0; $i < 32; $i++) + { + $GLOBALS['xml_iso88591_Entities']['in'][] = chr($i); + $GLOBALS['xml_iso88591_Entities']['out'][] = '&#'.$i.';'; + } + for ($i = 160; $i < 256; $i++) + { + $GLOBALS['xml_iso88591_Entities']['in'][] = chr($i); + $GLOBALS['xml_iso88591_Entities']['out'][] = '&#'.$i.';'; + } + + /// @todo add to iso table the characters from cp_1252 range, i.e. 128 to 159. + /// These will NOT be present in true ISO-8859-1, but will save the unwary + /// windows user from sending junk. +/* +$cp1252_to_xmlent = + array( + '\x80'=>'€', '\x81'=>'?', '\x82'=>'‚', '\x83'=>'ƒ', + '\x84'=>'„', '\x85'=>'…', '\x86'=>'†', \x87'=>'‡', + '\x88'=>'ˆ', '\x89'=>'‰', '\x8A'=>'Š', '\x8B'=>'‹', + '\x8C'=>'Œ', '\x8D'=>'?', '\x8E'=>'Ž', '\x8F'=>'?', + '\x90'=>'?', '\x91'=>'‘', '\x92'=>'’', '\x93'=>'“', + '\x94'=>'”', '\x95'=>'•', '\x96'=>'–', '\x97'=>'—', + '\x98'=>'˜', '\x99'=>'™', '\x9A'=>'š', '\x9B'=>'›', + '\x9C'=>'œ', '\x9D'=>'?', '\x9E'=>'ž', '\x9F'=>'Ÿ' + ); +*/ + + $GLOBALS['xmlrpcerr']['unknown_method']=1; + $GLOBALS['xmlrpcstr']['unknown_method']='Unknown method'; + $GLOBALS['xmlrpcerr']['invalid_return']=2; + $GLOBALS['xmlrpcstr']['invalid_return']='Invalid return payload: enable debugging to examine incoming payload'; + $GLOBALS['xmlrpcerr']['incorrect_params']=3; + $GLOBALS['xmlrpcstr']['incorrect_params']='Incorrect parameters passed to method'; + $GLOBALS['xmlrpcerr']['introspect_unknown']=4; + $GLOBALS['xmlrpcstr']['introspect_unknown']="Can't introspect: method unknown"; + $GLOBALS['xmlrpcerr']['http_error']=5; + $GLOBALS['xmlrpcstr']['http_error']="Didn't receive 200 OK from remote server."; + $GLOBALS['xmlrpcerr']['no_data']=6; + $GLOBALS['xmlrpcstr']['no_data']='No data received from server.'; + $GLOBALS['xmlrpcerr']['no_ssl']=7; + $GLOBALS['xmlrpcstr']['no_ssl']='No SSL support compiled in.'; + $GLOBALS['xmlrpcerr']['curl_fail']=8; + $GLOBALS['xmlrpcstr']['curl_fail']='CURL error'; + $GLOBALS['xmlrpcerr']['invalid_request']=15; + $GLOBALS['xmlrpcstr']['invalid_request']='Invalid request payload'; + $GLOBALS['xmlrpcerr']['no_curl']=16; + $GLOBALS['xmlrpcstr']['no_curl']='No CURL support compiled in.'; + $GLOBALS['xmlrpcerr']['server_error']=17; + $GLOBALS['xmlrpcstr']['server_error']='Internal server error'; + $GLOBALS['xmlrpcerr']['multicall_error']=18; + $GLOBALS['xmlrpcstr']['multicall_error']='Received from server invalid multicall response'; + + $GLOBALS['xmlrpcerr']['multicall_notstruct'] = 9; + $GLOBALS['xmlrpcstr']['multicall_notstruct'] = 'system.multicall expected struct'; + $GLOBALS['xmlrpcerr']['multicall_nomethod'] = 10; + $GLOBALS['xmlrpcstr']['multicall_nomethod'] = 'missing methodName'; + $GLOBALS['xmlrpcerr']['multicall_notstring'] = 11; + $GLOBALS['xmlrpcstr']['multicall_notstring'] = 'methodName is not a string'; + $GLOBALS['xmlrpcerr']['multicall_recursion'] = 12; + $GLOBALS['xmlrpcstr']['multicall_recursion'] = 'recursive system.multicall forbidden'; + $GLOBALS['xmlrpcerr']['multicall_noparams'] = 13; + $GLOBALS['xmlrpcstr']['multicall_noparams'] = 'missing params'; + $GLOBALS['xmlrpcerr']['multicall_notarray'] = 14; + $GLOBALS['xmlrpcstr']['multicall_notarray'] = 'params is not an array'; + + $GLOBALS['xmlrpcerr']['cannot_decompress']=103; + $GLOBALS['xmlrpcstr']['cannot_decompress']='Received from server compressed HTTP and cannot decompress'; + $GLOBALS['xmlrpcerr']['decompress_fail']=104; + $GLOBALS['xmlrpcstr']['decompress_fail']='Received from server invalid compressed HTTP'; + $GLOBALS['xmlrpcerr']['dechunk_fail']=105; + $GLOBALS['xmlrpcstr']['dechunk_fail']='Received from server invalid chunked HTTP'; + $GLOBALS['xmlrpcerr']['server_cannot_decompress']=106; + $GLOBALS['xmlrpcstr']['server_cannot_decompress']='Received from client compressed HTTP request and cannot decompress'; + $GLOBALS['xmlrpcerr']['server_decompress_fail']=107; + $GLOBALS['xmlrpcstr']['server_decompress_fail']='Received from client invalid compressed HTTP request'; + + // The charset encoding used by the server for received messages and + // by the client for received responses when received charset cannot be determined + // or is not supported + $GLOBALS['xmlrpc_defencoding']='UTF-8'; + + // The encoding used internally by PHP. + // String values received as xml will be converted to this, and php strings will be converted to xml + // as if having been coded with this + $GLOBALS['xmlrpc_internalencoding']='ISO-8859-1'; + + $GLOBALS['xmlrpcName']='XML-RPC for PHP'; + $GLOBALS['xmlrpcVersion']='2.2'; // let user errors start at 800 - $xmlrpcerruser=800; + $GLOBALS['xmlrpcerruser']=800; // let XML parse errors start at 100 - $xmlrpcerrxml=100; + $GLOBALS['xmlrpcerrxml']=100; // formulate backslashes for escaping regexp - $xmlrpc_backslash=chr(92).chr(92); + // Not in use anymore since 2.0. Shall we remove it? + /// @deprecated + $GLOBALS['xmlrpc_backslash']=chr(92).chr(92); + + // set to TRUE to enable correct decoding of <NIL/> values + $GLOBALS['xmlrpc_null_extension']=false; // used to store state during parsing // quick explanation of components: // ac - used to accumulate values - // isf - used to indicate a fault + // isf - used to indicate a parsing fault (2) or xmlrpcresp fault (1) + // isf_reason - used for storing xmlrpcresp fault string // lv - used to indicate "looking for a value": implements // the logic to allow values with no types to be strings // params - used to store parameters in method calls // method - used to store method name // stack - array with genealogy of xml elements names: // used to validate nesting of xmlrpc elements - - $_xh=array(); + $GLOBALS['_xh']=null; /** + * Convert a string to the correct XML representation in a target charset * To help correct communication of non-ascii chars inside strings, regardless * of the charset used when sending requests, parsing them, sending responses - * and parsing responses, convert all non-ascii chars present in the message + * and parsing responses, an option is to convert all non-ascii chars present in the message * into their equivalent 'charset entity'. Charset entities enumerated this way * are independent of the charset encoding used to transmit them, and all XML * parsers are bound to understand them. + * Note that in the std case we are not sending a charset encoding mime type + * along with http headers, so we are bound by RFC 3023 to emit strict us-ascii. + * + * @todo do a bit of basic benchmarking (strtr vs. str_replace) + * @todo make usage of iconv() or recode_string() or mb_string() where available */ - function xmlrpc_entity_decode($string) + function xmlrpc_encode_entitites($data, $src_encoding='', $dest_encoding='') { - $top=split('&', $string); - $op=''; - $i=0; - while($i<sizeof($top)) + if ($src_encoding == '') { - if (ereg("^([#a-zA-Z0-9]+);", $top[$i], $regs)) - { - $op.=ereg_replace("^[#a-zA-Z0-9]+;", - xmlrpc_lookup_entity($regs[1]), - $top[$i]); - } - else - { - if ($i==0) - { - $op=$top[$i]; - } - else - { - $op.='&' . $top[$i]; - } - } - $i++; + // lame, but we know no better... + $src_encoding = $GLOBALS['xmlrpc_internalencoding']; } - return $op; - } - function xmlrpc_lookup_entity($ent) - { - global $xmlEntities; - - if (isset($xmlEntities[strtolower($ent)])) - { - return $xmlEntities[strtolower($ent)]; - } - if (ereg("^#([0-9]+)$", $ent, $regs)) + switch(strtoupper($src_encoding.'_'.$dest_encoding)) { - return chr($regs[1]); - } - return '?'; - } - - /** - * These entities originate from HTML specs (1.1, proposed 2.0, etc), - * and are taken directly from php-4.3.1/ext/mbstring/html_entities.c. - * Until php provides functionality to translate these entities in its - * core library, use this function. - */ - function xmlrpc_html_entity_xlate($data = '') - { - $entities = array( - " " => " ", - "¡" => "¡", - "¢" => "¢", - "£" => "£", - "¤" => "¤", - "¥" => "¥", - "¦" => "¦", - "§" => "§", - "¨" => "¨", - "©" => "©", - "ª" => "ª", - "«" => "«", - "¬" => "¬", - "­" => "­", - "®" => "®", - "¯" => "¯", - "°" => "°", - "±" => "±", - "²" => "²", - "³" => "³", - "´" => "´", - "µ" => "µ", - "¶" => "¶", - "·" => "·", - "¸" => "¸", - "¹" => "¹", - "º" => "º", - "»" => "»", - "¼" => "¼", - "½" => "½", - "¾" => "¾", - "¿" => "¿", - "À" => "À", - "Á" => "Á", - "Â" => "Â", - "Ã" => "Ã", - "Ä" => "Ä", - "Å" => "Å", - "Æ" => "Æ", - "Ç" => "Ç", - "È" => "È", - "É" => "É", - "Ê" => "Ê", - "Ë" => "Ë", - "Ì" => "Ì", - "Í" => "Í", - "Î" => "Î", - "Ï" => "Ï", - "Ð" => "Ð", - "Ñ" => "Ñ", - "Ò" => "Ò", - "Ó" => "Ó", - "Ô" => "Ô", - "Õ" => "Õ", - "Ö" => "Ö", - "×" => "×", - "Ø" => "Ø", - "Ù" => "Ù", - "Ú" => "Ú", - "Û" => "Û", - "Ü" => "Ü", - "Ý" => "Ý", - "Þ" => "Þ", - "ß" => "ß", - "à" => "à", - "á" => "á", - "â" => "â", - "ã" => "ã", - "ä" => "ä", - "å" => "å", - "æ" => "æ", - "ç" => "ç", - "è" => "è", - "é" => "é", - "ê" => "ê", - "ë" => "ë", - "ì" => "ì", - "í" => "í", - "î" => "î", - "ï" => "ï", - "ð" => "ð", - "ñ" => "ñ", - "ò" => "ò", - "ó" => "ó", - "ô" => "ô", - "õ" => "õ", - "ö" => "ö", - "÷" => "÷", - "ø" => "ø", - "ù" => "ù", - "ú" => "ú", - "û" => "û", - "ü" => "ü", - "ý" => "ý", - "þ" => "þ", - "ÿ" => "ÿ", - "Œ" => "Œ", - "œ" => "œ", - "Š" => "Š", - "š" => "š", - "Ÿ" => "Ÿ", - "ƒ" => "ƒ", - "ˆ" => "ˆ", - "˜" => "˜", - "Α" => "Α", - "Β" => "Β", - "Γ" => "Γ", - "Δ" => "Δ", - "Ε" => "Ε", - "Ζ" => "Ζ", - "Η" => "Η", - "Θ" => "Θ", - "Ι" => "Ι", - "Κ" => "Κ", - "Λ" => "Λ", - "Μ" => "Μ", - "Ν" => "Ν", - "Ξ" => "Ξ", - "Ο" => "Ο", - "Π" => "Π", - "Ρ" => "Ρ", - "Σ" => "Σ", - "Τ" => "Τ", - "Υ" => "Υ", - "Φ" => "Φ", - "Χ" => "Χ", - "Ψ" => "Ψ", - "Ω" => "Ω", - "β" => "β", - "γ" => "γ", - "δ" => "δ", - "ε" => "ε", - "ζ" => "ζ", - "η" => "η", - "θ" => "θ", - "ι" => "ι", - "κ" => "κ", - "λ" => "λ", - "μ" => "μ", - "ν" => "ν", - "ξ" => "ξ", - "ο" => "ο", - "π" => "π", - "ρ" => "ρ", - "ς" => "ς", - "σ" => "σ", - "τ" => "τ", - "υ" => "υ", - "φ" => "φ", - "χ" => "χ", - "ψ" => "ψ", - "ω" => "ω", - "ϑ" => "ϑ", - "ϒ" => "ϒ", - "ϖ" => "ϖ", - " " => " ", - " " => " ", - " " => " ", - "‌" => "‌", - "‍" => "‍", - "‎" => "‎", - "‏" => "‏", - "–" => "–", - "—" => "—", - "‘" => "‘", - "’" => "’", - "‚" => "‚", - "“" => "“", - "”" => "”", - "„" => "„", - "†" => "†", - "‡" => "‡", - "•" => "•", - "…" => "…", - "‰" => "‰", - "′" => "′", - "″" => "″", - "‹" => "‹", - "›" => "›", - "‾" => "‾", - "⁄" => "⁄", - "€" => "€", - "℘" => "℘", - "ℑ" => "ℑ", - "ℜ" => "ℜ", - "™" => "™", - "ℵ" => "ℵ", - "←" => "←", - "↑" => "↑", - "→" => "→", - "↓" => "↓", - "↔" => "↔", - "↵" => "↵", - "⇐" => "⇐", - "⇑" => "⇑", - "⇒" => "⇒", - "⇓" => "⇓", - "⇔" => "⇔", - "∀" => "∀", - "∂" => "∂", - "∃" => "∃", - "∅" => "∅", - "∇" => "∇", - "∈" => "∈", - "∉" => "∉", - "∋" => "∋", - "∏" => "∏", - "∑" => "∑", - "−" => "−", - "∗" => "∗", - "√" => "√", - "∝" => "∝", - "∞" => "∞", - "∠" => "∠", - "∧" => "∧", - "∨" => "∨", - "∩" => "∩", - "∪" => "∪", - "∫" => "∫", - "∴" => "∴", - "∼" => "∼", - "≅" => "≅", - "≈" => "≈", - "≠" => "≠", - "≡" => "≡", - "≤" => "≤", - "≥" => "≥", - "⊂" => "⊂", - "⊃" => "⊃", - "⊄" => "⊄", - "⊆" => "⊆", - "⊇" => "⊇", - "⊕" => "⊕", - "⊗" => "⊗", - "⊥" => "⊥", - "⋅" => "⋅", - "⌈" => "⌈", - "⌉" => "⌉", - "⌊" => "⌊", - "⌋" => "⌋", - "⟨" => "〈", - "⟩" => "〉", - "◊" => "◊", - "♠" => "♠", - "♣" => "♣", - "♥" => "♥", - "♦" => "♦"); - return strtr($data, $entities); - } - - function xmlrpc_encode_entitites($data) + case 'ISO-8859-1_': + case 'ISO-8859-1_US-ASCII': + $escaped_data = str_replace(array('&', '"', "'", '<', '>'), array('&', '"', ''', '<', '>'), $data); + $escaped_data = str_replace($GLOBALS['xml_iso88591_Entities']['in'], $GLOBALS['xml_iso88591_Entities']['out'], $escaped_data); + break; + case 'ISO-8859-1_UTF-8': + $escaped_data = str_replace(array('&', '"', "'", '<', '>'), array('&', '"', ''', '<', '>'), $data); + $escaped_data = utf8_encode($escaped_data); + break; + case 'ISO-8859-1_ISO-8859-1': + case 'US-ASCII_US-ASCII': + case 'US-ASCII_UTF-8': + case 'US-ASCII_': + case 'US-ASCII_ISO-8859-1': + case 'UTF-8_UTF-8': + $escaped_data = str_replace(array('&', '"', "'", '<', '>'), array('&', '"', ''', '<', '>'), $data); + break; + case 'UTF-8_': + case 'UTF-8_US-ASCII': + case 'UTF-8_ISO-8859-1': + // NB: this will choke on invalid UTF-8, going most likely beyond EOF + $escaped_data = ''; + // be kind to users creating string xmlrpcvals out of different php types + $data = (string) $data; + $ns = strlen ($data); + for ($nn = 0; $nn < $ns; $nn++) { - $length = strlen($data); - $escapeddata = ""; - for($position = 0; $position < $length; $position++) + $ch = $data[$nn]; + $ii = ord($ch); + //1 7 0bbbbbbb (127) + if ($ii < 128) { - $character = substr($data, $position, 1); - $code = Ord($character); - switch($code) { + /// @todo shall we replace this with a (supposedly) faster str_replace? + switch($ii){ case 34: - $character = """; - break; + $escaped_data .= '"'; + break; case 38: - $character = "&"; - break; + $escaped_data .= '&'; + break; case 39: - $character = "'"; - break; + $escaped_data .= '''; + break; case 60: - $character = "<"; - break; + $escaped_data .= '<'; + break; case 62: - $character = ">"; - break; + $escaped_data .= '>'; + break; default: - if ($code < 32 || $code > 159) - $character = ("&#".strval($code).";"); + $escaped_data .= $ch; + } // switch + } + //2 11 110bbbbb 10bbbbbb (2047) + else if ($ii>>5 == 6) + { + $b1 = ($ii & 31); + $ii = ord($data[$nn+1]); + $b2 = ($ii & 63); + $ii = ($b1 * 64) + $b2; + $ent = sprintf ('&#%d;', $ii); + $escaped_data .= $ent; + $nn += 1; + } + //3 16 1110bbbb 10bbbbbb 10bbbbbb + else if ($ii>>4 == 14) + { + $b1 = ($ii & 31); + $ii = ord($data[$nn+1]); + $b2 = ($ii & 63); + $ii = ord($data[$nn+2]); + $b3 = ($ii & 63); + $ii = ((($b1 * 64) + $b2) * 64) + $b3; + $ent = sprintf ('&#%d;', $ii); + $escaped_data .= $ent; + $nn += 2; + } + //4 21 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb + else if ($ii>>3 == 30) + { + $b1 = ($ii & 31); + $ii = ord($data[$nn+1]); + $b2 = ($ii & 63); + $ii = ord($data[$nn+2]); + $b3 = ($ii & 63); + $ii = ord($data[$nn+3]); + $b4 = ($ii & 63); + $ii = ((((($b1 * 64) + $b2) * 64) + $b3) * 64) + $b4; + $ent = sprintf ('&#%d;', $ii); + $escaped_data .= $ent; + $nn += 3; + } + } break; - } - $escapeddata .= $character; + default: + $escaped_data = ''; + error_log("Converting from $src_encoding to $dest_encoding: not supported..."); } - return $escapeddata; + return $escaped_data; } - function xmlrpc_se($parser, $name, $attrs) + /// xml parser handler function for opening element tags + function xmlrpc_se($parser, $name, $attrs, $accept_single_vals=false) { - global $_xh, $xmlrpcDateTime, $xmlrpcString, $xmlrpc_valid_parents; - // if invalid xmlrpc already detected, skip all processing - if ($_xh[$parser]['isf'] < 2) - { - - // check for correct element nesting - // top level element can only be of 2 types - if (count($_xh[$parser]['stack']) == 0) + if ($GLOBALS['_xh']['isf'] < 2) { - if ($name != 'METHODRESPONSE' && $name != 'METHODCALL') + // check for correct element nesting + // top level element can only be of 2 types + /// @todo optimization creep: save this check into a bool variable, instead of using count() every time: + /// there is only a single top level element in xml anyway + if (count($GLOBALS['_xh']['stack']) == 0) { - $_xh[$parser]['isf'] = 2; - $_xh[$parser]['isf_reason'] = 'missing top level xmlrpc element'; - return; + if ($name != 'METHODRESPONSE' && $name != 'METHODCALL' && ( + $name != 'VALUE' && !$accept_single_vals)) + { + $GLOBALS['_xh']['isf'] = 2; + $GLOBALS['_xh']['isf_reason'] = 'missing top level xmlrpc element'; + return; + } + else + { + $GLOBALS['_xh']['rt'] = strtolower($name); + } } - } - else - { - // not top level element: see if parent is OK - if (!in_array($_xh[$parser]['stack'][0], $xmlrpc_valid_parents[$name])) + else { - $_xh[$parser]['isf'] = 2; - $_xh[$parser]['isf_reason'] = "xmlrpc element $name cannot be child of {$_xh[$parser]['stack'][0]}"; - return; - } - } - - switch($name) - { - case 'STRUCT': - case 'ARRAY': - //$_xh[$parser]['st'].='array('; - //$_xh[$parser]['cm']++; - // this last line turns quoting off - // this means if we get an empty array we'll - // simply get a bit of whitespace in the eval - //$_xh[$parser]['qt']=0; - - // create an empty array to hold child values, and push it onto appropriate stack - $cur_val = array(); - $cur_val['values'] = array(); - $cur_val['type'] = $name; - array_unshift($_xh[$parser]['valuestack'], $cur_val); - break; - case 'METHODNAME': - case 'NAME': - //$_xh[$parser]['st'].='"'; - $_xh[$parser]['ac']=''; - break; - case 'FAULT': - $_xh[$parser]['isf']=1; - break; - case 'PARAM': - //$_xh[$parser]['st']=''; - // clear value, so we can check later if no value will passed for this param/member - $_xh[$parser]['value']=null; - break; - case 'VALUE': - //$_xh[$parser]['st'].='new xmlrpcval('; - // look for a value: if this is still true by the - // time we reach the end tag for value then the type is string - // by implication - $_xh[$parser]['vt']='value'; - $_xh[$parser]['ac']=''; - //$_xh[$parser]['qt']=0; - $_xh[$parser]['lv']=1; - break; - case 'I4': - case 'INT': - case 'STRING': - case 'BOOLEAN': - case 'DOUBLE': - case 'DATETIME.ISO8601': - case 'BASE64': - if ($_xh[$parser]['vt']!='value') - { - //two data elements inside a value: an error occurred! - $_xh[$parser]['isf'] = 2; - $_xh[$parser]['isf_reason'] = "$name element following a {$_xh[$parser]['vt']} element inside a single value"; + // not top level element: see if parent is OK + $parent = end($GLOBALS['_xh']['stack']); + if (!array_key_exists($name, $GLOBALS['xmlrpc_valid_parents']) || !in_array($parent, $GLOBALS['xmlrpc_valid_parents'][$name])) + { + $GLOBALS['_xh']['isf'] = 2; + $GLOBALS['_xh']['isf_reason'] = "xmlrpc element $name cannot be child of $parent"; return; } + } - // reset the accumulator - $_xh[$parser]['ac']=''; - - /*if ($name=='DATETIME.ISO8601' || $name=='STRING') - { - $_xh[$parser]['qt']=1; - if ($name=='DATETIME.ISO8601') + switch($name) + { + // optimize for speed switch cases: most common cases first + case 'VALUE': + /// @todo we could check for 2 VALUE elements inside a MEMBER or PARAM element + $GLOBALS['_xh']['vt']='value'; // indicator: no value found yet + $GLOBALS['_xh']['ac']=''; + $GLOBALS['_xh']['lv']=1; + $GLOBALS['_xh']['php_class']=null; + break; + case 'I4': + case 'INT': + case 'STRING': + case 'BOOLEAN': + case 'DOUBLE': + case 'DATETIME.ISO8601': + case 'BASE64': + if ($GLOBALS['_xh']['vt']!='value') { - $_xh[$parser]['vt']=$xmlrpcDateTime; + //two data elements inside a value: an error occurred! + $GLOBALS['_xh']['isf'] = 2; + $GLOBALS['_xh']['isf_reason'] = "$name element following a {$GLOBALS['_xh']['vt']} element inside a single value"; + return; } - } - elseif ($name=='BASE64') - { - $_xh[$parser]['qt']=2; - } - else - { - // No quoting is required here -- but - // at the end of the element we must check - // for data format errors. - $_xh[$parser]['qt']=0; - }*/ - break; - case 'MEMBER': - //$_xh[$parser]['ac']=''; - // avoid warnings later on if no NAME is found before VALUE inside - // a struct member predefining member name as NULL - $_xh[$parser]['valuestack'][0]['name'] = ''; - // clear value, so we can check later if no value will passed for this param/member - $_xh[$parser]['value']=null; - break; - case 'DATA': - case 'METHODCALL': - case 'METHODRESPONSE': - case 'PARAMS': - // valid elements that add little to processing - break; - default: - /// INVALID ELEMENT: RAISE ISF so that it is later recognized!!! - $_xh[$parser]['isf'] = 2; - $_xh[$parser]['isf_reason'] = "found not-xmlrpc xml element $name"; - break; - } + $GLOBALS['_xh']['ac']=''; // reset the accumulator + break; + case 'STRUCT': + case 'ARRAY': + if ($GLOBALS['_xh']['vt']!='value') + { + //two data elements inside a value: an error occurred! + $GLOBALS['_xh']['isf'] = 2; + $GLOBALS['_xh']['isf_reason'] = "$name element following a {$GLOBALS['_xh']['vt']} element inside a single value"; + return; + } + // create an empty array to hold child values, and push it onto appropriate stack + $cur_val = array(); + $cur_val['values'] = array(); + $cur_val['type'] = $name; + // check for out-of-band information to rebuild php objs + // and in case it is found, save it + if (@isset($attrs['PHP_CLASS'])) + { + $cur_val['php_class'] = $attrs['PHP_CLASS']; + } + $GLOBALS['_xh']['valuestack'][] = $cur_val; + $GLOBALS['_xh']['vt']='data'; // be prepared for a data element next + break; + case 'DATA': + if ($GLOBALS['_xh']['vt']!='data') + { + //two data elements inside a value: an error occurred! + $GLOBALS['_xh']['isf'] = 2; + $GLOBALS['_xh']['isf_reason'] = "found two data elements inside an array element"; + return; + } + case 'METHODCALL': + case 'METHODRESPONSE': + case 'PARAMS': + // valid elements that add little to processing + break; + case 'METHODNAME': + case 'NAME': + /// @todo we could check for 2 NAME elements inside a MEMBER element + $GLOBALS['_xh']['ac']=''; + break; + case 'FAULT': + $GLOBALS['_xh']['isf']=1; + break; + case 'MEMBER': + $GLOBALS['_xh']['valuestack'][count($GLOBALS['_xh']['valuestack'])-1]['name']=''; // set member name to null, in case we do not find in the xml later on + //$GLOBALS['_xh']['ac']=''; + // Drop trough intentionally + case 'PARAM': + // clear value type, so we can check later if no value has been passed for this param/member + $GLOBALS['_xh']['vt']=null; + break; + case 'NIL': + if ($GLOBALS['xmlrpc_null_extension']) + { + if ($GLOBALS['_xh']['vt']!='value') + { + //two data elements inside a value: an error occurred! + $GLOBALS['_xh']['isf'] = 2; + $GLOBALS['_xh']['isf_reason'] = "$name element following a {$GLOBALS['_xh']['vt']} element inside a single value"; + return; + } + $GLOBALS['_xh']['ac']=''; // reset the accumulator + break; + } + // we do not support the <NIL/> extension, so + // drop through intentionally + default: + /// INVALID ELEMENT: RAISE ISF so that it is later recognized!!! + $GLOBALS['_xh']['isf'] = 2; + $GLOBALS['_xh']['isf_reason'] = "found not-xmlrpc xml element $name"; + break; + } - // Save current element name to stack, to validate nesting - array_unshift($_xh[$parser]['stack'], $name); + // Save current element name to stack, to validate nesting + $GLOBALS['_xh']['stack'][] = $name; - if ($name!='VALUE') - { - $_xh[$parser]['lv']=0; - } + /// @todo optimization creep: move this inside the big switch() above + if($name!='VALUE') + { + $GLOBALS['_xh']['lv']=0; + } } } - function xmlrpc_ee($parser, $name) + /// Used in decoding xml chunks that might represent single xmlrpc values + function xmlrpc_se_any($parser, $name, $attrs) { - global $_xh,$xmlrpcTypes,$xmlrpcString,$xmlrpcDateTime; - - if ($_xh[$parser]['isf'] < 2) - { - - // push this element name from stack - // NB: if XML validates, correct opening/closing is guaranteed and - // we do not have to check for $name == $curr_elem. - // we also checked for proper nesting at start of elements... - $curr_elem = array_shift($_xh[$parser]['stack']); + xmlrpc_se($parser, $name, $attrs, true); + } - switch($name) + /// xml parser handler function for close element tags + function xmlrpc_ee($parser, $name, $rebuild_xmlrpcvals = true) + { + if ($GLOBALS['_xh']['isf'] < 2) { - case 'STRUCT': - case 'ARRAY': - //if ($_xh[$parser]['cm'] && substr($_xh[$parser]['st'], -1) ==',') - //{ - // $_xh[$parser]['st']=substr($_xh[$parser]['st'],0,-1); - //} - //$_xh[$parser]['st'].=')'; - - // fetch out of stack array of values, and promote it to current value - $cur_val = array_shift($_xh[$parser]['valuestack']); - $_xh[$parser]['value'] = $cur_val['values']; + // push this element name from stack + // NB: if XML validates, correct opening/closing is guaranteed and + // we do not have to check for $name == $curr_elem. + // we also checked for proper nesting at start of elements... + $curr_elem = array_pop($GLOBALS['_xh']['stack']); - $_xh[$parser]['vt']=strtolower($name); - //$_xh[$parser]['cm']--; - break; - case 'NAME': - //$_xh[$parser]['st'].= $_xh[$parser]['ac'] . '" => '; - $_xh[$parser]['valuestack'][0]['name'] = $_xh[$parser]['ac']; - break; - case 'BOOLEAN': - case 'I4': - case 'INT': - case 'STRING': - case 'DOUBLE': - case 'DATETIME.ISO8601': - case 'BASE64': - $_xh[$parser]['vt']=strtolower($name); - //if ($_xh[$parser]['qt']==1) - if ($name=='STRING') - { - // we use double quotes rather than single so backslashification works OK - //$_xh[$parser]['st'].='"'. $_xh[$parser]['ac'] . '"'; - $_xh[$parser]['value']=$_xh[$parser]['ac']; - } - elseif ($name=='DATETIME.ISO8601') - { - $_xh[$parser]['vt']=$xmlrpcDateTime; - $_xh[$parser]['value']=$_xh[$parser]['ac']; - } - elseif ($name=='BASE64') - { - //$_xh[$parser]['st'].='base64_decode("'. $_xh[$parser]['ac'] . '")'; + switch($name) + { + case 'VALUE': + // This if() detects if no scalar was inside <VALUE></VALUE> + if ($GLOBALS['_xh']['vt']=='value') + { + $GLOBALS['_xh']['value']=$GLOBALS['_xh']['ac']; + $GLOBALS['_xh']['vt']=$GLOBALS['xmlrpcString']; + } - ///@todo check for failure of base64 decoding / catch warnings - $_xh[$parser]['value']=base64_decode($_xh[$parser]['ac']); - } - elseif ($name=='BOOLEAN') - { - // special case here: we translate boolean 1 or 0 into PHP - // constants true or false - // NB: this simple checks helps a lot sanitizing input, ie no - // security problems around here - if ($_xh[$parser]['ac']=='1') + if ($rebuild_xmlrpcvals) { - //$_xh[$parser]['ac']='true'; - $_xh[$parser]['value']=true; + // build the xmlrpc val out of the data received, and substitute it + $temp =& new xmlrpcval($GLOBALS['_xh']['value'], $GLOBALS['_xh']['vt']); + // in case we got info about underlying php class, save it + // in the object we're rebuilding + if (isset($GLOBALS['_xh']['php_class'])) + $temp->_php_class = $GLOBALS['_xh']['php_class']; + // check if we are inside an array or struct: + // if value just built is inside an array, let's move it into array on the stack + $vscount = count($GLOBALS['_xh']['valuestack']); + if ($vscount && $GLOBALS['_xh']['valuestack'][$vscount-1]['type']=='ARRAY') + { + $GLOBALS['_xh']['valuestack'][$vscount-1]['values'][] = $temp; + } + else + { + $GLOBALS['_xh']['value'] = $temp; + } } else { - //$_xh[$parser]['ac']='false'; - // log if receiveing something strange, even though we set the value to false anyway - if ($_xh[$parser]['ac']!='0') - error_log('XML-RPC: invalid value received in BOOLEAN: '.$_xh[$parser]['ac']); - $_xh[$parser]['value']=false; + /// @todo this needs to treat correctly php-serialized objects, + /// since std deserializing is done by php_xmlrpc_decode, + /// which we will not be calling... + if (isset($GLOBALS['_xh']['php_class'])) + { + } + + // check if we are inside an array or struct: + // if value just built is inside an array, let's move it into array on the stack + $vscount = count($GLOBALS['_xh']['valuestack']); + if ($vscount && $GLOBALS['_xh']['valuestack'][$vscount-1]['type']=='ARRAY') + { + $GLOBALS['_xh']['valuestack'][$vscount-1]['values'][] = $GLOBALS['_xh']['value']; + } } - //$_xh[$parser]['st'].=$_xh[$parser]['ac']; - } - elseif ($name=='DOUBLE') - { - // we have a DOUBLE - // we must check that only 0123456789-.<space> are characters here - if (!ereg("^[+-]?[eE0123456789 \\t\\.]+$", $_xh[$parser]['ac'])) + break; + case 'BOOLEAN': + case 'I4': + case 'INT': + case 'STRING': + case 'DOUBLE': + case 'DATETIME.ISO8601': + case 'BASE64': + $GLOBALS['_xh']['vt']=strtolower($name); + /// @todo: optimization creep - remove the if/elseif cycle below + /// since the case() in which we are already did that + if ($name=='STRING') + { + $GLOBALS['_xh']['value']=$GLOBALS['_xh']['ac']; + } + elseif ($name=='DATETIME.ISO8601') { - // TODO: find a better way of throwing an error - // than this! - error_log('XML-RPC: non numeric value received in DOUBLE: '.$_xh[$parser]['ac']); - //$_xh[$parser]['st'].="'ERROR_NON_NUMERIC_FOUND'"; - $_xh[$parser]['value']='ERROR_NON_NUMERIC_FOUND'; + if (!preg_match('/^[0-9]{8}T[0-9]{2}:[0-9]{2}:[0-9]{2}$/', $GLOBALS['_xh']['ac'])) + { + error_log('XML-RPC: invalid value received in DATETIME: '.$GLOBALS['_xh']['ac']); + } + $GLOBALS['_xh']['vt']=$GLOBALS['xmlrpcDateTime']; + $GLOBALS['_xh']['value']=$GLOBALS['_xh']['ac']; + } + elseif ($name=='BASE64') + { + /// @todo check for failure of base64 decoding / catch warnings + $GLOBALS['_xh']['value']=base64_decode($GLOBALS['_xh']['ac']); + } + elseif ($name=='BOOLEAN') + { + // special case here: we translate boolean 1 or 0 into PHP + // constants true or false. + // Strings 'true' and 'false' are accepted, even though the + // spec never mentions them (see eg. Blogger api docs) + // NB: this simple checks helps a lot sanitizing input, ie no + // security problems around here + if ($GLOBALS['_xh']['ac']=='1' || strcasecmp($GLOBALS['_xh']['ac'], 'true') == 0) + { + $GLOBALS['_xh']['value']=true; + } + else + { + // log if receiveing something strange, even though we set the value to false anyway + if ($GLOBALS['_xh']['ac']!='0' && strcasecmp($_xh[$parser]['ac'], 'false') != 0) + error_log('XML-RPC: invalid value received in BOOLEAN: '.$GLOBALS['_xh']['ac']); + $GLOBALS['_xh']['value']=false; + } + } + elseif ($name=='DOUBLE') + { + // we have a DOUBLE + // we must check that only 0123456789-.<space> are characters here + if (!preg_match('/^[+-]?[eE0123456789 \t.]+$/', $GLOBALS['_xh']['ac'])) + { + /// @todo: find a better way of throwing an error + // than this! + error_log('XML-RPC: non numeric value received in DOUBLE: '.$GLOBALS['_xh']['ac']); + $GLOBALS['_xh']['value']='ERROR_NON_NUMERIC_FOUND'; + } + else + { + // it's ok, add it on + $GLOBALS['_xh']['value']=(double)$GLOBALS['_xh']['ac']; + } } else { - // it's ok, add it on - //$_xh[$parser]['st'].=(double)$_xh[$parser]['ac']; - $_xh[$parser]['value']=(double)$_xh[$parser]['ac']; + // we have an I4/INT + // we must check that only 0123456789-<space> are characters here + if (!preg_match('/^[+-]?[0123456789 \t]+$/', $GLOBALS['_xh']['ac'])) + { + /// @todo find a better way of throwing an error + // than this! + error_log('XML-RPC: non numeric value received in INT: '.$GLOBALS['_xh']['ac']); + $GLOBALS['_xh']['value']='ERROR_NON_NUMERIC_FOUND'; + } + else + { + // it's ok, add it on + $GLOBALS['_xh']['value']=(int)$GLOBALS['_xh']['ac']; + } } - } - else - { - // we have an I4/INT - // we must check that only 0123456789-<space> are characters here - if (!ereg("^[+-]?[0123456789 \\t]+$", $_xh[$parser]['ac'])) + //$GLOBALS['_xh']['ac']=''; // is this necessary? + $GLOBALS['_xh']['lv']=3; // indicate we've found a value + break; + case 'NAME': + $GLOBALS['_xh']['valuestack'][count($GLOBALS['_xh']['valuestack'])-1]['name'] = $GLOBALS['_xh']['ac']; + break; + case 'MEMBER': + //$GLOBALS['_xh']['ac']=''; // is this necessary? + // add to array in the stack the last element built, + // unless no VALUE was found + if ($GLOBALS['_xh']['vt']) + { + $vscount = count($GLOBALS['_xh']['valuestack']); + $GLOBALS['_xh']['valuestack'][$vscount-1]['values'][$GLOBALS['_xh']['valuestack'][$vscount-1]['name']] = $GLOBALS['_xh']['value']; + } else + error_log('XML-RPC: missing VALUE inside STRUCT in received xml'); + break; + case 'DATA': + //$GLOBALS['_xh']['ac']=''; // is this necessary? + $GLOBALS['_xh']['vt']=null; // reset this to check for 2 data elements in a row - even if they're empty + break; + case 'STRUCT': + case 'ARRAY': + // fetch out of stack array of values, and promote it to current value + $curr_val = array_pop($GLOBALS['_xh']['valuestack']); + $GLOBALS['_xh']['value'] = $curr_val['values']; + $GLOBALS['_xh']['vt']=strtolower($name); + if (isset($curr_val['php_class'])) { - // TODO: find a better way of throwing an error - // than this! - error_log('XML-RPC: non numeric value received in INT: '.$_xh[$parser]['ac']); - //$_xh[$parser]['st'].="'ERROR_NON_NUMERIC_FOUND'"; - $_xh[$parser]['value']='ERROR_NON_NUMERIC_FOUND'; + $GLOBALS['_xh']['php_class'] = $curr_val['php_class']; + } + break; + case 'PARAM': + // add to array of params the current value, + // unless no VALUE was found + if ($GLOBALS['_xh']['vt']) + { + $GLOBALS['_xh']['params'][]=$GLOBALS['_xh']['value']; + $GLOBALS['_xh']['pt'][]=$GLOBALS['_xh']['vt']; } else + error_log('XML-RPC: missing VALUE inside PARAM in received xml'); + break; + case 'METHODNAME': + $GLOBALS['_xh']['method']=preg_replace('/^[\n\r\t ]+/', '', $GLOBALS['_xh']['ac']); + break; + case 'NIL': + if ($GLOBALS['xmlrpc_null_extension']) { - // it's ok, add it on - //$_xh[$parser]['st'].=(int)$_xh[$parser]['ac']; - $_xh[$parser]['value']=(int)$_xh[$parser]['ac']; + $GLOBALS['_xh']['vt']='null'; + $GLOBALS['_xh']['value']=null; + $GLOBALS['_xh']['lv']=3; + break; } - } - $_xh[$parser]['ac']=''; - //$_xh[$parser]['qt']=0; - $_xh[$parser]['lv']=3; // indicate we've found a value - break; - case 'VALUE': - // This if() detects if no scalar was inside <VALUE></VALUE> - if ($_xh[$parser]['vt']=='value') - { - $_xh[$parser]['value']=$_xh[$parser]['ac']; - $_xh[$parser]['vt']=$xmlrpcString; - } - /*if (strlen($_xh[$parser]['ac'])>0 && - $_xh[$parser]['vt']==$xmlrpcString) - { - $_xh[$parser]['st'].='"'. $_xh[$parser]['ac'] . '"'; - } - // This if() detects if no scalar was inside <VALUE></VALUE> - // and pads an empty ''. - if($_xh[$parser]['st'][strlen($_xh[$parser]['st'])-1] == '(') - { - $_xh[$parser]['st'].= '""'; - } - // G. Giunta 2005/03/12 save some chars in the reconstruction of string vals... - if ($_xh[$parser]['vt'] != $xmlrpcString) - $_xh[$parser]['st'].=", '" . $_xh[$parser]['vt'] . "')"; - else - $_xh[$parser]['st'].=")"; - if ($_xh[$parser]['cm']) - { - $_xh[$parser]['st'].=','; - }*/ - - // build the xmlrpc val out of the data received, and substitute it - $temp = new xmlrpcval($_xh[$parser]['value'], $_xh[$parser]['vt']); - // check if we are inside an array or struct: - // if value just built is inside an array, let's move it into array on the stack - if (count($_xh[$parser]['valuestack']) && $_xh[$parser]['valuestack'][0]['type']=='ARRAY') - { - $_xh[$parser]['valuestack'][0]['values'][] = $temp; - } else { - $_xh[$parser]['value'] = $temp; - } - break; - case 'MEMBER': - $_xh[$parser]['ac']=''; - //$_xh[$parser]['qt']=0; - // add to array in the stack the last element built - // unless no VALUE was found - if ($_xh[$parser]['value']) - $_xh[$parser]['valuestack'][0]['values'][$_xh[$parser]['valuestack'][0]['name']] = $_xh[$parser]['value']; - else - error_log('XML-RPC: missing VALUE inside STRUCT in received xml'); - break; - case 'DATA': - $_xh[$parser]['ac']=''; - //$_xh[$parser]['qt']=0; - break; - case 'PARAM': - //$_xh[$parser]['params'][]=$_xh[$parser]['st']; - if ($_xh[$parser]['value']) - $_xh[$parser]['params'][]=$_xh[$parser]['value']; - else - error_log('XML-RPC: missing VALUE inside PARAM in received xml'); - break; - case 'METHODNAME': - $_xh[$parser]['method']=ereg_replace("^[\n\r\t ]+", '', $_xh[$parser]['ac']); - break; - case 'PARAMS': - case 'FAULT': - case 'METHODCALL': - case 'METHORESPONSE': - break; - default: - // End of INVALID ELEMENT! - // shall we add an assert here for unreachable code??? - break; - } - - // if it's a valid type name, set the type - /*if (isset($xmlrpcTypes[strtolower($name)])) - { - $_xh[$parser]['vt']=strtolower($name); - }*/ - + // drop through intentionally if nil extension not enabled + case 'PARAMS': + case 'FAULT': + case 'METHODCALL': + case 'METHORESPONSE': + break; + default: + // End of INVALID ELEMENT! + // shall we add an assert here for unreachable code??? + break; + } } + } + /// Used in decoding xmlrpc requests/responses without rebuilding xmlrpc values + function xmlrpc_ee_fast($parser, $name) + { + xmlrpc_ee($parser, $name, false); } + /// xml parser handler function for character data function xmlrpc_cd($parser, $data) { - global $_xh, $xmlrpc_backslash; - - //if (ereg("^[\n\r \t]+$", $data)) return; - // print "adding [${data}]\n"; - // skip processing if xml fault already detected - if ($_xh[$parser]['isf'] < 2) + if ($GLOBALS['_xh']['isf'] < 2) { - if ($_xh[$parser]['lv']!=3) + // "lookforvalue==3" means that we've found an entire value + // and should discard any further character data + if($GLOBALS['_xh']['lv']!=3) { - // "lookforvalue==3" means that we've found an entire value - // and should discard any further character data - if ($_xh[$parser]['lv']==1) - { + // G. Giunta 2006-08-23: useless change of 'lv' from 1 to 2 + //if($GLOBALS['_xh']['lv']==1) + //{ // if we've found text and we're just in a <value> then - // turn quoting on, as this will be a string - //$_xh[$parser]['qt']=1; - // and say we've found a value - $_xh[$parser]['lv']=2; - } - if(!@isset($_xh[$parser]['ac'])) - { - $_xh[$parser]['ac'] = ''; - } - //$_xh[$parser]['ac'].=str_replace('$', '\$', str_replace('"', '\"', str_replace(chr(92),$xmlrpc_backslash, $data))); - $_xh[$parser]['ac'].=$data; + // say we've found a value + //$GLOBALS['_xh']['lv']=2; + //} + // we always initialize the accumulator before starting parsing, anyway... + //if(!@isset($GLOBALS['_xh']['ac'])) + //{ + // $GLOBALS['_xh']['ac'] = ''; + //} + $GLOBALS['_xh']['ac'].=$data; } } } + /// xml parser handler function for 'other stuff', ie. not char data or + /// element start/end tag. In fact it only gets called on unknown entities... function xmlrpc_dh($parser, $data) { - global $_xh, $xmlrpc_backslash; - // skip processing if xml fault already detected - if ($parser[$_xh]['isf'] < 2) + if ($GLOBALS['_xh']['isf'] < 2) { - if (substr($data, 0, 1) == '&' && substr($data, -1, 1) == ';') + if(substr($data, 0, 1) == '&' && substr($data, -1, 1) == ';') { - if ($_xh[$parser]['lv']==1) - { - //$_xh[$parser]['qt']=1; - $_xh[$parser]['lv']=2; - } - //$_xh[$parser]['ac'].=str_replace('$', '\$', str_replace('"', '\"', str_replace(chr(92),$xmlrpc_backslash, $data))); - $_xh[$parser]['ac'].=$data; + // G. Giunta 2006-08-25: useless change of 'lv' from 1 to 2 + //if($GLOBALS['_xh']['lv']==1) + //{ + // $GLOBALS['_xh']['lv']=2; + //} + $GLOBALS['_xh']['ac'].=$data; } } + return true; } class xmlrpc_client { var $path; var $server; - var $port; + var $port=0; + var $method='http'; var $errno; var $errstr; var $debug=0; var $username=''; var $password=''; + var $authtype=1; var $cert=''; var $certpass=''; - var $verifypeer=1; + var $cacert=''; + var $cacertdir=''; + var $key=''; + var $keypass=''; + var $verifypeer=true; var $verifyhost=1; var $no_multicall=false; - - function xmlrpc_client($path, $server, $port=0) - { - $this->port=$port; $this->server=$server; $this->path=$path; - } - - function setDebug($in) - { - if ($in) + var $proxy=''; + var $proxyport=0; + var $proxy_user=''; + var $proxy_pass=''; + var $proxy_authtype=1; + var $cookies=array(); + /** + * List of http compression methods accepted by the client for responses. + * NB: PHP supports deflate, gzip compressions out of the box if compiled w. zlib + * + * NNB: you can set it to any non-empty array for HTTP11 and HTTPS, since + * in those cases it will be up to CURL to decide the compression methods + * it supports. You might check for the presence of 'zlib' in the output of + * curl_version() to determine wheter compression is supported or not + */ + var $accepted_compression = array(); + /** + * Name of compression scheme to be used for sending requests. + * Either null, gzip or deflate + */ + var $request_compression = ''; + /** + * CURL handle: used for keep-alive connections (PHP 4.3.8 up, see: + * http://curl.haxx.se/docs/faq.html#7.3) + */ + var $xmlrpc_curl_handle = null; + /// Wheter to use persistent connections for http 1.1 and https + var $keepalive = false; + /// Charset encodings that can be decoded without problems by the client + var $accepted_charset_encodings = array(); + /// Charset encoding to be used in serializing request. NULL = use ASCII + var $request_charset_encoding = ''; + /** + * Decides the content of xmlrpcresp objects returned by calls to send() + * valid strings are 'xmlrpcvals', 'phpvals' or 'xml' + */ + var $return_type = 'xmlrpcvals'; + + /** + * @param string $path either the complete server URL or the PATH part of the xmlrc server URL, e.g. /xmlrpc/server.php + * @param string $server the server name / ip address + * @param integer $port the port the server is listening on, defaults to 80 or 443 depending on protocol used + * @param string $method the http protocol variant: defaults to 'http', 'https' and 'http11' can be used if CURL is installed + */ + function xmlrpc_client($path, $server='', $port='', $method='') + { + // allow user to specify all params in $path + if($server == '' and $port == '' and $method == '') + { + $parts = parse_url($path); + $server = $parts['host']; + $path = $parts['path']; + if(isset($parts['query'])) + { + $path .= '?'.$parts['query']; + } + if(isset($parts['fragment'])) + { + $path .= '#'.$parts['fragment']; + } + if(isset($parts['port'])) + { + $port = $parts['port']; + } + if(isset($parts['scheme'])) + { + $method = $parts['scheme']; + } + if(isset($parts['user'])) + { + $this->username = $parts['user']; + } + if(isset($parts['pass'])) + { + $this->password = $parts['pass']; + } + } + if($path == '' || $path[0] != '/') { - $this->debug=1; + $this->path='/'.$path; } else { - $this->debug=0; + $this->path=$path; + } + $this->server=$server; + if($port != '') + { + $this->port=$port; + } + if($method != '') + { + $this->method=$method; + } + + // if ZLIB is enabled, let the client by default accept compressed responses + if(function_exists('gzinflate') || ( + function_exists('curl_init') && (($info = curl_version()) && + ((is_string($info) && strpos($info, 'zlib') !== null) || isset($info['libz_version']))) + )) + { + $this->accepted_compression = array('gzip', 'deflate'); + } + + // keepalives: enabled by default ONLY for PHP >= 4.3.8 + // (see http://curl.haxx.se/docs/faq.html#7.3) + if(version_compare(phpversion(), '4.3.8') >= 0) + { + $this->keepalive = true; } + + // by default the xml parser can support these 3 charset encodings + $this->accepted_charset_encodings = array('UTF-8', 'ISO-8859-1', 'US-ASCII'); + } + + /** + * Enables/disables the echoing to screen of the xmlrpc responses received + * @param integer $debug values 0, 1 and 2 are supported (2 = echo sent msg too, before received response) + * @access public + */ + function setDebug($in) + { + $this->debug=$in; } - function setCredentials($u, $p) + /** + * Add some http BASIC AUTH credentials, used by the client to authenticate + * @param string $u username + * @param string $p password + * @param integer $t auth type. See curl_setopt man page for supported auth types. Defaults to CURLAUTH_BASIC (basic auth) + * @access public + */ + function setCredentials($u, $p, $t=1) { $this->username=$u; $this->password=$p; + $this->authtype=$t; } + /** + * Add a client-side https certificate + * @param string $cert + * @param string $certpass + * @access public + */ function setCertificate($cert, $certpass) { $this->cert = $cert; $this->certpass = $certpass; } + /** + * Add a CA certificate to verify server with (see man page about + * CURLOPT_CAINFO for more details + * @param string $cacert certificate file name (or dir holding certificates) + * @param bool $is_dir set to true to indicate cacert is a dir. defaults to false + * @access public + */ + function setCaCertificate($cacert, $is_dir=false) + { + if ($is_dir) + { + $this->cacert = $cacert; + } + else + { + $this->cacertdir = $cacert; + } + } + + /** + * Set attributes for SSL communication: private SSL key + * @param string $key The name of a file containing a private SSL key + * @param string $keypass The secret password needed to use the private SSL key + * @access public + * NB: does not work in older php/curl installs + * Thanks to Daniel Convissor + */ + function setKey($key, $keypass) + { + $this->key = $key; + $this->keypass = $keypass; + } + + /** + * Set attributes for SSL communication: verify server certificate + * @param bool $i enable/disable verification of peer certificate + * @access public + */ function setSSLVerifyPeer($i) { $this->verifypeer = $i; } + /** + * Set attributes for SSL communication: verify match of server cert w. hostname + * @param int $i + * @access public + */ function setSSLVerifyHost($i) { $this->verifyhost = $i; } - function send($msg, $timeout=0, $method='http') + /** + * Set proxy info + * @param string $proxyhost + * @param string $proxyport Defaults to 8080 for HTTP and 443 for HTTPS + * @param string $proxyusername Leave blank if proxy has public access + * @param string $proxypassword Leave blank if proxy has public access + * @param int $proxyauthtype set to constant CURLAUTH_NTLM to use NTLM auth with proxy + * @access public + */ + function setProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '', $proxyauthtype = 1) + { + $this->proxy = $proxyhost; + $this->proxyport = $proxyport; + $this->proxy_user = $proxyusername; + $this->proxy_pass = $proxypassword; + $this->proxy_authtype = $proxyauthtype; + } + + /** + * Enables/disables reception of compressed xmlrpc responses. + * Note that enabling reception of compressed responses merely adds some standard + * http headers to xmlrpc requests. It is up to the xmlrpc server to return + * compressed responses when receiving such requests. + * @param string $compmethod either 'gzip', 'deflate', 'any' or '' + * @access public + */ + function setAcceptedCompression($compmethod) + { + if ($compmethod == 'any') + $this->accepted_compression = array('gzip', 'deflate'); + else + $this->accepted_compression = array($compmethod); + } + + /** + * Enables/disables http compression of xmlrpc request. + * Take care when sending compressed requests: servers might not support them + * (and automatic fallback to uncompressed requests is not yet implemented) + * @param string $compmethod either 'gzip', 'deflate' or '' + * @access public + */ + function setRequestCompression($compmethod) { - if (is_array($msg)) + $this->request_compression = $compmethod; + } + + /** + * Adds a cookie to list of cookies that will be sent to server. + * NB: setting any param but name and value will turn the cookie into a 'version 1' cookie: + * do not do it unless you know what you are doing + * @param string $name + * @param string $value + * @param string $path + * @param string $domain + * @param int $port + * @access public + * + * @todo check correctness of urlencoding cookie value (copied from php way of doing it...) + */ + function setCookie($name, $value='', $path='', $domain='', $port=null) + { + $this->cookies[$name]['value'] = urlencode($value); + if ($path || $domain || $port) + { + $this->cookies[$name]['path'] = $path; + $this->cookies[$name]['domain'] = $domain; + $this->cookies[$name]['port'] = $port; + $this->cookies[$name]['version'] = 1; + } + else + { + $this->cookies[$name]['version'] = 0; + } + } + + /** + * Send an xmlrpc request + * @param mixed $msg The message object, or an array of messages for using multicall, or the complete xml representation of a request + * @param integer $timeout Connection timeout, in seconds, If unspecified, a platform specific timeout will apply + * @param string $method if left unspecified, the http protocol chosen during creation of the object will be used + * @return xmlrpcresp + * @access public + */ + function& send($msg, $timeout=0, $method='') + { + // if user deos not specify http protocol, use native method of this client + // (i.e. method set during call to constructor) + if($method == '') + { + $method = $this->method; + } + + if(is_array($msg)) { // $msg is an array of xmlrpcmsg's - return $this->multicall($msg, $timeout, $method); + $r = $this->multicall($msg, $timeout, $method); + return $r; + } + elseif(is_string($msg)) + { + $n =& new xmlrpcmsg(''); + $n->payload = $msg; + $msg = $n; } // where msg is an xmlrpcmsg $msg->debug=$this->debug; - if ($method == 'https') - { - return $this->sendPayloadHTTPS($msg, - $this->server, - $this->port, $timeout, - $this->username, $this->password, - $this->cert, - $this->certpass); + if($method == 'https') + { + $r =& $this->sendPayloadHTTPS( + $msg, + $this->server, + $this->port, + $timeout, + $this->username, + $this->password, + $this->authtype, + $this->cert, + $this->certpass, + $this->cacert, + $this->cacertdir, + $this->proxy, + $this->proxyport, + $this->proxy_user, + $this->proxy_pass, + $this->proxy_authtype, + $this->keepalive, + $this->key, + $this->keypass + ); + } + elseif($method == 'http11') + { + $r =& $this->sendPayloadCURL( + $msg, + $this->server, + $this->port, + $timeout, + $this->username, + $this->password, + $this->authtype, + null, + null, + null, + null, + $this->proxy, + $this->proxyport, + $this->proxy_user, + $this->proxy_pass, + $this->proxy_authtype, + 'http', + $this->keepalive + ); } else { - return $this->sendPayloadHTTP10($msg, $this->server, $this->port, - $timeout, $this->username, - $this->password); + $r =& $this->sendPayloadHTTP10( + $msg, + $this->server, + $this->port, + $timeout, + $this->username, + $this->password, + $this->authtype, + $this->proxy, + $this->proxyport, + $this->proxy_user, + $this->proxy_pass, + $this->proxy_authtype + ); } + + return $r; } - function sendPayloadHTTP10($msg, $server, $port, $timeout=0,$username='', $password='') + /** + * @access private + */ + function &sendPayloadHTTP10($msg, $server, $port, $timeout=0, + $username='', $password='', $authtype=1, $proxyhost='', + $proxyport=0, $proxyusername='', $proxypassword='', $proxyauthtype=1) { - global $xmlrpcerr, $xmlrpcstr, $xmlrpcName, $xmlrpcVersion, $xmlrpc_defencoding; - if ($port==0) + if($port==0) { $port=80; } - if($timeout>0) + + // Only create the payload if it was not created previously + if(empty($msg->payload)) + { + $msg->createPayload($this->request_charset_encoding); + } + + $payload = $msg->payload; + // Deflate request body and set appropriate request headers + if(function_exists('gzdeflate') && ($this->request_compression == 'gzip' || $this->request_compression == 'deflate')) { - $fp=@fsockopen($server, $port,$this->errno, $this->errstr, $timeout); + if($this->request_compression == 'gzip') + { + $a = @gzencode($payload); + if($a) + { + $payload = $a; + $encoding_hdr = "Content-Encoding: gzip\r\n"; + } + } + else + { + $a = @gzcompress($payload); + if($a) + { + $payload = $a; + $encoding_hdr = "Content-Encoding: deflate\r\n"; + } + } } else { - $fp=@fsockopen($server, $port,$this->errno, $this->errstr); + $encoding_hdr = ''; } - if ($fp) + + // thanks to Grant Rauscher <grant7@firstworld.net> for this + $credentials=''; + if($username!='') { - if ($timeout>0 && function_exists('stream_set_timeout')) - stream_set_timeout($fp, $timeout); + $credentials='Authorization: Basic ' . base64_encode($username . ':' . $password) . "\r\n"; + if ($authtype != 1) + { + error_log('XML-RPC: xmlrpc_client::send: warning. Only Basic auth is supported with HTTP 1.0'); + } + } + + $accepted_encoding = ''; + if(is_array($this->accepted_compression) && count($this->accepted_compression)) + { + $accepted_encoding = 'Accept-Encoding: ' . implode(', ', $this->accepted_compression) . "\r\n"; + } + + $proxy_credentials = ''; + if($proxyhost) + { + if($proxyport == 0) + { + $proxyport = 8080; + } + $connectserver = $proxyhost; + $connectport = $proxyport; + $uri = 'http://'.$server.':'.$port.$this->path; + if($proxyusername != '') + { + if ($proxyauthtype != 1) + { + error_log('XML-RPC: xmlrpc_client::send: warning. Only Basic auth to proxy is supported with HTTP 1.0'); + } + $proxy_credentials = 'Proxy-Authorization: Basic ' . base64_encode($proxyusername.':'.$proxypassword) . "\r\n"; + } } else { - $this->errstr='Connect error'; - $r=new xmlrpcresp(0, $xmlrpcerr['http_error'],$xmlrpcstr['http_error']); - return $r; + $connectserver = $server; + $connectport = $port; + $uri = $this->path; } - // Only create the payload if it was not created previously - if(empty($msg->payload)) + + // Cookie generation, as per rfc2965 (version 1 cookies) or + // netscape's rules (version 0 cookies) + $cookieheader=''; + foreach ($this->cookies as $name => $cookie) { - $msg->createPayload(); + if ($cookie['version']) + { + $cookieheader .= 'Cookie: $Version="' . $cookie['version'] . '"; '; + $cookieheader .= $name . '="' . $cookie['value'] . '";'; + if ($cookie['path']) + $cookieheader .= ' $Path="' . $cookie['path'] . '";'; + if ($cookie['domain']) + $cookieheader .= ' $Domain="' . $cookie['domain'] . '";'; + if ($cookie['port']) + $cookieheader .= ' $Port="' . $cookie['domain'] . '";'; + $cookieheader = substr($cookieheader, 0, -1) . "\r\n"; + } + else + { + $cookieheader .= 'Cookie: ' . $name . '=' . $cookie['value'] . "\r\n"; + } } - // thanks to Grant Rauscher <grant7@firstworld.net> - // for this - $credentials=''; - if ($username!='') + $op= 'POST ' . $uri. " HTTP/1.0\r\n" . + 'User-Agent: ' . $GLOBALS['xmlrpcName'] . ' ' . $GLOBALS['xmlrpcVersion'] . "\r\n" . + 'Host: '. $server . ':' . $port . "\r\n" . + $credentials . + $proxy_credentials . + $accepted_encoding . + $encoding_hdr . + 'Accept-Charset: ' . implode(',', $this->accepted_charset_encodings) . "\r\n" . + $cookieheader . + 'Content-Type: ' . $msg->content_type . "\r\nContent-Length: " . + strlen($payload) . "\r\n\r\n" . + $payload; + + if($this->debug > 1) { - $credentials='Authorization: Basic ' . base64_encode($username . ':' . $password) . "\r\n"; + print "<PRE>\n---SENDING---\n" . htmlentities($op) . "\n---END---\n</PRE>"; + // let the client see this now in case http times out... + flush(); } - $op= "POST " . $this->path. " HTTP/1.0\r\n" . - "User-Agent: " . $xmlrpcName . " " . $xmlrpcVersion . "\r\n" . - "Host: ". $server . "\r\n" . - $credentials . - "Accept-Charset: " . $xmlrpc_defencoding . "\r\n" . - "Content-Type: text/xml\r\nContent-Length: " . - strlen($msg->payload) . "\r\n\r\n" . - $msg->payload; + if($timeout>0) + { + $fp=@fsockopen($connectserver, $connectport, $this->errno, $this->errstr, $timeout); + } + else + { + $fp=@fsockopen($connectserver, $connectport, $this->errno, $this->errstr); + } + if($fp) + { + if($timeout>0 && function_exists('stream_set_timeout')) + { + stream_set_timeout($fp, $timeout); + } + } + else + { + $this->errstr='Connect error: '.$this->errstr; + $r=&new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['http_error'], $this->errstr . ' (' . $this->errno . ')'); + return $r; + } - if (!fputs($fp, $op, strlen($op))) + if(!fputs($fp, $op, strlen($op))) { $this->errstr='Write error'; - $r=new xmlrpcresp(0, $xmlrpcerr['http_error'], $xmlrpcstr['http_error']); + $r=&new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['http_error'], $this->errstr); return $r; } - $resp=$msg->parseResponseFile($fp); + else + { + // reset errno and errstr on succesful socket connection + $this->errstr = ''; + } + // G. Giunta 2005/10/24: close socket before parsing. + // should yeld slightly better execution times, and make easier recursive calls (e.g. to follow http redirects) + $ipd=''; + while($data=fread($fp, 32768)) + { + // shall we check for $data === FALSE? + // as per the manual, it signals an error + $ipd.=$data; + } fclose($fp); - return $resp; + $r =& $msg->parseResponse($ipd, false, $this->return_type); + return $r; + } - // contributed by Justin Miller <justin@voxel.net> - // requires curl to be built into PHP - function sendPayloadHTTPS($msg, $server, $port, $timeout=0,$username='', $password='', $cert='',$certpass='') - { - global $xmlrpcerr, $xmlrpcstr, $xmlrpcVersion, $xmlrpc_internalencoding; - if ($port == 0) + /** + * @access private + */ + function &sendPayloadHTTPS($msg, $server, $port, $timeout=0, $username='', + $password='', $authtype=1, $cert='',$certpass='', $cacert='', $cacertdir='', + $proxyhost='', $proxyport=0, $proxyusername='', $proxypassword='', $proxyauthtype=1, + $keepalive=false, $key='', $keypass='') + { + $r =& $this->sendPayloadCURL($msg, $server, $port, $timeout, $username, + $password, $authtype, $cert, $certpass, $cacert, $cacertdir, $proxyhost, $proxyport, + $proxyusername, $proxypassword, $proxyauthtype, 'https', $keepalive, $key, $keypass); + return $r; + } + + /** + * Contributed by Justin Miller <justin@voxel.net> + * Requires curl to be built into PHP + * NB: CURL versions before 7.11.10 cannot use proxy to talk to https servers! + * @access private + */ + function &sendPayloadCURL($msg, $server, $port, $timeout=0, $username='', + $password='', $authtype=1, $cert='', $certpass='', $cacert='', $cacertdir='', + $proxyhost='', $proxyport=0, $proxyusername='', $proxypassword='', $proxyauthtype=1, $method='https', + $keepalive=false, $key='', $keypass='') + { + if(!function_exists('curl_init')) + { + $this->errstr='CURL unavailable on this install'; + $r=&new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['no_curl'], $GLOBALS['xmlrpcstr']['no_curl']); + return $r; + } + if($method == 'https') { - $port = 443; + if(($info = curl_version()) && + ((is_string($info) && strpos($info, 'OpenSSL') === null) || (is_array($info) && !isset($info['ssl_version'])))) + { + $this->errstr='SSL unavailable on this install'; + $r=&new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['no_ssl'], $GLOBALS['xmlrpcstr']['no_ssl']); + return $r; + } + } + + if($port == 0) + { + if($method == 'http') + { + $port = 80; + } + else + { + $port = 443; + } } // Only create the payload if it was not created previously if(empty($msg->payload)) { - $msg->createPayload(); + $msg->createPayload($this->request_charset_encoding); } - if (!function_exists('curl_init')) + // Deflate request body and set appropriate request headers + $payload = $msg->payload; + if(function_exists('gzdeflate') && ($this->request_compression == 'gzip' || $this->request_compression == 'deflate')) { - $this->errstr='SSL unavailable on this install'; - $r=new xmlrpcresp(0, $xmlrpcerr['no_ssl'], $xmlrpcstr['no_ssl']); - return $r; + if($this->request_compression == 'gzip') + { + $a = @gzencode($payload); + if($a) + { + $payload = $a; + $encoding_hdr = 'Content-Encoding: gzip'; + } + } + else + { + $a = @gzcompress($payload); + if($a) + { + $payload = $a; + $encoding_hdr = 'Content-Encoding: deflate'; + } + } + } + else + { + $encoding_hdr = ''; } - $curl = curl_init('https://' . $server . ':' . $port . $this->path); + if($this->debug > 1) + { + print "<PRE>\n---SENDING---\n" . htmlentities($payload) . "\n---END---\n</PRE>"; + // let the client see this now in case http times out... + flush(); + } + + if(!$keepalive || !$this->xmlrpc_curl_handle) + { + $curl = curl_init($method . '://' . $server . ':' . $port . $this->path); + if($keepalive) + { + $this->xmlrpc_curl_handle = $curl; + } + } + else + { + $curl = $this->xmlrpc_curl_handle; + } - curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // results into variable - if ($this->debug) + curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); + + if($this->debug) { curl_setopt($curl, CURLOPT_VERBOSE, 1); } - curl_setopt($curl, CURLOPT_USERAGENT, 'PHP XMLRPC '.$xmlrpcVersion); - // required for XMLRPC + curl_setopt($curl, CURLOPT_USERAGENT, $GLOBALS['xmlrpcName'].' '.$GLOBALS['xmlrpcVersion']); + // required for XMLRPC: post the data curl_setopt($curl, CURLOPT_POST, 1); - // post the data - curl_setopt($curl, CURLOPT_POSTFIELDS, $msg->payload); // the data - curl_setopt($curl, CURLOPT_HEADER, 1); + curl_setopt($curl, CURLOPT_POSTFIELDS, $payload); + // return the header too - curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Type: text/xml', 'Accept-Charset: '.$xmlrpc_internalencoding)); - // whether to verify remote host's cert - curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, $this->verifypeer); - // whether to verify cert's common name (CN); 0 for no, 1 to verify that it exists, and 2 to verify that it matches the hostname used - curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, $this->verifyhost); - // required for XMLRPC - if ($timeout) + curl_setopt($curl, CURLOPT_HEADER, 1); + + // will only work with PHP >= 5.0 + // NB: if we set an empty string, CURL will add http header indicating + // ALL methods it is supporting. This is possibly a better option than + // letting the user tell what curl can / cannot do... + if(is_array($this->accepted_compression) && count($this->accepted_compression)) { - curl_setopt($curl, CURLOPT_TIMEOUT, $timeout == 1 ? 1 : $timeout - 1); + //curl_setopt($curl, CURLOPT_ENCODING, implode(',', $this->accepted_compression)); + // empty string means 'any supported by CURL' (shall we catch errors in case CURLOPT_SSLKEY undefined ?) + if (count($this->accepted_compression) == 1) + { + curl_setopt($curl, CURLOPT_ENCODING, $this->accepted_compression[0]); + } + else + curl_setopt($curl, CURLOPT_ENCODING, ''); + } + // extra headers + $headers = array('Content-Type: ' . $msg->content_type , 'Accept-Charset: ' . implode(',', $this->accepted_charset_encodings)); + // if no keepalive is wanted, let the server know it in advance + if(!$keepalive) + { + $headers[] = 'Connection: close'; + } + // request compression header + if($encoding_hdr) + { + $headers[] = $encoding_hdr; } + + curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); // timeout is borked - if ($username && $password) + if($timeout) { - curl_setopt($curl, CURLOPT_USERPWD,"$username:$password"); + curl_setopt($curl, CURLOPT_TIMEOUT, $timeout == 1 ? 1 : $timeout - 1); } - // set auth stuff - if ($cert) + + if($username && $password) { - curl_setopt($curl, CURLOPT_SSLCERT, $cert); + curl_setopt($curl, CURLOPT_USERPWD, $username.':'.$password); + if (defined('CURLOPT_HTTPAUTH')) + { + curl_setopt($curl, CURLOPT_HTTPAUTH, $authtype); + } + else if ($authtype != 1) + { + error_log('XML-RPC: xmlrpc_client::send: warning. Only Basic auth is supported by the current PHP/curl install'); + } } - // set cert file - if ($certpass) + + if($method == 'https') { - curl_setopt($curl, CURLOPT_SSLCERTPASSWD,$certpass); + // set cert file + if($cert) + { + curl_setopt($curl, CURLOPT_SSLCERT, $cert); + } + // set cert password + if($certpass) + { + curl_setopt($curl, CURLOPT_SSLCERTPASSWD, $certpass); + } + // whether to verify remote host's cert + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, $this->verifypeer); + // set ca certificates file/dir + if($cacert) + { + curl_setopt($curl, CURLOPT_CAINFO, $cacert); + } + if($cacertdir) + { + curl_setopt($curl, CURLOPT_CAPATH, $cacertdir); + } + // set key file (shall we catch errors in case CURLOPT_SSLKEY undefined ?) + if($key) + { + curl_setopt($curl, CURLOPT_SSLKEY, $key); + } + // set key password (shall we catch errors in case CURLOPT_SSLKEY undefined ?) + if($keypass) + { + curl_setopt($curl, CURLOPT_SSLKEYPASSWD, $keypass); + } + // whether to verify cert's common name (CN); 0 for no, 1 to verify that it exists, and 2 to verify that it matches the hostname used + curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, $this->verifyhost); + } + + // proxy info + if($proxyhost) + { + if($proxyport == 0) + { + $proxyport = 8080; // NB: even for HTTPS, local connection is on port 8080 + } + curl_setopt($curl, CURLOPT_PROXY,$proxyhost.':'.$proxyport); + //curl_setopt($curl, CURLOPT_PROXYPORT,$proxyport); + if($proxyusername) + { + curl_setopt($curl, CURLOPT_PROXYUSERPWD, $proxyusername.':'.$proxypassword); + if (defined('CURLOPT_PROXYAUTH')) + { + curl_setopt($curl, CURLOPT_PROXYAUTH, $proxyauthtype); + } + else if ($proxyauthtype != 1) + { + error_log('XML-RPC: xmlrpc_client::send: warning. Only Basic auth to proxy is supported by the current PHP/curl install'); + } + } + } + + // NB: should we build cookie http headers by hand rather than let CURL do it? + // the following code does not honour 'expires', 'path' and 'domain' cookie attributes + // set to clint obj the the user... + if (count($this->cookies)) + { + $cookieheader = ''; + foreach ($this->cookies as $name => $cookie) + { + $cookieheader .= $name . '=' . $cookie['value'] . ', '; + } + curl_setopt($curl, CURLOPT_COOKIE, substr($cookieheader, 0, -2)); } - // set cert password $result = curl_exec($curl); - if (!$result) + if(!$result) { $this->errstr='no response'; - $resp=new xmlrpcresp(0, $xmlrpcerr['curl_fail'], $xmlrpcstr['curl_fail']. ': '. curl_error($curl)); - curl_close($curl); + $resp=&new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['curl_fail'], $GLOBALS['xmlrpcstr']['curl_fail']. ': '. curl_error($curl)); + if(!$keepalive) + { + curl_close($curl); + } } else { - curl_close($curl); - $resp = $msg->parseResponse($result); + if(!$keepalive) + { + curl_close($curl); + } + $resp =& $msg->parseResponse($result, true, $this->return_type); } return $resp; } - function multicall($msgs, $timeout=0, $method='http') - { - $results = false; - - if (! $this->no_multicall) + /** + * Send an array of request messages and return an array of responses. + * Unless $this->no_multicall has been set to true, it will try first + * to use one single xmlrpc call to server method system.multicall, and + * revert to sending many successive calls in case of failure. + * This failure is also stored in $this->no_multicall for subsequent calls. + * Unfortunately, there is no server error code universally used to denote + * the fact that multicall is unsupported, so there is no way to reliably + * distinguish between that and a temporary failure. + * If you are sure that server supports multicall and do not want to + * fallback to using many single calls, set the fourth parameter to FALSE. + * + * NB: trying to shoehorn extra functionality into existing syntax has resulted + * in pretty much convoluted code... + * + * @param array $msgs an array of xmlrpcmsg objects + * @param integer $timeout connection timeout (in seconds) + * @param string $method the http protocol variant to be used + * @param boolean fallback When true, upon receiveing an error during multicall, multiple single calls will be attempted + * @return array + * @access public + */ + function multicall($msgs, $timeout=0, $method='', $fallback=true) + { + if ($method == '') + { + $method = $this->method; + } + if(!$this->no_multicall) { $results = $this->_try_multicall($msgs, $timeout, $method); - /* TODO - this is not php3-friendly */ - // if($results !== false) if(is_array($results)) { - // Either the system.multicall succeeded, or the send - // failed (e.g. due to HTTP timeout). In either case, - // we're done for now. + // System.multicall succeeded return $results; } else { - // system.multicall unsupported by server, - // don't try it next time... - $this->no_multicall = true; + // either system.multicall is unsupported by server, + // or call failed for some other reason. + if ($fallback) + { + // Don't try it next time... + $this->no_multicall = true; + } + else + { + if (is_a($results, 'xmlrpcresp')) + { + $result = $results; + } + else + { + $result =& new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['multicall_error'], $GLOBALS['xmlrpcstr']['multicall_error']); + } + } } } + else + { + // override fallback, in case careless user tries to do two + // opposite things at the same time + $fallback = true; + } - // system.multicall is unupported by server: - // Emulate multicall via multiple requests $results = array(); - //foreach($msgs as $msg) - @reset($msgs); - while(list(,$msg) = @each($msgs)) + if ($fallback) + { + // system.multicall is (probably) unsupported by server: + // emulate multicall via multiple requests + foreach($msgs as $msg) + { + $results[] =& $this->send($msg, $timeout, $method); + } + } + else { - $results[] = $this->send($msg, $timeout, $method); + // user does NOT want to fallback on many single calls: + // since we should always return an array of responses, + // return an array with the same error repeated n times + foreach($msgs as $msg) + { + $results[] = $result; + } } return $results; } - // Attempt to boxcar $msgs via system.multicall. + /** + * Attempt to boxcar $msgs via system.multicall. + * Returns either an array of xmlrpcreponses, an xmlrpc error response + * or false (when received response does not respect valid multicall syntax) + * @access private + */ function _try_multicall($msgs, $timeout, $method) { // Construct multicall message $calls = array(); - //foreach($msgs as $msg) - @reset($msgs); - while(list(,$msg) = @each($msgs)) + foreach($msgs as $msg) { - $call['methodName'] = new xmlrpcval($msg->method(),'string'); + $call['methodName'] =& new xmlrpcval($msg->method(),'string'); $numParams = $msg->getNumParams(); $params = array(); - for ($i = 0; $i < $numParams; $i++) + for($i = 0; $i < $numParams; $i++) { $params[$i] = $msg->getParam($i); } - $call['params'] = new xmlrpcval($params, 'array'); - $calls[] = new xmlrpcval($call, 'struct'); + $call['params'] =& new xmlrpcval($params, 'array'); + $calls[] =& new xmlrpcval($call, 'struct'); } - $multicall = new xmlrpcmsg('system.multicall'); + $multicall =& new xmlrpcmsg('system.multicall'); $multicall->addParam(new xmlrpcval($calls, 'array')); // Attempt RPC call - $result = $this->send($multicall, $timeout, $method); - if(!is_object($result)) - { - return ($result || 0); // transport failed - } + $result =& $this->send($multicall, $timeout, $method); if($result->faultCode() != 0) { - return false; // system.multicall failed + // call to system.multicall failed + return $result; } // Unpack responses. $rets = $result->value(); - if($rets->kindOf() != 'array') + + if ($this->return_type == 'xml') { - return false; // bad return type from system.multicall + return $rets; } - $numRets = $rets->arraysize(); - if($numRets != count($msgs)) + else if ($this->return_type == 'phpvals') { - return false; // wrong number of return values. - } + ///@todo test this code branch... + $rets = $result->value(); + if(!is_array($rets)) + { + return false; // bad return type from system.multicall + } + $numRets = count($rets); + if($numRets != count($msgs)) + { + return false; // wrong number of return values. + } - $response = array(); - for ($i = 0; $i < $numRets; $i++) - { - $val = $rets->arraymem($i); - switch ($val->kindOf()) + $response = array(); + for($i = 0; $i < $numRets; $i++) { - case 'array': - if($val->arraysize() != 1) - { - return false; // Bad value + $val = $rets[$i]; + if (!is_array($val)) { + return false; } - // Normal return value - $response[$i] = new xmlrpcresp($val->arraymem(0)); - break; - case 'struct': - $code = $val->structmem('faultCode'); - if($code->kindOf() != 'scalar' || $code->scalartyp() != 'int') + switch(count($val)) { - return false; + case 1: + if(!isset($val[0])) + { + return false; // Bad value + } + // Normal return value + $response[$i] =& new xmlrpcresp($val[0], 0, '', 'phpvals'); + break; + case 2: + /// @todo remove usage of @: it is apparently quite slow + $code = @$val['faultCode']; + if(!is_int($code)) + { + return false; + } + $str = @$val['faultString']; + if(!is_string($str)) + { + return false; + } + $response[$i] =& new xmlrpcresp(0, $code, $str); + break; + default: + return false; } - $str = $val->structmem('faultString'); - if($str->kindOf() != 'scalar' || $str->scalartyp() != 'string') + } + return $response; + } + else // return type == 'xmlrpcvals' + { + $rets = $result->value(); + if($rets->kindOf() != 'array') + { + return false; // bad return type from system.multicall + } + $numRets = $rets->arraysize(); + if($numRets != count($msgs)) + { + return false; // wrong number of return values. + } + + $response = array(); + for($i = 0; $i < $numRets; $i++) + { + $val = $rets->arraymem($i); + switch($val->kindOf()) { - return false; + case 'array': + if($val->arraysize() != 1) + { + return false; // Bad value + } + // Normal return value + $response[$i] =& new xmlrpcresp($val->arraymem(0)); + break; + case 'struct': + $code = $val->structmem('faultCode'); + if($code->kindOf() != 'scalar' || $code->scalartyp() != 'int') + { + return false; + } + $str = $val->structmem('faultString'); + if($str->kindOf() != 'scalar' || $str->scalartyp() != 'string') + { + return false; + } + $response[$i] =& new xmlrpcresp(0, $code->scalarval(), $str->scalarval()); + break; + default: + return false; } - $response[$i] = new xmlrpcresp(0, $code->scalarval(), $str->scalarval()); - break; - default: - return false; } + return $response; } - return $response; } } // end class xmlrpc_client class xmlrpcresp { var $val = 0; + var $valtyp; var $errno = 0; var $errstr = ''; + var $payload; var $hdrs = array(); - - function xmlrpcresp($val, $fcode = 0, $fstr = '') - { - if ($fcode != 0) - { - // error + var $_cookies = array(); + var $content_type = 'text/xml'; + var $raw_data = ''; + + /** + * @param mixed $val either an xmlrpcval obj, a php value or the xml serialization of an xmlrpcval (a string) + * @param integer $fcode set it to anything but 0 to create an error response + * @param string $fstr the error string, in case of an error response + * @param string $valtyp either 'xmlrpcvals', 'phpvals' or 'xml' + * + * @todo add check that $val / $fcode / $fstr is of correct type??? + * NB: as of now we do not do it, since it might be either an xmlrpcval or a plain + * php val, or a complete xml chunk, depending on usage of xmlrpc_client::send() inside which creator is called... + */ + function xmlrpcresp($val, $fcode = 0, $fstr = '', $valtyp='') + { + if($fcode != 0) + { + // error response $this->errno = $fcode; $this->errstr = $fstr; //$this->errstr = htmlspecialchars($fstr); // XXX: encoding probably shouldn't be done here; fix later. } - elseif (!is_object($val)) - { - // programmer error - error_log("Invalid type '" . gettype($val) . "' (value: $val) passed to xmlrpcresp. Defaulting to empty value."); - $this->val = new xmlrpcval(); - } else { - // success + // successful response $this->val = $val; + if ($valtyp == '') + { + // user did not declare type of response value: try to guess it + if (is_object($this->val) && is_a($this->val, 'xmlrpcval')) + { + $this->valtyp = 'xmlrpcvals'; + } + else if (is_string($this->val)) + { + $this->valtyp = 'xml'; + + } + else + { + $this->valtyp = 'phpvals'; + } + } + else + { + // user declares type of resp value: believe him + $this->valtyp = $valtyp; + } } } + /** + * Returns the error code of the response. + * @return integer the error code of this response (0 for not-error responses) + * @access public + */ function faultCode() { return $this->errno; } + /** + * Returns the error code of the response. + * @return string the error string of this response ('' for not-error responses) + * @access public + */ function faultString() { return $this->errstr; } + /** + * Returns the value received by the server. + * @return mixed the xmlrpcval object returned by the server. Might be an xml string or php value if the response has been created by specially configured xmlrpc_client objects + * @access public + */ function value() { return $this->val; } - function serialize() + /** + * Returns an array with the cookies received from the server. + * Array has the form: $cookiename => array ('value' => $val, $attr1 => $val1, $attr2 = $val2, ...) + * with attributes being e.g. 'expires', 'path', domain'. + * NB: cookies sent as 'expired' by the server (i.e. with an expiry date in the past) + * are still present in the array. It is up to the user-defined code to decide + * how to use the received cookies, and wheter they have to be sent back with the next + * request to the server (using xmlrpc_client::setCookie) or not + * @return array array of cookies received from the server + * @access public + */ + function cookies() + { + return $this->_cookies; + } + + /** + * Returns xml representation of the response. XML prologue not included + * @param string $charset_encoding the charset to be used for serialization. if null, US-ASCII is assumed + * @return string the xml representation of the response + * @access public + */ + function serialize($charset_encoding='') { + if ($charset_encoding != '') + $this->content_type = 'text/xml; charset=' . $charset_encoding; + else + $this->content_type = 'text/xml'; $result = "<methodResponse>\n"; - if ($this->errno) + if($this->errno) { // G. Giunta 2005/2/13: let non-ASCII response messages be tolerated by clients - $result .= '<fault> -<value> -<struct> -<member> -<name>faultCode</name> -<value><int>' . $this->errno . '</int></value> -</member> -<member> -<name>faultString</name> -<value><string>' . xmlrpc_encode_entitites($this->errstr) . '</string></value> -</member> -</struct> -</value> -</fault>'; + // by xml-encoding non ascii chars + $result .= "<fault>\n" . +"<value>\n<struct><member><name>faultCode</name>\n<value><int>" . $this->errno . +"</int></value>\n</member>\n<member>\n<name>faultString</name>\n<value><string>" . +xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $charset_encoding) . "</string></value>\n</member>\n" . +"</struct>\n</value>\n</fault>"; } else { - $result .= "<params>\n<param>\n" . - $this->val->serialize() . - "</param>\n</params>"; + if(!is_object($this->val) || !is_a($this->val, 'xmlrpcval')) + { + if (is_string($this->val) && $this->valtyp == 'xml') + { + $result .= "<params>\n<param>\n" . + $this->val . + "</param>\n</params>"; + } + else + { + /// @todo try to build something serializable? + die('cannot serialize xmlrpcresp objects whose content is native php values'); + } + } + else + { + $result .= "<params>\n<param>\n" . + $this->val->serialize($charset_encoding) . + "</param>\n</params>"; + } } $result .= "\n</methodResponse>"; + $this->payload = $result; return $result; } } @@ -1359,218 +2030,514 @@ var $methodname; var $params=array(); var $debug=0; + var $content_type = 'text/xml'; + /** + * @param string $meth the name of the method to invoke + * @param array $pars array of parameters to be paased to the method (xmlrpcval objects) + */ function xmlrpcmsg($meth, $pars=0) { $this->methodname=$meth; - if (is_array($pars) && sizeof($pars)>0) + if(is_array($pars) && count($pars)>0) { - for($i=0; $i<sizeof($pars); $i++) + for($i=0; $i<count($pars); $i++) { $this->addParam($pars[$i]); } } } - function xml_header() + /** + * @access private + */ + function xml_header($charset_encoding='') { - return "<?xml version=\"1.0\"?" . ">\n<methodCall>\n"; + if ($charset_encoding != '') + { + return "<?xml version=\"1.0\" encoding=\"$charset_encoding\" ?" . ">\n<methodCall>\n"; + } + else + { + return "<?xml version=\"1.0\"?" . ">\n<methodCall>\n"; + } } + /** + * @access private + */ function xml_footer() { - return "</methodCall>\n"; + return '</methodCall>'; + } + + /** + * @access private + */ + function kindOf() + { + return 'msg'; } - function createPayload() + /** + * @access private + */ + function createPayload($charset_encoding='') { - $this->payload=$this->xml_header(); + if ($charset_encoding != '') + $this->content_type = 'text/xml; charset=' . $charset_encoding; + else + $this->content_type = 'text/xml'; + $this->payload=$this->xml_header($charset_encoding); $this->payload.='<methodName>' . $this->methodname . "</methodName>\n"; - // if (sizeof($this->params)) { $this->payload.="<params>\n"; - for($i=0; $i<sizeof($this->params); $i++) + for($i=0; $i<count($this->params); $i++) { $p=$this->params[$i]; - $this->payload.="<param>\n" . $p->serialize() . + $this->payload.="<param>\n" . $p->serialize($charset_encoding) . "</param>\n"; } $this->payload.="</params>\n"; - // } $this->payload.=$this->xml_footer(); - //$this->payload=str_replace("\n", "\r\n", $this->payload); } + /** + * Gets/sets the xmlrpc method to be invoked + * @param string $meth the method to be set (leave empty not to set it) + * @return string the method that will be invoked + * @access public + */ function method($meth='') { - if ($meth!='') + if($meth!='') { $this->methodname=$meth; } return $this->methodname; } - function serialize() + /** + * Returns xml representation of the message. XML prologue included + * @return string the xml representation of the message, xml prologue included + * @access public + */ + function serialize($charset_encoding='') { - $this->createPayload(); + $this->createPayload($charset_encoding); return $this->payload; } - function addParam($par) { $this->params[]=$par; } + /** + * Add a parameter to the list of parameters to be used upon method invocation + * @param xmlrpcval $par + * @return boolean false on failure + * @access public + */ + function addParam($par) + { + // add check: do not add to self params which are not xmlrpcvals + if(is_object($par) && is_a($par, 'xmlrpcval')) + { + $this->params[]=$par; + return true; + } + else + { + return false; + } + } + + /** + * Returns the nth parameter in the message. The index zero-based. + * @param integer $i the index of the parameter to fetch (zero based) + * @return xmlrpcval the i-th parameter + * @access public + */ function getParam($i) { return $this->params[$i]; } - function getNumParams() { return sizeof($this->params); } - function parseResponseFile($fp) + /** + * Returns the number of parameters in the messge. + * @return integer the number of parameters currently set + * @access public + */ + function getNumParams() { return count($this->params); } + + /** + * Given an open file handle, read all data available and parse it as axmlrpc response. + * NB: the file handle is not closed by this function. + * @access public + * @return xmlrpcresp + * @todo add 2nd & 3rd param to be passed to ParseResponse() ??? + */ + function &parseResponseFile($fp) { $ipd=''; while($data=fread($fp, 32768)) { $ipd.=$data; } - return $this->parseResponse($ipd); + //fclose($fp); + $r =& $this->parseResponse($ipd); + return $r; } - function parseResponse($data='') + /** + * Parses HTTP headers and separates them from data. + * @access private + */ + function &parseResponseHeaders(&$data, $headers_processed=false) { - global $_xh,$xmlrpcerr,$xmlrpcstr; - global $xmlrpc_defencoding, $xmlrpc_internalencoding; - - $hdrfnd = 0; - if($this->debug) - { - //by maHo, replaced htmlspecialchars with htmlentities - print "<PRE>---GOT---\n" . htmlentities($data) . "\n---END---\n</PRE>"; - } + // Support "web-proxy-tunelling" connections for https through proxies + if(preg_match('/^HTTP\/1\.[0-1] 200 Connection established/', $data)) + { + // Look for CR/LF or simple LF as line separator, + // (even though it is not valid http) + $pos = strpos($data,"\r\n\r\n"); + if($pos || is_int($pos)) + { + $bd = $pos+4; + } + else + { + $pos = strpos($data,"\n\n"); + if($pos || is_int($pos)) + { + $bd = $pos+2; + } + else + { + // No separation between response headers and body: fault? + $bd = 0; + } + } + if ($bd) + { + // this filters out all http headers from proxy. + // maybe we could take them into account, too? + $data = substr($data, $bd); + } + else + { + error_log('XML-RPC: xmlrpcmsg::parseResponse: HTTPS via proxy error, tunnel connection possibly failed'); + $r=&new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['http_error'], $GLOBALS['xmlrpcstr']['http_error']. ' (HTTPS via proxy error, tunnel connection possibly failed)'); + return $r; + } + } - if($data == '') - { - error_log('No response received from server.'); - $r = new xmlrpcresp(0, $xmlrpcerr['no_data'], $xmlrpcstr['no_data']); - return $r; - } - // see if we got an HTTP 200 OK, else bomb - // but only do this if we're using the HTTP protocol. - if(ereg("^HTTP",$data)) - { // Strip HTTP 1.1 100 Continue header if present - while (ereg('^HTTP/1.1 1[0-9]{2}', $data)) + while(preg_match('/^HTTP\/1\.1 1[0-9]{2} /', $data)) { $pos = strpos($data, 'HTTP', 12); // server sent a Continue header without any (valid) content following... // give the client a chance to know it - if (!$pos && !is_int($pos)) // works fine in php 3, 4 and 5 + if(!$pos && !is_int($pos)) // works fine in php 3, 4 and 5 + { break; + } $data = substr($data, $pos); } - if (!ereg("^HTTP/[0-9\\.]+ 200 ", $data)) + if(!preg_match('/^HTTP\/[0-9.]+ 200 /', $data)) { $errstr= substr($data, 0, strpos($data, "\n")-1); - error_log('HTTP error, got response: ' .$errstr); - $r=new xmlrpcresp(0, $xmlrpcerr['http_error'], $xmlrpcstr['http_error']. ' (' . $errstr . ')'); + error_log('XML-RPC: xmlrpcmsg::parseResponse: HTTP error, got response: ' .$errstr); + $r=&new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['http_error'], $GLOBALS['xmlrpcstr']['http_error']. ' (' . $errstr . ')'); return $r; } - } - $parser = xml_parser_create($xmlrpc_defencoding); - // G. Giunta 2004/04/06 - // Clean up the accumulator, or it will grow indefinitely long - // if making xmlrpc calls for a while - $_xh=array(); - $_xh[$parser]=array(); - $_xh[$parser]['headers'] = array(); - $_xh[$parser]['stack'] = array(); - $_xh[$parser]['valuestack'] = array(); + $GLOBALS['_xh']['headers'] = array(); + $GLOBALS['_xh']['cookies'] = array(); - // separate HTTP headers from data - if (ereg("^HTTP", $data)) - { // be tolerant to usage of \n instead of \r\n to separate headers and data // (even though it is not valid http) $pos = strpos($data,"\r\n\r\n"); if($pos || is_int($pos)) + { $bd = $pos+4; + } else { $pos = strpos($data,"\n\n"); if($pos || is_int($pos)) + { $bd = $pos+2; + } else { // No separation between response headers and body: fault? + // we could take some action here instead of going on... $bd = 0; } } // be tolerant to line endings, and extra empty lines $ar = split("\r?\n", trim(substr($data, 0, $pos))); - while (list(,$line) = @each($ar)) + while(list(,$line) = @each($ar)) { - // take care of multi-line headers - $arr = explode(':',$line); + // take care of multi-line headers and cookies + $arr = explode(':',$line,2); if(count($arr) > 1) { - $header_name = trim($arr[0]); - // TO DO: some headers (the ones that allow a CSV list of values) - // do allow many values to be passed using multiple header lines. - // We should add content to $_xh[$parser]['headers'][$header_name] - // instead of replacing it for those... - $_xh[$parser]['headers'][$header_name] = $arr[1]; - for ($i = 2; $i < count($arr); $i++) + $header_name = strtolower(trim($arr[0])); + /// @todo some other headers (the ones that allow a CSV list of values) + /// do allow many values to be passed using multiple header lines. + /// We should add content to $GLOBALS['_xh']['headers'][$header_name] + /// instead of replacing it for those... + if ($header_name == 'set-cookie' || $header_name == 'set-cookie2') { - $_xh[$parser]['headers'][$header_name] .= ':'.$arr[$i]; - } // while - $_xh[$parser]['headers'][$header_name] = trim($_xh[$parser]['headers'][$header_name]); - } else if (isset($header_name)) + if ($header_name == 'set-cookie2') + { + // version 2 cookies: + // there could be many cookies on one line, comma separated + $cookies = explode(',', $arr[1]); + } + else + { + $cookies = array($arr[1]); + } + foreach ($cookies as $cookie) + { + // glue together all received cookies, using a comma to separate them + // (same as php does with getallheaders()) + if (isset($GLOBALS['_xh']['headers'][$header_name])) + $GLOBALS['_xh']['headers'][$header_name] .= ', ' . trim($cookie); + else + $GLOBALS['_xh']['headers'][$header_name] = trim($cookie); + // parse cookie attributes, in case user wants to correctly honour them + // feature creep: only allow rfc-compliant cookie attributes? + $cookie = explode(';', $cookie); + foreach ($cookie as $pos => $val) + { + $val = explode('=', $val, 2); + $tag = trim($val[0]); + $val = trim(@$val[1]); + /// @todo with version 1 cookies, we should strip leading and trailing " chars + if ($pos == 0) + { + $cookiename = $tag; + $GLOBALS['_xh']['cookies'][$tag] = array(); + $GLOBALS['_xh']['cookies'][$cookiename]['value'] = urldecode($val); + } + else + { + $GLOBALS['_xh']['cookies'][$cookiename][$tag] = $val; + } + } + } + } + else + { + $GLOBALS['_xh']['headers'][$header_name] = trim($arr[1]); + } + } + elseif(isset($header_name)) { - $_xh[$parser]['headers'][$header_name] .= ' ' . trim($line); + /// @todo version1 cookies might span multiple lines, thus breaking the parsing above + $GLOBALS['_xh']['headers'][$header_name] .= ' ' . trim($line); } } + $data = substr($data, $bd); - if ($this->debug && count($_xh[$parser]['headers'])) + if($this->debug && count($GLOBALS['_xh']['headers'])) { print '<PRE>'; - //foreach ($_xh[$parser]['headers'] as $header) - @reset($_xh[$parser]['headers']); - while(list($header, $value) = @each($_xh[$parser]['headers'])) + foreach($GLOBALS['_xh']['headers'] as $header => $value) + { + print htmlentities("HEADER: $header: $value\n"); + } + foreach($GLOBALS['_xh']['cookies'] as $header => $value) { - print "HEADER: $header: $value\n"; + print htmlentities("COOKIE: $header={$value['value']}\n"); } print "</PRE>\n"; } + + // if CURL was used for the call, http headers have been processed, + // and dechunking + reinflating have been carried out + if(!$headers_processed) + { + // Decode chunked encoding sent by http 1.1 servers + if(isset($GLOBALS['_xh']['headers']['transfer-encoding']) && $GLOBALS['_xh']['headers']['transfer-encoding'] == 'chunked') + { + if(!$data = decode_chunked($data)) + { + error_log('XML-RPC: xmlrpcmsg::parseResponse: errors occurred when trying to rebuild the chunked data received from server'); + $r =& new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['dechunk_fail'], $GLOBALS['xmlrpcstr']['dechunk_fail']); + return $r; + } + } + + // Decode gzip-compressed stuff + // code shamelessly inspired from nusoap library by Dietrich Ayala + if(isset($GLOBALS['_xh']['headers']['content-encoding'])) + { + $GLOBALS['_xh']['headers']['content-encoding'] = str_replace('x-', '', $GLOBALS['_xh']['headers']['content-encoding']); + if($GLOBALS['_xh']['headers']['content-encoding'] == 'deflate' || $GLOBALS['_xh']['headers']['content-encoding'] == 'gzip') + { + // if decoding works, use it. else assume data wasn't gzencoded + if(function_exists('gzinflate')) + { + if($GLOBALS['_xh']['headers']['content-encoding'] == 'deflate' && $degzdata = @gzuncompress($data)) + { + $data = $degzdata; + if($this->debug) + print "<PRE>---INFLATED RESPONSE---[".strlen($data)." chars]---\n" . htmlentities($data) . "\n---END---</PRE>"; + } + elseif($GLOBALS['_xh']['headers']['content-encoding'] == 'gzip' && $degzdata = @gzinflate(substr($data, 10))) + { + $data = $degzdata; + if($this->debug) + print "<PRE>---INFLATED RESPONSE---[".strlen($data)." chars]---\n" . htmlentities($data) . "\n---END---</PRE>"; + } + else + { + error_log('XML-RPC: xmlrpcmsg::parseResponse: errors occurred when trying to decode the deflated data received from server'); + $r =& new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['decompress_fail'], $GLOBALS['xmlrpcstr']['decompress_fail']); + return $r; + } + } + else + { + error_log('XML-RPC: xmlrpcmsg::parseResponse: the server sent deflated data. Your php install must have the Zlib extension compiled in to support this.'); + $r =& new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['cannot_decompress'], $GLOBALS['xmlrpcstr']['cannot_decompress']); + return $r; + } + } + } + } // end of 'if needed, de-chunk, re-inflate response' + + // real stupid hack to avoid PHP 4 complaining about returning NULL by ref + $r = null; + $r =& $r; + return $r; + } + + /** + * Parse the xmlrpc response contained in the string $data and return an xmlrpcresp object. + * @param string $data the xmlrpc response, eventually including http headers + * @param bool $headers_processed when true prevents parsing HTTP headers for interpretation of content-encoding and consequent decoding + * @param string $return_type decides return type, i.e. content of response->value(). Either 'xmlrpcvals', 'xml' or 'phpvals' + * @return xmlrpcresp + * @access public + */ + function &parseResponse($data='', $headers_processed=false, $return_type='xmlrpcvals') + { + if($this->debug) + { + //by maHo, replaced htmlspecialchars with htmlentities + print "<PRE>---GOT---\n" . htmlentities($data) . "\n---END---\n</PRE>"; + } + + if($data == '') + { + error_log('XML-RPC: xmlrpcmsg::parseResponse: no response received from server.'); + $r =& new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['no_data'], $GLOBALS['xmlrpcstr']['no_data']); + return $r; + } + + $GLOBALS['_xh']=array(); + + $raw_data = $data; + // parse the HTTP headers of the response, if present, and separate them from data + if(substr($data, 0, 4) == 'HTTP') + { + $r =& $this->parseResponseHeaders($data, $headers_processed); + if ($r) + { + // failed processing of HTTP response headers + // save into response obj the full payload received, for debugging + $r->raw_data = $data; + return $r; + } + } + else + { + $GLOBALS['_xh']['headers'] = array(); + $GLOBALS['_xh']['cookies'] = array(); + } + + if($this->debug) + { + $start = strpos($data, '<!-- SERVER DEBUG INFO (BASE64 ENCODED):'); + if ($start) + { + $start += strlen('<!-- SERVER DEBUG INFO (BASE64 ENCODED):'); + $end = strpos($data, '-->', $start); + $comments = substr($data, $start, $end-$start); + print "<PRE>---SERVER DEBUG INFO (DECODED) ---\n\t".htmlentities(str_replace("\n", "\n\t", base64_decode($comments)))."\n---END---\n</PRE>"; + } } // be tolerant of extra whitespace in response body $data = trim($data); - // be tolerant of junk after methodResponse (e.g. javascript automatically inserted by free hosts) + /// @todo return an error msg if $data=='' ? + + // be tolerant of junk after methodResponse (e.g. javascript ads automatically inserted by free hosts) // idea from Luca Mariano <luca.mariano@email.it> originally in PEARified version of the lib $bd = false; - $pos = strpos($data, "</methodResponse>"); - while ($pos || is_int($pos)) + // Poor man's version of strrpos for php 4... + $pos = strpos($data, '</methodResponse>'); + while($pos || is_int($pos)) { $bd = $pos+17; - $pos = strpos($data, "</methodResponse>", $bd); + $pos = strpos($data, '</methodResponse>', $bd); } - if ($bd) + if($bd) + { $data = substr($data, 0, $bd); + } + + // if user wants back raw xml, give it to him + if ($return_type == 'xml') + { + $r =& new xmlrpcresp($data, 0, '', 'xml'); + $r->hdrs = $GLOBALS['_xh']['headers']; + $r->_cookies = $GLOBALS['_xh']['cookies']; + $r->raw_data = $raw_data; + return $r; + } - //$_xh[$parser]['st']=''; - //$_xh[$parser]['cm']=0; - $_xh[$parser]['isf']=0; - $_xh[$parser]['isf_reason']=0; - $_xh[$parser]['ac']=''; - //$_xh[$parser]['qt']=''; + // try to 'guestimate' the character encoding of the received response + $resp_encoding = guess_encoding(@$GLOBALS['_xh']['headers']['content-type'], $data); + $GLOBALS['_xh']['ac']=''; + //$GLOBALS['_xh']['qt']=''; //unused... + $GLOBALS['_xh']['stack'] = array(); + $GLOBALS['_xh']['valuestack'] = array(); + $GLOBALS['_xh']['isf']=0; // 0 = OK, 1 for xmlrpc fault responses, 2 = invalid xmlrpc + $GLOBALS['_xh']['isf_reason']=''; + $GLOBALS['_xh']['rt']=''; // 'methodcall or 'methodresponse' + + // if response charset encoding is not known / supported, try to use + // the default encoding and parse the xml anyway, but log a warning... + if (!in_array($resp_encoding, array('UTF-8', 'ISO-8859-1', 'US-ASCII'))) + // the following code might be better for mb_string enabled installs, but + // makes the lib about 200% slower... + //if (!is_valid_charset($resp_encoding, array('UTF-8', 'ISO-8859-1', 'US-ASCII'))) + { + error_log('XML-RPC: xmlrpcmsg::parseResponse: invalid charset encoding of received response: '.$resp_encoding); + $resp_encoding = $GLOBALS['xmlrpc_defencoding']; + } + $parser = xml_parser_create($resp_encoding); xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true); // G. Giunta 2005/02/13: PHP internally uses ISO-8859-1, so we have to tell // the xml parser to give us back data in the expected charset - xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $xmlrpc_internalencoding); + xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $GLOBALS['xmlrpc_internalencoding']); + + if ($return_type == 'phpvals') + { + xml_set_element_handler($parser, 'xmlrpc_se', 'xmlrpc_ee_fast'); + } + else + { + xml_set_element_handler($parser, 'xmlrpc_se', 'xmlrpc_ee'); + } - xml_set_element_handler($parser, 'xmlrpc_se', 'xmlrpc_ee'); xml_set_character_data_handler($parser, 'xmlrpc_cd'); xml_set_default_handler($parser, 'xmlrpc_dh'); - //$xmlrpc_value=new xmlrpcval; - if (!xml_parse($parser, $data, sizeof($data))) + // first error check: xml not well formed + if(!xml_parse($parser, $data, count($data))) { // thanks to Peter Kocks <peter.kocks@baygate.com> if((xml_get_current_line_number($parser)) == 1) @@ -1579,81 +2546,92 @@ } else { - $errstr = sprintf('XML error: %s at line %d', + $errstr = sprintf('XML error: %s at line %d, column %d', xml_error_string(xml_get_error_code($parser)), - xml_get_current_line_number($parser)); + xml_get_current_line_number($parser), xml_get_current_column_number($parser)); } error_log($errstr); - $r=new xmlrpcresp(0, $xmlrpcerr['invalid_return'], $xmlrpcstr['invalid_return'].' ('.$errstr.')'); + $r=&new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['invalid_return'], $GLOBALS['xmlrpcstr']['invalid_return'].' ('.$errstr.')'); xml_parser_free($parser); - if ($this->debug) - echo $errstr; - $r->hdrs = $_xh[$parser]['headers']; + if($this->debug) + { + print $errstr; + } + $r->hdrs = $GLOBALS['_xh']['headers']; + $r->_cookies = $GLOBALS['_xh']['cookies']; + $r->raw_data = $raw_data; return $r; } xml_parser_free($parser); - - if ($_xh[$parser]['isf'] > 1) + // second error check: xml well formed but not xml-rpc compliant + if ($GLOBALS['_xh']['isf'] > 1) { if ($this->debug) { - ///@todo echo something for user? + /// @todo echo something for user? } - $r = new xmlrpcresp(0, $xmlrpcerr['invalid_return'], - $xmlrpcstr['invalid_return'] . ' ' . $_xh[$parser]['isf_reason']); + $r =& new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['invalid_return'], + $GLOBALS['xmlrpcstr']['invalid_return'] . ' ' . $GLOBALS['_xh']['isf_reason']); } - //else if (strlen($_xh[$parser]['st'])==0) - else if (!is_object($_xh[$parser]['value'])) + // third error check: parsing of the response has somehow gone boink. + // NB: shall we omit this check, since we trust the parsing code? + elseif ($return_type == 'xmlrpcvals' && !is_object($GLOBALS['_xh']['value'])) { - // then something odd has happened + // something odd has happened // and it's time to generate a client side error // indicating something odd went on - $r=new xmlrpcresp(0, $xmlrpcerr['invalid_return'], - $xmlrpcstr['invalid_return']); + $r=&new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['invalid_return'], + $GLOBALS['xmlrpcstr']['invalid_return']); } else { - if ($this->debug) { - //print "<PRE>---EVALING---[" . - //strlen($_xh[$parser]['st']) . " chars]---\n" . - //htmlspecialchars($_xh[$parser]['st']) . ";\n---END---</PRE>"; - print "<PRE>---PARSED---\n" ; - var_dump($_xh[$parser]['value']); + print "<PRE>---PARSED---\n"; + // somehow htmlentities chokes on var_export, and some full html string... + //print htmlentitites(var_export($GLOBALS['_xh']['value'], true)); + print htmlspecialchars(var_export($GLOBALS['_xh']['value'], true)); print "\n---END---</PRE>"; } - //$allOK=0; - //@eval('$v=' . $_xh[$parser]['st'] . '; $allOK=1;'); - //if (!$allOK) - //{ - // $r = new xmlrpcresp(0, $xmlrpcerr['invalid_return'], $xmlrpcstr['invalid_return']); - //} - //else - $v = $_xh[$parser]['value']; - if ($_xh[$parser]['isf']) + // note that using =& will raise an error if $GLOBALS['_xh']['st'] does not generate an object. + $v =& $GLOBALS['_xh']['value']; + + if($GLOBALS['_xh']['isf']) { - $errno_v = $v->structmem('faultCode'); - $errstr_v = $v->structmem('faultString'); - $errno = $errno_v->scalarval(); + /// @todo we should test here if server sent an int and a string, + /// and/or coerce them into such... + if ($return_type == 'xmlrpcvals') + { + $errno_v = $v->structmem('faultCode'); + $errstr_v = $v->structmem('faultString'); + $errno = $errno_v->scalarval(); + $errstr = $errstr_v->scalarval(); + } + else + { + $errno = $v['faultCode']; + $errstr = $v['faultString']; + } - if ($errno == 0) + if($errno == 0) { // FAULT returned, errno needs to reflect that $errno = -1; } - $r = new xmlrpcresp($v, $errno, $errstr_v->scalarval()); + $r =& new xmlrpcresp(0, $errno, $errstr); } else { - $r=new xmlrpcresp($v); + $r=&new xmlrpcresp($v, 0, '', $return_type); } } - $r->hdrs = $_xh[$parser]['headers']; + $r->hdrs = $GLOBALS['_xh']['headers']; + $r->_cookies = $GLOBALS['_xh']['cookies']; + $r->raw_data = $raw_data; return $r; } } @@ -1662,120 +2640,200 @@ { var $me=array(); var $mytype=0; + var $_php_class=null; + /** + * @param mixed $val + * @param string $type any valid xmlrpc type name (lowercase). If null, 'string' is assumed + */ function xmlrpcval($val=-1, $type='') { - global $xmlrpcTypes; - $this->me=array(); - $this->mytype=0; - if ($val!=-1 || !is_int($val) || $type!='') + /// @todo: optimization creep - do not call addXX, do it all inline. + /// downside: booleans will not be coerced anymore + if($val!==-1 || $type!='') { - if ($type=='') + // optimization creep: inlined all work done by constructor + switch($type) + { + case '': + $this->mytype=1; + $this->me['string']=$val; + break; + case 'i4': + case 'int': + case 'double': + case 'string': + case 'boolean': + case 'dateTime.iso8601': + case 'base64': + case 'null': + $this->mytype=1; + $this->me[$type]=$val; + break; + case 'array': + $this->mytype=2; + $this->me['array']=$val; + break; + case 'struct': + $this->mytype=3; + $this->me['struct']=$val; + break; + default: + error_log("XML-RPC: xmlrpcval::xmlrpcval: not a known type ($type)"); + } + /*if($type=='') { $type='string'; } - if ($xmlrpcTypes[$type]==1) + if($GLOBALS['xmlrpcTypes'][$type]==1) { $this->addScalar($val,$type); } - elseif ($xmlrpcTypes[$type]==2) + elseif($GLOBALS['xmlrpcTypes'][$type]==2) { $this->addArray($val); } - elseif ($xmlrpcTypes[$type]==3) + elseif($GLOBALS['xmlrpcTypes'][$type]==3) { $this->addStruct($val); - } + }*/ } } + /** + * Add a single php value to an (unitialized) xmlrpcval + * @param mixed $val + * @param string $type + * @return int 1 or 0 on failure + */ function addScalar($val, $type='string') { - global $xmlrpcTypes, $xmlrpcBoolean; - - if ($this->mytype==1) + $typeof=@$GLOBALS['xmlrpcTypes'][$type]; + if($typeof!=1) { - echo '<B>xmlrpcval</B>: scalar can have only one value<BR>'; - return 0; - } - $typeof=$xmlrpcTypes[$type]; - if ($typeof!=1) - { - echo '<B>xmlrpcval</B>: not a scalar type (${typeof})<BR>'; + error_log("XML-RPC: xmlrpcval::addScalar: not a scalar type ($type)"); return 0; } - if ($type==$xmlrpcBoolean) + // coerce booleans into correct values + // NB: we should iether do it for datetimes, integers and doubles, too, + // or just plain remove this check, implemnted on booleans only... + if($type==$GLOBALS['xmlrpcBoolean']) { - if (strcasecmp($val,'true')==0 || $val==1 || ($val==true && strcasecmp($val,'false'))) + if(strcasecmp($val,'true')==0 || $val==1 || ($val==true && strcasecmp($val,'false'))) { - $val=1; + $val=true; } else { - $val=0; + $val=false; } } - if ($this->mytype==2) - { - // we're adding to an array here - $ar=$this->me['array']; - $ar[]=new xmlrpcval($val, $type); - $this->me['array']=$ar; - } - else + switch($this->mytype) { - // a scalar, so set the value and remember we're scalar - $this->me[$type]=$val; - $this->mytype=$typeof; + case 1: + error_log('XML-RPC: xmlrpcval::addScalar: scalar xmlrpcval can have only one value'); + return 0; + case 3: + error_log('XML-RPC: xmlrpcval::addScalar: cannot add anonymous scalar to struct xmlrpcval'); + return 0; + case 2: + // we're adding a scalar value to an array here + //$ar=$this->me['array']; + //$ar[]=&new xmlrpcval($val, $type); + //$this->me['array']=$ar; + // Faster (?) avoid all the costly array-copy-by-val done here... + $this->me['array'][]=&new xmlrpcval($val, $type); + return 1; + default: + // a scalar, so set the value and remember we're scalar + $this->me[$type]=$val; + $this->mytype=$typeof; + return 1; } - return 1; } + /** + * Add an array of xmlrpcval objects to an xmlrpcval + * @param array $vals + * @return int 1 or 0 on failure + * @access public + * + * @todo add some checking for $vals to be an array of xmlrpcvals? + */ function addArray($vals) { - global $xmlrpcTypes; - if ($this->mytype!=0) + if($this->mytype==0) + { + $this->mytype=$GLOBALS['xmlrpcTypes']['array']; + $this->me['array']=$vals; + return 1; + } + elseif($this->mytype==2) + { + // we're adding to an array here + $this->me['array'] = array_merge($this->me['array'], $vals); + return 1; + } + else { - echo '<B>xmlrpcval</B>: already initialized as a [' . $this->kindOf() . ']<BR>'; + error_log('XML-RPC: xmlrpcval::addArray: already initialized as a [' . $this->kindOf() . ']'); return 0; } - - $this->mytype=$xmlrpcTypes['array']; - $this->me['array']=$vals; - return 1; } + /** + * Add an array of named xmlrpcval objects to an xmlrpcval + * @param array $vals + * @return int 1 or 0 on failure + * @access public + * + * @todo add some checking for $vals to be an array? + */ function addStruct($vals) { - global $xmlrpcTypes; - if ($this->mytype!=0) + if($this->mytype==0) { - echo '<B>xmlrpcval</B>: already initialized as a [' . $this->kindOf() . ']<BR>'; + $this->mytype=$GLOBALS['xmlrpcTypes']['struct']; + $this->me['struct']=$vals; + return 1; + } + elseif($this->mytype==3) + { + // we're adding to a struct here + $this->me['struct'] = array_merge($this->me['struct'], $vals); + return 1; + } + else + { + error_log('XML-RPC: xmlrpcval::addStruct: already initialized as a [' . $this->kindOf() . ']'); return 0; } - $this->mytype=$xmlrpcTypes['struct']; - $this->me['struct']=$vals; - return 1; } + // poor man's version of print_r ??? + // DEPRECATED! function dump($ar) { - reset($ar); - while ( list( $key, $val ) = each( $ar ) ) + foreach($ar as $key => $val) { - echo "$key => $val<br>"; - if ($key == 'array') + echo "$key => $val<br />"; + if($key == 'array') { - while ( list( $key2, $val2 ) = each( $val ) ) + while(list($key2, $val2) = each($val)) { - echo "-- $key2 => $val2<br>"; + echo "-- $key2 => $val2<br />"; } } } } + /** + * Returns a string containing "struct", "array" or "scalar" describing the base type of the value + * @return string + * @access public + */ function kindOf() { switch($this->mytype) @@ -1794,21 +2852,59 @@ } } - function serializedata($typ, $val) + /** + * @access private + */ + function serializedata($typ, $val, $charset_encoding='') { $rs=''; - global $xmlrpcTypes, $xmlrpcBase64, $xmlrpcString, - $xmlrpcBoolean; - switch(@$xmlrpcTypes[$typ]) + switch(@$GLOBALS['xmlrpcTypes'][$typ]) { + case 1: + switch($typ) + { + case $GLOBALS['xmlrpcBase64']: + $rs.="<${typ}>" . base64_encode($val) . "</${typ}>"; + break; + case $GLOBALS['xmlrpcBoolean']: + $rs.="<${typ}>" . ($val ? '1' : '0') . "</${typ}>"; + break; + case $GLOBALS['xmlrpcString']: + // G. Giunta 2005/2/13: do NOT use htmlentities, since + // it will produce named html entities, which are invalid xml + $rs.="<${typ}>" . xmlrpc_encode_entitites($val, $GLOBALS['xmlrpc_internalencoding'], $charset_encoding). "</${typ}>"; + break; + case $GLOBALS['xmlrpcInt']: + case $GLOBALS['xmlrpcI4']: + $rs.="<${typ}>".(int)$val."</${typ}>"; + break; + case $GLOBALS['xmlrpcDouble']: + $rs.="<${typ}>".(double)$val."</${typ}>"; + break; + case $GLOBALS['xmlrpcNull']: + $rs.="<nil/>"; + break; + default: + // no standard type value should arrive here, but provide a possibility + // for xmlrpcvals of unknown type... + $rs.="<${typ}>${val}</${typ}>"; + } + break; case 3: // struct - $rs.="<struct>\n"; - reset($val); - while(list($key2, $val2)=each($val)) + if ($this->_php_class) + { + $rs.='<struct php_class="' . $this->_php_class . "\">\n"; + } + else + { + $rs.="<struct>\n"; + } + foreach($val as $key2 => $val2) { - $rs.="<member><name>${key2}</name>\n"; - $rs.=$this->serializeval($val2); + $rs.='<member><name>'.xmlrpc_encode_entitites($key2, $GLOBALS['xmlrpc_internalencoding'], $charset_encoding)."</name>\n"; + //$rs.=$this->serializeval($val2); + $rs.=$val2->serialize($charset_encoding); $rs.="</member>\n"; } $rs.='</struct>'; @@ -1816,75 +2912,97 @@ case 2: // array $rs.="<array>\n<data>\n"; - for($i=0; $i<sizeof($val); $i++) + for($i=0; $i<count($val); $i++) { - $rs.=$this->serializeval($val[$i]); + //$rs.=$this->serializeval($val[$i]); + $rs.=$val[$i]->serialize($charset_encoding); } $rs.="</data>\n</array>"; break; - case 1: - switch ($typ) - { - case $xmlrpcBase64: - $rs.="<${typ}>" . base64_encode($val) . "</${typ}>"; - break; - case $xmlrpcBoolean: - $rs.="<${typ}>" . ($val ? '1' : '0') . "</${typ}>"; - break; - case $xmlrpcString: - // G. Giunta 2005/2/13: do NOT use htmlentities, since - // it will produce named html entities, which are invalid xml - $rs.="<${typ}>" . xmlrpc_encode_entitites($val). "</${typ}>"; - // $rs.="<${typ}>" . htmlentities($val). "</${typ}>"; - break; - default: - $rs.="<${typ}>${val}</${typ}>"; - } - break; default: break; } return $rs; } - function serialize() - { - return $this->serializeval($this); + /** + * Returns xml representation of the value. XML prologue not included + * @param string $charset_encoding the charset to be used for serialization. if null, US-ASCII is assumed + * @return string + * @access public + */ + function serialize($charset_encoding='') + { + // add check? slower, but helps to avoid recursion in serializing broken xmlrpcvals... + //if (is_object($o) && (get_class($o) == 'xmlrpcval' || is_subclass_of($o, 'xmlrpcval'))) + //{ + reset($this->me); + list($typ, $val) = each($this->me); + return '<value>' . $this->serializedata($typ, $val, $charset_encoding) . "</value>\n"; + //} } + // DEPRECATED function serializeval($o) { - //global $xmlrpcTypes; - $rs=''; - $ar=$o->me; - reset($ar); - list($typ, $val) = each($ar); - $rs.='<value>'; - $rs.=$this->serializedata($typ, $val); - $rs.="</value>\n"; - return $rs; + // add check? slower, but helps to avoid recursion in serializing broken xmlrpcvals... + //if (is_object($o) && (get_class($o) == 'xmlrpcval' || is_subclass_of($o, 'xmlrpcval'))) + //{ + $ar=$o->me; + reset($ar); + list($typ, $val) = each($ar); + return '<value>' . $this->serializedata($typ, $val) . "</value>\n"; + //} } + /** + * Checks wheter a struct member with a given name is present. + * Works only on xmlrpcvals of type struct. + * @param string $m the name of the struct member to be looked up + * @return boolean + * @access public + */ + function structmemexists($m) + { + return array_key_exists($m, $this->me['struct']); + } + + /** + * Returns the value of a given struct member (an xmlrpcval object in itself). + * Will raise a php warning if struct member of given name does not exist + * @param string $m the name of the struct member to be looked up + * @return xmlrpcval + * @access public + */ function structmem($m) { - $nv=$this->me['struct'][$m]; - return $nv; + return $this->me['struct'][$m]; } + /** + * Reset internal pointer for xmlrpcvals of type struct. + * @access public + */ function structreset() { reset($this->me['struct']); } + /** + * Return next member element for xmlrpcvals of type struct. + * @return xmlrpcval + * @access public + */ function structeach() { return each($this->me['struct']); } + // DEPRECATED! this code looks like it is very fragile and has not been fixed + // for a long long time. Shall we remove it for 2.0? function getval() { // UNSTABLE - global $xmlrpcBoolean, $xmlrpcBase64; reset($this->me); list($a,$b)=each($this->me); // contributed by I Sofer, 2001-03-24 @@ -1892,7 +3010,7 @@ // i've created a new method here, so as to // preserve back compatibility - if (is_array($b)) + if(is_array($b)) { @reset($b); while(list($id,$cont) = @each($b)) @@ -1902,7 +3020,7 @@ } // add support for structures directly encoding php objects - if (is_object($b)) + if(is_object($b)) { $t = get_object_vars($b); @reset($t); @@ -1913,7 +3031,6 @@ @reset($t); while(list($id,$cont) = @each($t)) { - //eval('$b->'.$id.' = $cont;'); @$b->$id = $cont; } } @@ -1921,60 +3038,96 @@ return $b; } + /** + * Returns the value of a scalar xmlrpcval + * @return mixed + * @access public + */ function scalarval() { - //global $xmlrpcBoolean, $xmlrpcBase64; reset($this->me); - list($a,$b)=each($this->me); + list(,$b)=each($this->me); return $b; } + /** + * Returns the type of the xmlrpcval. + * For integers, 'int' is always returned in place of 'i4' + * @return string + * @access public + */ function scalartyp() { - global $xmlrpcI4, $xmlrpcInt; reset($this->me); - list($a,$b)=each($this->me); - if ($a==$xmlrpcI4) + list($a,)=each($this->me); + if($a==$GLOBALS['xmlrpcI4']) { - $a=$xmlrpcInt; + $a=$GLOBALS['xmlrpcInt']; } return $a; } + /** + * Returns the m-th member of an xmlrpcval of struct type + * @param integer $m the index of the value to be retrieved (zero based) + * @return xmlrpcval + * @access public + */ function arraymem($m) { - $nv=$this->me['array'][$m]; - return $nv; + return $this->me['array'][$m]; } + /** + * Returns the number of members in an xmlrpcval of array type + * @return integer + * @access public + */ function arraysize() { - reset($this->me); - list($a,$b)=each($this->me); - return sizeof($b); + return count($this->me['array']); + } + + /** + * Returns the number of members in an xmlrpcval of struct type + * @return integer + * @access public + */ + function structsize() + { + return count($this->me['struct']); } } + // date helpers + + /** + * Given a timestamp, return the corresponding ISO8601 encoded string. + * + * Really, timezones ought to be supported + * but the XML-RPC spec says: + * + * "Don't assume a timezone. It should be specified by the server in its + * documentation what assumptions it makes about timezones." + * + * These routines always assume localtime unless + * $utc is set to 1, in which case UTC is assumed + * and an adjustment for locale is made when encoding + * + * @param int $timet (timestamp) + * @param int $utc (0 or 1) + * @return string + */ function iso8601_encode($timet, $utc=0) { - // return an ISO8601 encoded string - // really, timezones ought to be supported - // but the XML-RPC spec says: - // - // "Don't assume a timezone. It should be specified by the server in its - // documentation what assumptions it makes about timezones." - // - // these routines always assume localtime unless - // $utc is set to 1, in which case UTC is assumed - // and an adjustment for locale is made when encoding - if (!$utc) + if(!$utc) { $t=strftime("%Y%m%dT%H:%M:%S", $timet); } else { - if (function_exists('gmstrftime')) + if(function_exists('gmstrftime')) { // gmstrftime doesn't exist in some versions // of PHP @@ -1988,13 +3141,18 @@ return $t; } + /** + * Given an ISO8601 date string, return a timet in the localtime, or UTC + * @param string $idate + * @param int $utc either 0 or 1 + * @return int (datetime) + */ function iso8601_decode($idate, $utc=0) { - // return a timet in the localtime, or UTC $t=0; - if (ereg("([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})", $idate, $regs)) + if(preg_match('/([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})/', $idate, $regs)) { - if ($utc) + if($utc) { $t=gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); } @@ -2002,199 +3160,481 @@ { $t=mktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); } - } - return $t; - } - - /**************************************************************** - * xmlrpc_decode takes a message in PHP xmlrpc object format and * - * tranlates it into native PHP types. * - * * - * author: Dan Libby (dan@libby.com) * - ****************************************************************/ - function php_xmlrpc_decode($xmlrpc_val) - { - $kind = $xmlrpc_val->kindOf(); - - if($kind == 'scalar') - { - return $xmlrpc_val->scalarval(); - } - elseif($kind == 'array') - { - $size = $xmlrpc_val->arraysize(); - $arr = array(); - - for($i = 0; $i < $size; $i++) - { - $arr[] = php_xmlrpc_decode($xmlrpc_val->arraymem($i)); - } - return $arr; - } - elseif($kind == 'struct') - { - $xmlrpc_val->structreset(); - $arr = array(); - - while(list($key,$value)=$xmlrpc_val->structeach()) - { - $arr[$key] = php_xmlrpc_decode($value); - } - return $arr; } + return $t; } - if(function_exists('xmlrpc_decode')) - { - define('XMLRPC_EPI_ENABLED','1'); - } - else + /** + * Takes an xmlrpc value in PHP xmlrpcval object format and translates it into native PHP types. + * + * Works with xmlrpc message objects as input, too. + * + * Given proper options parameter, can rebuild generic php object instances + * (provided those have been encoded to xmlrpc format using a corresponding + * option in php_xmlrpc_encode()) + * PLEASE NOTE that rebuilding php objects involves calling their constructor function. + * This means that the remote communication end can decide which php code will + * get executed on your server, leaving the door possibly open to 'php-injection' + * style of attacks (provided you have some classes defined on your server that + * might wreak havoc if instances are built outside an appropriate context). + * Make sure you trust the remote server/client before eanbling this! + * + * @author Dan Libby (dan@libby.com) + * + * @param xmlrpcval $xmlrpc_val + * @param array $options if 'decode_php_objs' is set in the options array, xmlrpc structs can be decoded into php objects + * @return mixed + */ + function php_xmlrpc_decode($xmlrpc_val, $options=array()) { - define('XMLRPC_EPI_ENABLED','0'); - function xmlrpc_decode($xmlrpc_val) + switch($xmlrpc_val->kindOf()) { - $kind = $xmlrpc_val->kindOf(); - - if($kind == 'scalar') - { + case 'scalar': + if (in_array('extension_api', $options)) + { + reset($xmlrpc_val->me); + list($typ,$val) = each($xmlrpc_val->me); + switch ($typ) + { + case 'dateTime.iso8601': + $xmlrpc_val->scalar = $val; + $xmlrpc_val->xmlrpc_type = 'datetime'; + $xmlrpc_val->timestamp = iso8601_decode($val); + return $xmlrpc_val; + case 'base64': + $xmlrpc_val->scalar = $val; + $xmlrpc_val->type = $typ; + return $xmlrpc_val; + default: + return $xmlrpc_val->scalarval(); + } + } return $xmlrpc_val->scalarval(); - } - elseif($kind == 'array') - { + case 'array': $size = $xmlrpc_val->arraysize(); $arr = array(); - for($i = 0; $i < $size; $i++) { - $arr[]=xmlrpc_decode($xmlrpc_val->arraymem($i)); + $arr[] = php_xmlrpc_decode($xmlrpc_val->arraymem($i), $options); } return $arr; - } - elseif($kind == 'struct') - { + case 'struct': $xmlrpc_val->structreset(); + // If user said so, try to rebuild php objects for specific struct vals. + /// @todo should we raise a warning for class not found? + // shall we check for proper subclass of xmlrpcval instead of + // presence of _php_class to detect what we can do? + if (in_array('decode_php_objs', $options) && $xmlrpc_val->_php_class != '' + && class_exists($xmlrpc_val->_php_class)) + { + $obj = @new $xmlrpc_val->_php_class; + while(list($key,$value)=$xmlrpc_val->structeach()) + { + $obj->$key = php_xmlrpc_decode($value, $options); + } + return $obj; + } + else + { + $arr = array(); + while(list($key,$value)=$xmlrpc_val->structeach()) + { + $arr[$key] = php_xmlrpc_decode($value, $options); + } + return $arr; + } + case 'msg': + $paramcount = $xmlrpc_val->getNumParams(); $arr = array(); - - while(list($key,$value)=$xmlrpc_val->structeach()) + for($i = 0; $i < $paramcount; $i++) { - $arr[$key] = xmlrpc_decode($value); + $arr[] = php_xmlrpc_decode($xmlrpc_val->getParam($i)); } return $arr; } - } } - /**************************************************************** - * xmlrpc_encode takes native php types and encodes them into * - * xmlrpc PHP object format. * - * BUG: All sequential arrays are turned into structs. I don't * - * know of a good way to determine if an array is sequential * - * only. * - * * - * feature creep -- could support more types via optional type * - * argument. * - * * - * author: Dan Libby (dan@libby.com) * - ****************************************************************/ - function php_xmlrpc_encode($php_val) + // This constant left here only for historical reasons... + // it was used to decide if we have to define xmlrpc_encode on our own, but + // we do not do it anymore + if(function_exists('xmlrpc_decode')) + { + define('XMLRPC_EPI_ENABLED','1'); + } + else { - global $xmlrpcInt; - global $xmlrpcDouble; - global $xmlrpcString; - global $xmlrpcArray; - global $xmlrpcStruct; - global $xmlrpcBoolean; + define('XMLRPC_EPI_ENABLED','0'); + } + /** + * Takes native php types and encodes them into xmlrpc PHP object format. + * It will not re-encode xmlrpcval objects. + * + * Feature creep -- could support more types via optional type argument + * (string => datetime support has been added, ??? => base64 not yet) + * + * If given a proper options parameter, php object instances will be encoded + * into 'special' xmlrpc values, that can later be decoded into php objects + * by calling php_xmlrpc_decode() with a corresponding option + * + * @author Dan Libby (dan@libby.com) + * + * @param mixed $php_val the value to be converted into an xmlrpcval object + * @param array $options can include 'encode_php_objs', 'auto_dates', 'null_extension' or 'extension_api' + * @return xmlrpcval + */ + function &php_xmlrpc_encode($php_val, $options=array()) + { $type = gettype($php_val); - $xmlrpc_val = new xmlrpcval; - switch($type) { - case 'array': - case 'object': - $arr = array(); - while (list($k,$v) = each($php_val)) - { - $arr[$k] = php_xmlrpc_encode($v); - } - $xmlrpc_val->addStruct($arr); + case 'string': + if (in_array('auto_dates', $options) && preg_match('/^[0-9]{8}T[0-9]{2}:[0-9]{2}:[0-9]{2}$/', $php_val)) + $xmlrpc_val =& new xmlrpcval($php_val, $GLOBALS['xmlrpcDateTime']); + else + $xmlrpc_val =& new xmlrpcval($php_val, $GLOBALS['xmlrpcString']); break; case 'integer': - $xmlrpc_val->addScalar($php_val, $xmlrpcInt); + $xmlrpc_val =& new xmlrpcval($php_val, $GLOBALS['xmlrpcInt']); break; case 'double': - $xmlrpc_val->addScalar($php_val, $xmlrpcDouble); - break; - case 'string': - $xmlrpc_val->addScalar($php_val, $xmlrpcString); + $xmlrpc_val =& new xmlrpcval($php_val, $GLOBALS['xmlrpcDouble']); break; // <G_Giunta_2001-02-29> // Add support for encoding/decoding of booleans, since they are supported in PHP case 'boolean': - $xmlrpc_val->addScalar($php_val, $xmlrpcBoolean); + $xmlrpc_val =& new xmlrpcval($php_val, $GLOBALS['xmlrpcBoolean']); break; // </G_Giunta_2001-02-29> - // catch "resource", "NULL", "user function", "unknown type" - //case 'unknown type': + case 'array': + // PHP arrays can be encoded to either xmlrpc structs or arrays, + // depending on wheter they are hashes or plain 0..n integer indexed + // A shorter one-liner would be + // $tmp = array_diff(array_keys($php_val), range(0, count($php_val)-1)); + // but execution time skyrockets! + $j = 0; + $arr = array(); + $ko = false; + foreach($php_val as $key => $val) + { + $arr[$key] =& php_xmlrpc_encode($val, $options); + if(!$ko && $key !== $j) + { + $ko = true; + } + $j++; + } + if($ko) + { + $xmlrpc_val =& new xmlrpcval($arr, $GLOBALS['xmlrpcStruct']); + } + else + { + $xmlrpc_val =& new xmlrpcval($arr, $GLOBALS['xmlrpcArray']); + } + break; + case 'object': + if(is_a($php_val, 'xmlrpcval')) + { + $xmlrpc_val = $php_val; + } + else + { + $arr = array(); + while(list($k,$v) = each($php_val)) + { + $arr[$k] = php_xmlrpc_encode($v, $options); + } + $xmlrpc_val =& new xmlrpcval($arr, $GLOBALS['xmlrpcStruct']); + if (in_array('encode_php_objs', $options)) + { + // let's save original class name into xmlrpcval: + // might be useful later on... + $xmlrpc_val->_php_class = get_class($php_val); + } + } + break; + case 'NULL': + if (in_array('extension_api', $options)) + { + $xmlrpc_val =& new xmlrpcval('', $GLOBALS['xmlrpcString']); + } + if (in_array('null_extension', $options)) + { + $xmlrpc_val =& new xmlrpcval('', $GLOBALS['xmlrpcNull']); + } + else + { + $xmlrpc_val =& new xmlrpcval(); + } + break; + case 'resource': + if (in_array('extension_api', $options)) + { + $xmlrpc_val =& new xmlrpcval((int)$php_val, $GLOBALS['xmlrpcInt']); + } + else + { + $xmlrpc_val =& new xmlrpcval(); + } + // catch "user function", "unknown type" default: // giancarlo pinerolo <ping@alt.it> - // it has to return - // an empty object in case (which is already - // at this point), not a boolean. + // it has to return + // an empty object in case, not a boolean. + $xmlrpc_val =& new xmlrpcval(); break; } return $xmlrpc_val; } - if(XMLRPC_EPI_ENABLED == '0') + /** + * Convert the xml representation of a method response, method request or single + * xmlrpc value into the appropriate object (a.k.a. deserialize) + * @param string $xml_val + * @param array $options + * @return mixed false on error, or an instance of either xmlrpcval, xmlrpcmsg or xmlrpcresp + */ + function php_xmlrpc_decode_xml($xml_val, $options=array()) + { + $GLOBALS['_xh'] = array(); + $GLOBALS['_xh']['ac'] = ''; + $GLOBALS['_xh']['stack'] = array(); + $GLOBALS['_xh']['valuestack'] = array(); + $GLOBALS['_xh']['params'] = array(); + $GLOBALS['_xh']['pt'] = array(); + $GLOBALS['_xh']['isf'] = 0; + $GLOBALS['_xh']['isf_reason'] = ''; + $GLOBALS['_xh']['method'] = false; + $GLOBALS['_xh']['rt'] = ''; + /// @todo 'guestimate' encoding + $parser = xml_parser_create(); + xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true); + xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $GLOBALS['xmlrpc_internalencoding']); + xml_set_element_handler($parser, 'xmlrpc_se_any', 'xmlrpc_ee'); + xml_set_character_data_handler($parser, 'xmlrpc_cd'); + xml_set_default_handler($parser, 'xmlrpc_dh'); + if(!xml_parse($parser, $xml_val, 1)) + { + $errstr = sprintf('XML error: %s at line %d, column %d', + xml_error_string(xml_get_error_code($parser)), + xml_get_current_line_number($parser), xml_get_current_column_number($parser)); + error_log($errstr); + xml_parser_free($parser); + return false; + } + xml_parser_free($parser); + if ($GLOBALS['_xh']['isf'] > 1) // test that $GLOBALS['_xh']['value'] is an obj, too??? + { + error_log($GLOBALS['_xh']['isf_reason']); + return false; + } + switch ($GLOBALS['_xh']['rt']) + { + case 'methodresponse': + $v =& $GLOBALS['_xh']['value']; + if ($GLOBALS['_xh']['isf'] == 1) + { + $vc = $v->structmem('faultCode'); + $vs = $v->structmem('faultString'); + $r =& new xmlrpcresp(0, $vc->scalarval(), $vs->scalarval()); + } + else + { + $r =& new xmlrpcresp($v); + } + return $r; + case 'methodcall': + $m =& new xmlrpcmsg($GLOBALS['_xh']['method']); + for($i=0; $i < count($GLOBALS['_xh']['params']); $i++) + { + $m->addParam($GLOBALS['_xh']['params'][$i]); + } + return $m; + case 'value': + return $GLOBALS['_xh']['value']; + default: + return false; + } + } + + /** + * decode a string that is encoded w/ "chunked" transfer encoding + * as defined in rfc2068 par. 19.4.6 + * code shamelessly stolen from nusoap library by Dietrich Ayala + * + * @param string $buffer the string to be decoded + * @return string + */ + function decode_chunked($buffer) + { + // length := 0 + $length = 0; + $new = ''; + + // read chunk-size, chunk-extension (if any) and crlf + // get the position of the linebreak + $chunkend = strpos($buffer,"\r\n") + 2; + $temp = substr($buffer,0,$chunkend); + $chunk_size = hexdec( trim($temp) ); + $chunkstart = $chunkend; + while($chunk_size > 0) + { + $chunkend = strpos($buffer, "\r\n", $chunkstart + $chunk_size); + + // just in case we got a broken connection + if($chunkend == false) + { + $chunk = substr($buffer,$chunkstart); + // append chunk-data to entity-body + $new .= $chunk; + $length += strlen($chunk); + break; + } + + // read chunk-data and crlf + $chunk = substr($buffer,$chunkstart,$chunkend-$chunkstart); + // append chunk-data to entity-body + $new .= $chunk; + // length := length + chunk-size + $length += strlen($chunk); + // read chunk-size and crlf + $chunkstart = $chunkend + 2; + + $chunkend = strpos($buffer,"\r\n",$chunkstart)+2; + if($chunkend == false) + { + break; //just in case we got a broken connection + } + $temp = substr($buffer,$chunkstart,$chunkend-$chunkstart); + $chunk_size = hexdec( trim($temp) ); + $chunkstart = $chunkend; + } + return $new; + } + + /** + * xml charset encoding guessing helper function. + * Tries to determine the charset encoding of an XML chunk + * received over HTTP. + * NB: according to the spec (RFC 3023, if text/xml content-type is received over HTTP without a content-type, + * we SHOULD assume it is strictly US-ASCII. But we try to be more tolerant of unconforming (legacy?) clients/servers, + * which will be most probably using UTF-8 anyway... + * + * @param string $httpheaders the http Content-type header + * @param string $xmlchunk xml content buffer + * @param string $encoding_prefs comma separated list of character encodings to be used as default (when mb extension is enabled) + * + * @todo explore usage of mb_http_input(): does it detect http headers + post data? if so, use it instead of hand-detection!!! + */ + function guess_encoding($httpheader='', $xmlchunk='', $encoding_prefs=null) { - function xmlrpc_encode($php_val) + // discussion: see http://www.yale.edu/pclt/encoding/ + // 1 - test if encoding is specified in HTTP HEADERS + + //Details: + // LWS: (\13\10)?( |\t)+ + // token: (any char but excluded stuff)+ + // header: Content-type = ...; charset=value(; ...)* + // where value is of type token, no LWS allowed between 'charset' and value + // Note: we do not check for invalid chars in VALUE: + // this had better be done using pure ereg as below + + /// @todo this test will pass if ANY header has charset specification, not only Content-Type. Fix it? + $matches = array(); + if(preg_match('/;\s*charset=([^;]+)/i', $httpheader, $matches)) + { + return strtoupper(trim($matches[1])); + } + + // 2 - scan the first bytes of the data for a UTF-16 (or other) BOM pattern + // (source: http://www.w3.org/TR/2000/REC-xml-20001006) + // NOTE: actually, according to the spec, even if we find the BOM and determine + // an encoding, we should check if there is an encoding specified + // in the xml declaration, and verify if they match. + /// @todo implement check as described above? + /// @todo implement check for first bytes of string even without a BOM? (It sure looks harder than for cases WITH a BOM) + if(preg_match('/^(\x00\x00\xFE\xFF|\xFF\xFE\x00\x00|\x00\x00\xFF\xFE|\xFE\xFF\x00\x00)/', $xmlchunk)) { - global $xmlrpcInt; - global $xmlrpcDouble; - global $xmlrpcString; - global $xmlrpcArray; - global $xmlrpcStruct; - global $xmlrpcBoolean; + return 'UCS-4'; + } + elseif(preg_match('/^(\xFE\xFF|\xFF\xFE)/', $xmlchunk)) + { + return 'UTF-16'; + } + elseif(preg_match('/^(\xEF\xBB\xBF)/', $xmlchunk)) + { + return 'UTF-8'; + } - $type = gettype($php_val); - $xmlrpc_val = new xmlrpcval; + // 3 - test if encoding is specified in the xml declaration + // Details: + // SPACE: (#x20 | #x9 | #xD | #xA)+ === [ \x9\xD\xA]+ + // EQ: SPACE?=SPACE? === [ \x9\xD\xA]*=[ \x9\xD\xA]* + if (preg_match('/^<\?xml\s+version\s*=\s*'. "((?:\"[a-zA-Z0-9_.:-]+\")|(?:'[a-zA-Z0-9_.:-]+'))". + '\s+encoding\s*=\s*' . "((?:\"[A-Za-z][A-Za-z0-9._-]*\")|(?:'[A-Za-z][A-Za-z0-9._-]*'))/", + $xmlchunk, $matches)) + { + return strtoupper(substr($matches[2], 1, -1)); + } - switch($type) + // 4 - if mbstring is available, let it do the guesswork + // NB: we favour finding an encoding that is compatible with what we can process + if(extension_loaded('mbstring')) + { + if($encoding_prefs) { - case 'array': - case 'object': - $arr = array(); - while (list($k,$v) = each($php_val)) - { - $arr[$k] = xmlrpc_encode($v); - } - $xmlrpc_val->addStruct($arr); - break; - case 'integer': - $xmlrpc_val->addScalar($php_val, $xmlrpcInt); - break; - case 'double': - $xmlrpc_val->addScalar($php_val, $xmlrpcDouble); - break; - case 'string': - $xmlrpc_val->addScalar($php_val, $xmlrpcString); - break; - // <G_Giunta_2001-02-29> - // Add support for encoding/decoding of booleans, since they are supported in PHP - case 'boolean': - $xmlrpc_val->addScalar($php_val, $xmlrpcBoolean); - break; - // </G_Giunta_2001-02-29> - //case 'unknown type': - default: - // giancarlo pinerolo <ping@alt.it> - // it has to return - // an empty object in case (which is already - // at this point), not a boolean. - break; + $enc = mb_detect_encoding($xmlchunk, $encoding_prefs); } - return $xmlrpc_val; + else + { + $enc = mb_detect_encoding($xmlchunk); + } + // NB: mb_detect likes to call it ascii, xml parser likes to call it US_ASCII... + // IANA also likes better US-ASCII, so go with it + if($enc == 'ASCII') + { + $enc = 'US-'.$enc; + } + return $enc; + } + else + { + // no encoding specified: as per HTTP1.1 assume it is iso-8859-1? + // Both RFC 2616 (HTTP 1.1) and 1945(http 1.0) clearly state that for text/xxx content types + // this should be the standard. And we should be getting text/xml as request and response. + // BUT we have to be backward compatible with the lib, which always used UTF-8 as default... + return $GLOBALS['xmlrpc_defencoding']; + } + } + + /** + * Checks if a given charset encoding is present in a list of encodings or + * if it is a valid subset of any encoding in the list + * @param string $encoding charset to be tested + * @param mixed $validlist comma separated list of valid charsets (or array of charsets) + */ + function is_valid_charset($encoding, $validlist) + { + $charset_supersets = array( + 'US-ASCII' => array ('ISO-8859-1', 'ISO-8859-2', 'ISO-8859-3', 'ISO-8859-4', + 'ISO-8859-5', 'ISO-8859-6', 'ISO-8859-7', 'ISO-8859-8', + 'ISO-8859-9', 'ISO-8859-10', 'ISO-8859-11', 'ISO-8859-12', + 'ISO-8859-13', 'ISO-8859-14', 'ISO-8859-15', 'UTF-8', + 'EUC-JP', 'EUC-', 'EUC-KR', 'EUC-CN') + ); + if (is_string($validlist)) + $validlist = explode(',', $validlist); + if (@in_array(strtoupper($encoding), $validlist)) + return true; + else + { + if (array_key_exists($encoding, $charset_supersets)) + foreach ($validlist as $allowed) + if (in_array($allowed, $charset_supersets[$encoding])) + return true; + return false; } } -?> + +?>
\ No newline at end of file diff --git a/modules/xmlrpc/xmlrpcs.inc b/modules/xmlrpc/xmlrpcs.inc index 080fcd3e..661a1b4b 100755 --- a/modules/xmlrpc/xmlrpcs.inc +++ b/modules/xmlrpc/xmlrpcs.inc @@ -1,7 +1,7 @@ <?php // by Edd Dumbill (C) 1999-2002 // <edd@usefulinc.com> -// $Id: xmlrpcs.inc,v 1.17 2005/04/24 18:16:21 ggiunta Exp $ +// $Id: xmlrpcs.inc,v 1.66 2006/09/17 21:25:06 ggiunta Exp $ // Copyright (c) 1999,2000,2002 Edd Dumbill. // All rights reserved. @@ -38,173 +38,272 @@ // XML RPC Server class // requires: xmlrpc.inc - // listMethods: either a string, or nothing - $_xmlrpcs_listMethods_sig=array(array($xmlrpcArray, $xmlrpcString), array($xmlrpcArray)); + $GLOBALS['xmlrpcs_capabilities'] = array( + // xmlrpc spec: always supported + 'xmlrpc' => new xmlrpcval(array( + 'specUrl' => new xmlrpcval('http://www.xmlrpc.com/spec', 'string'), + 'specVersion' => new xmlrpcval(1, 'int') + ), 'struct'), + // if we support system.xxx functions, we always support multicall, too... + // Note that, as of 2006/09/17, the following URL does not respond anymore + 'system.multicall' => new xmlrpcval(array( + 'specUrl' => new xmlrpcval('http://www.xmlrpc.com/discuss/msgReader$1208', 'string'), + 'specVersion' => new xmlrpcval(1, 'int') + ), 'struct'), + // introspection: version 2! we support 'mixed', too + 'introspection' => new xmlrpcval(array( + 'specUrl' => new xmlrpcval('http://phpxmlrpc.sourceforge.net/doc-2/ch10.html', 'string'), + 'specVersion' => new xmlrpcval(2, 'int') + ), 'struct') + ); + + /* Functions that implement system.XXX methods of xmlrpc servers */ + $_xmlrpcs_getCapabilities_sig=array(array($GLOBALS['xmlrpcStruct'])); + $_xmlrpcs_getCapabilities_doc='This method lists all the capabilites that the XML-RPC server has: the (more or less standard) extensions to the xmlrpc spec that it adheres to'; + $_xmlrpcs_getCapabilities_sdoc=array(array('list of capabilities, described as structs with a version number and url for the spec')); + function _xmlrpcs_getCapabilities($server, $m=null) + { + $outAr = $GLOBALS['xmlrpcs_capabilities']; + // NIL extension + if ($GLOBALS['xmlrpc_null_extension']) { + $outAr['nil'] = new xmlrpcval(array( + 'specUrl' => new xmlrpcval('http://www.ontosys.com/xml-rpc/extensions.php', 'string'), + 'specVersion' => new xmlrpcval(1, 'int') + ), 'struct'); + } + return new xmlrpcresp(new xmlrpcval($outAr, 'struct')); + } + + // listMethods: signature was either a string, or nothing. + // The useless string variant has been removed + $_xmlrpcs_listMethods_sig=array(array($GLOBALS['xmlrpcArray'])); $_xmlrpcs_listMethods_doc='This method lists all the methods that the XML-RPC server knows how to dispatch'; - function _xmlrpcs_listMethods($server, $m) + $_xmlrpcs_listMethods_sdoc=array(array('list of method names')); + function _xmlrpcs_listMethods($server, $m=null) // if called in plain php values mode, second param is missing { - global $xmlrpcerr, $xmlrpcstr, $_xmlrpcs_dmap; - $v=new xmlrpcval(); - $dmap=$server->dmap; + $outAr=array(); - for(reset($dmap); list($key, $val)=each($dmap); ) + foreach($server->dmap as $key => $val) { - $outAr[]=new xmlrpcval($key, 'string'); + $outAr[]=&new xmlrpcval($key, 'string'); } - $dmap=$_xmlrpcs_dmap; - for(reset($dmap); list($key, $val)=each($dmap); ) + if($server->allow_system_funcs) { - $outAr[]=new xmlrpcval($key, 'string'); + foreach($GLOBALS['_xmlrpcs_dmap'] as $key => $val) + { + $outAr[]=&new xmlrpcval($key, 'string'); + } } - $v->addArray($outAr); - return new xmlrpcresp($v); + return new xmlrpcresp(new xmlrpcval($outAr, 'array')); } - $_xmlrpcs_methodSignature_sig=array(array($xmlrpcArray, $xmlrpcString)); + $_xmlrpcs_methodSignature_sig=array(array($GLOBALS['xmlrpcArray'], $GLOBALS['xmlrpcString'])); $_xmlrpcs_methodSignature_doc='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)'; + $_xmlrpcs_methodSignature_sdoc=array(array('list of known signatures, each sig being an array of xmlrpc type names', 'name of method to be described')); function _xmlrpcs_methodSignature($server, $m) { - global $xmlrpcerr, $xmlrpcstr, $_xmlrpcs_dmap; - - $methName=$m->getParam(0); - $methName=$methName->scalarval(); - if (ereg("^system\.", $methName)) + // let accept as parameter both an xmlrpcval or string + if (is_object($m)) { - $dmap=$_xmlrpcs_dmap; $sysCall=1; + $methName=$m->getParam(0); + $methName=$methName->scalarval(); + } + else + { + $methName=$m; + } + if(strpos($methName, "system.") === 0) + { + $dmap=$GLOBALS['_xmlrpcs_dmap']; $sysCall=1; } else { $dmap=$server->dmap; $sysCall=0; } - // print "<!-- ${methName} -->\n"; - if (isset($dmap[$methName])) + if(isset($dmap[$methName])) { - if ($dmap[$methName]['signature']) + if(isset($dmap[$methName]['signature'])) { $sigs=array(); - $thesigs=$dmap[$methName]['signature']; - for($i=0; $i<sizeof($thesigs); $i++) + foreach($dmap[$methName]['signature'] as $inSig) { $cursig=array(); - $inSig=$thesigs[$i]; - for($j=0; $j<sizeof($inSig); $j++) + foreach($inSig as $sig) { - $cursig[]=new xmlrpcval($inSig[$j], 'string'); + $cursig[]=&new xmlrpcval($sig, 'string'); } - $sigs[]=new xmlrpcval($cursig, 'array'); + $sigs[]=&new xmlrpcval($cursig, 'array'); } - $r=new xmlrpcresp(new xmlrpcval($sigs, 'array')); + $r=&new xmlrpcresp(new xmlrpcval($sigs, 'array')); } else { - $r=new xmlrpcresp(new xmlrpcval('undef', 'string')); + // NB: according to the official docs, we should be returning a + // "none-array" here, which means not-an-array + $r=&new xmlrpcresp(new xmlrpcval('undef', 'string')); } } else { - $r=new xmlrpcresp(0,$xmlrpcerr['introspect_unknown'], $xmlrpcstr['introspect_unknown']); + $r=&new xmlrpcresp(0,$GLOBALS['xmlrpcerr']['introspect_unknown'], $GLOBALS['xmlrpcstr']['introspect_unknown']); } return $r; } - $_xmlrpcs_methodHelp_sig=array(array($xmlrpcString, $xmlrpcString)); + $_xmlrpcs_methodHelp_sig=array(array($GLOBALS['xmlrpcString'], $GLOBALS['xmlrpcString'])); $_xmlrpcs_methodHelp_doc='Returns help text if defined for the method passed, otherwise returns an empty string'; + $_xmlrpcs_methodHelp_sdoc=array(array('method description', 'name of the method to be described')); function _xmlrpcs_methodHelp($server, $m) { - global $xmlrpcerr, $xmlrpcstr, $_xmlrpcs_dmap; - - $methName=$m->getParam(0); - $methName=$methName->scalarval(); - if (ereg("^system\.", $methName)) + // let accept as parameter both an xmlrpcval or string + if (is_object($m)) + { + $methName=$m->getParam(0); + $methName=$methName->scalarval(); + } + else + { + $methName=$m; + } + if(strpos($methName, "system.") === 0) { - $dmap=$_xmlrpcs_dmap; $sysCall=1; + $dmap=$GLOBALS['_xmlrpcs_dmap']; $sysCall=1; } else { $dmap=$server->dmap; $sysCall=0; } - // print "<!-- ${methName} -->\n"; - if (isset($dmap[$methName])) + if(isset($dmap[$methName])) { - if ($dmap[$methName]['docstring']) + if(isset($dmap[$methName]['docstring'])) { - $r=new xmlrpcresp(new xmlrpcval($dmap[$methName]['docstring']), 'string'); + $r=&new xmlrpcresp(new xmlrpcval($dmap[$methName]['docstring']), 'string'); } else { - $r=new xmlrpcresp(new xmlrpcval('', 'string')); + $r=&new xmlrpcresp(new xmlrpcval('', 'string')); } } else { - $r=new xmlrpcresp(0, $xmlrpcerr['introspect_unknown'], $xmlrpcstr['introspect_unknown']); + $r=&new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['introspect_unknown'], $GLOBALS['xmlrpcstr']['introspect_unknown']); } return $r; } - $_xmlrpcs_multicall_sig = array(array($xmlrpcArray, $xmlrpcArray)); + $_xmlrpcs_multicall_sig = array(array($GLOBALS['xmlrpcArray'], $GLOBALS['xmlrpcArray'])); $_xmlrpcs_multicall_doc = 'Boxcar multiple RPC calls in one request. See http://www.xmlrpc.com/discuss/msgReader$1208 for details'; - + $_xmlrpcs_multicall_sdoc = array(array('list of response structs, where each struct has the usual members', 'list of calls, with each call being represented as a struct, with members "methodname" and "params"')); function _xmlrpcs_multicall_error($err) { - if (is_string($err)) + if(is_string($err)) { - global $xmlrpcerr, $xmlrpcstr; - $str = $xmlrpcstr["multicall_${err}"]; - $code = $xmlrpcerr["multicall_${err}"]; + $str = $GLOBALS['xmlrpcstr']["multicall_${err}"]; + $code = $GLOBALS['xmlrpcerr']["multicall_${err}"]; } else { $code = $err->faultCode(); $str = $err->faultString(); } - $struct['faultCode'] = new xmlrpcval($code, 'int'); - $struct['faultString'] = new xmlrpcval($str, 'string'); + $struct = array(); + $struct['faultCode'] =& new xmlrpcval($code, 'int'); + $struct['faultString'] =& new xmlrpcval($str, 'string'); return new xmlrpcval($struct, 'struct'); } function _xmlrpcs_multicall_do_call($server, $call) { - if ($call->kindOf() != 'struct') + if($call->kindOf() != 'struct') { return _xmlrpcs_multicall_error('notstruct'); } - $methName = $call->structmem('methodName'); - if (!$methName) + $methName = @$call->structmem('methodName'); + if(!$methName) { return _xmlrpcs_multicall_error('nomethod'); } - if ($methName->kindOf() != 'scalar' || $methName->scalartyp() != 'string') + if($methName->kindOf() != 'scalar' || $methName->scalartyp() != 'string') { return _xmlrpcs_multicall_error('notstring'); } - if ($methName->scalarval() == 'system.multicall') + if($methName->scalarval() == 'system.multicall') { return _xmlrpcs_multicall_error('recursion'); } - $params = $call->structmem('params'); - if (!$params) + $params = @$call->structmem('params'); + if(!$params) { return _xmlrpcs_multicall_error('noparams'); } - if ($params->kindOf() != 'array') + if($params->kindOf() != 'array') { return _xmlrpcs_multicall_error('notarray'); } $numParams = $params->arraysize(); - $msg = new xmlrpcmsg($methName->scalarval()); - for ($i = 0; $i < $numParams; $i++) + $msg =& new xmlrpcmsg($methName->scalarval()); + for($i = 0; $i < $numParams; $i++) { - $msg->addParam($params->arraymem($i)); + if(!$msg->addParam($params->arraymem($i))) + { + $i++; + return _xmlrpcs_multicall_error(new xmlrpcresp(0, + $GLOBALS['xmlrpcerr']['incorrect_params'], + $GLOBALS['xmlrpcstr']['incorrect_params'] . ": probable xml error in param " . $i)); + } } $result = $server->execute($msg); - if ($result->faultCode() != 0) + if($result->faultCode() != 0) + { + return _xmlrpcs_multicall_error($result); // Method returned fault. + } + + return new xmlrpcval(array($result->value()), 'array'); + } + + function _xmlrpcs_multicall_do_call_phpvals($server, $call) + { + if(!is_array($call)) + { + return _xmlrpcs_multicall_error('notstruct'); + } + if(!array_key_exists('methodName', $call)) + { + return _xmlrpcs_multicall_error('nomethod'); + } + if (!is_string($call['methodName'])) + { + return _xmlrpcs_multicall_error('notstring'); + } + if($call['methodName'] == 'system.multicall') + { + return _xmlrpcs_multicall_error('recursion'); + } + if(!array_key_exists('params', $call)) + { + return _xmlrpcs_multicall_error('noparams'); + } + if(!is_array($call['params'])) + { + return _xmlrpcs_multicall_error('notarray'); + } + + // this is a real dirty and simplistic hack, since we might have received a + // base64 or datetime values, but they will be listed as strings here... + $numParams = count($call['params']); + $pt = array(); + foreach($call['params'] as $val) + $pt[] = php_2_xmlrpc_type(gettype($val)); + + $result = $server->execute($call['methodName'], $call['params'], $pt); + + if($result->faultCode() != 0) { - return _xmlrpcs_multicall_error($result); // Method returned fault. + return _xmlrpcs_multicall_error($result); // Method returned fault. } return new xmlrpcval(array($result->value()), 'array'); @@ -212,53 +311,182 @@ function _xmlrpcs_multicall($server, $m) { - $calls = $m->getParam(0); - $numCalls = $calls->arraysize(); $result = array(); - - for ($i = 0; $i < $numCalls; $i++) + // let accept a plain list of php parameters, beside a single xmlrpc msg object + if (is_object($m)) + { + $calls = $m->getParam(0); + $numCalls = $calls->arraysize(); + for($i = 0; $i < $numCalls; $i++) + { + $call = $calls->arraymem($i); + $result[$i] = _xmlrpcs_multicall_do_call($server, $call); + } + } + else { - $call = $calls->arraymem($i); - $result[$i] = _xmlrpcs_multicall_do_call($server, $call); + $numCalls=count($m); + for($i = 0; $i < $numCalls; $i++) + { + $result[$i] = _xmlrpcs_multicall_do_call_phpvals($server, $m[$i]); + } } return new xmlrpcresp(new xmlrpcval($result, 'array')); } - $_xmlrpcs_dmap=array( + $GLOBALS['_xmlrpcs_dmap']=array( 'system.listMethods' => array( 'function' => '_xmlrpcs_listMethods', 'signature' => $_xmlrpcs_listMethods_sig, - 'docstring' => $_xmlrpcs_listMethods_doc), + 'docstring' => $_xmlrpcs_listMethods_doc, + 'signature_docs' => $_xmlrpcs_listMethods_sdoc), 'system.methodHelp' => array( 'function' => '_xmlrpcs_methodHelp', 'signature' => $_xmlrpcs_methodHelp_sig, - 'docstring' => $_xmlrpcs_methodHelp_doc), + 'docstring' => $_xmlrpcs_methodHelp_doc, + 'signature_docs' => $_xmlrpcs_methodHelp_sdoc), 'system.methodSignature' => array( 'function' => '_xmlrpcs_methodSignature', 'signature' => $_xmlrpcs_methodSignature_sig, - 'docstring' => $_xmlrpcs_methodSignature_doc), + 'docstring' => $_xmlrpcs_methodSignature_doc, + 'signature_docs' => $_xmlrpcs_methodSignature_sdoc), 'system.multicall' => array( 'function' => '_xmlrpcs_multicall', 'signature' => $_xmlrpcs_multicall_sig, - 'docstring' => $_xmlrpcs_multicall_doc - ) + 'docstring' => $_xmlrpcs_multicall_doc, + 'signature_docs' => $_xmlrpcs_multicall_sdoc), + 'system.getCapabilities' => array( + 'function' => '_xmlrpcs_getCapabilities', + 'signature' => $_xmlrpcs_getCapabilities_sig, + 'docstring' => $_xmlrpcs_getCapabilities_doc, + 'signature_docs' => $_xmlrpcs_getCapabilities_sdoc) ); - $_xmlrpc_debuginfo=''; + $GLOBALS['_xmlrpcs_occurred_errors'] = ''; + $GLOBALS['_xmlrpcs_prev_ehandler'] = ''; + /** + * Error handler used to track errors that occur during server-side execution of PHP code. + * This allows to report back to the client whether an internal error has occurred or not + * using an xmlrpc response object, instead of letting the client deal with the html junk + * that a PHP execution error on the server generally entails. + * + * NB: in fact a user defined error handler can only handle WARNING, NOTICE and USER_* errors. + * + */ + function _xmlrpcs_errorHandler($errcode, $errstring, $filename=null, $lineno=null, $context=null) + { + // obey the @ protocol + if (error_reporting() == 0) + return; + + //if($errcode != E_NOTICE && $errcode != E_WARNING && $errcode != E_USER_NOTICE && $errcode != E_USER_WARNING) + if($errcode != 2048) // do not use E_STRICT by name, since on PHP 4 it will not be defined + { + $GLOBALS['_xmlrpcs_occurred_errors'] = $GLOBALS['_xmlrpcs_occurred_errors'] . $errstring . "\n"; + } + // Try to avoid as much as possible disruption to the previous error handling + // mechanism in place + if($GLOBALS['_xmlrpcs_prev_ehandler'] == '') + { + // The previous error handler was the default: all we should do is log error + // to the default error log (if level high enough) + if(ini_get('log_errors') && (intval(ini_get('error_reporting')) & $errcode)) + { + error_log($errstring); + } + } + else + { + // Pass control on to previous error handler, trying to avoid loops... + if($GLOBALS['_xmlrpcs_prev_ehandler'] != '_xmlrpcs_errorHandler') + { + // NB: this code will NOT work on php < 4.0.2: only 2 params were used for error handlers + if(is_array($GLOBALS['_xmlrpcs_prev_ehandler'])) + { + $GLOBALS['_xmlrpcs_prev_ehandler'][0]->$GLOBALS['_xmlrpcs_prev_ehandler'][1]($errcode, $errstring, $filename, $lineno, $context); + } + else + { + $GLOBALS['_xmlrpcs_prev_ehandler']($errcode, $errstring, $filename, $lineno, $context); + } + } + } + } + + $GLOBALS['_xmlrpc_debuginfo']=''; + + /** + * Add a string to the debug info that can be later seralized by the server + * as part of the response message. + * Note that for best compatbility, the debug string should be encoded using + * the $GLOBALS['xmlrpc_internalencoding'] character set. + * @param string $m + * @access public + */ function xmlrpc_debugmsg($m) { - global $_xmlrpc_debuginfo; - $_xmlrpc_debuginfo=$_xmlrpc_debuginfo . $m . "\n"; + $GLOBALS['_xmlrpc_debuginfo'] .= $m . "\n"; } class xmlrpc_server { + /// array defining php functions exposed as xmlrpc methods by this server var $dmap=array(); + /** + * Defines how functions in dmap will be invokde: either using an xmlrpc msg object + * or plain php values. + * valid strings are 'xmlrpcvals', 'phpvals' or 'epivals' + */ + var $functions_parameters_type='xmlrpcvals'; + /// controls wether the server is going to echo debugging messages back to the client as comments in response body. valid values: 0,1,2,3 + var $debug = 1; + /** + * When set to true, it will enable HTTP compression of the response, in case + * the client has declared its support for compression in the request. + */ + var $compress_response = false; + /** + * List of http compression methods accepted by the server for requests. + * NB: PHP supports deflate, gzip compressions out of the box if compiled w. zlib + */ + var $accepted_compression = array(); + /// shall we serve calls to system.* methods? + var $allow_system_funcs = true; + /// list of charset encodings natively accepted for requests + var $accepted_charset_encodings = array(); + /** + * charset encoding to be used for response. + * NB: if we can, we will convert the generated response from internal_encoding to the intended one. + * can be: a supported xml encoding (only UTF-8 and ISO-8859-1 at present, unless mbstring is enabled), + * null (leave unspecified in response, convert output stream to US_ASCII), + * 'default' (use xmlrpc library default as specified in xmlrpc.inc, convert output stream if needed), + * or 'auto' (use client-specified charset encoding or same as request if request headers do not specify it (unless request is US-ASCII: then use library default anyway). + * NB: pretty dangerous if you accept every charset and do not have mbstring enabled) + */ + var $response_charset_encoding = ''; + /// storage for internal debug info + var $debug_info = ''; + /// extra data passed at runtime to method handling functions. Used only by EPI layer + var $user_data = null; - function xmlrpc_server($dispMap='', $serviceNow=1) + /** + * @param array $dispmap the dispatch map withd efinition of exposed services + * @param boolean $servicenow set to false to prevent the server from runnung upon construction + */ + function xmlrpc_server($dispMap=null, $serviceNow=true) { - global $HTTP_RAW_POST_DATA; + // if ZLIB is enabled, let the server by default accept compressed requests, + // and compress responses sent to clients that support them + if(function_exists('gzinflate')) + { + $this->accepted_compression = array('gzip', 'deflate'); + $this->compress_response = true; + } + + // by default the xml parser can support these 3 charset encodings + $this->accepted_charset_encodings = array('UTF-8', 'ISO-8859-1', 'US-ASCII'); + // dispMap is a dispatch array of methods // mapped to function names and signatures // if a method @@ -278,229 +506,667 @@ } } - function serializeDebug() + /** + * Set debug level of server. + * @param integer $in debug lvl: determines info added to xmlrpc responses (as xml comments) + * 0 = no debug info, + * 1 = msgs set from user with debugmsg(), + * 2 = add complete xmlrpc request (headers and body), + * 3 = add also all processing warnings happened during method processing + * (NB: this involves setting a custom error handler, and might interfere + * with the standard processing of the php function exposed as method. In + * particular, triggering an USER_ERROR level error will not halt script + * execution anymore, but just end up logged in the xmlrpc response) + * Note that info added at elevel 2 and 3 will be base64 encoded + * @access public + */ + function setDebug($in) + { + $this->debug=$in; + } + + /** + * Return a string with the serialized representation of all debug info + * @param string $charset_encoding the target charset encoding for the serialization + * @return string an XML comment (or two) + */ + function serializeDebug($charset_encoding='') { - global $_xmlrpc_debuginfo; - if ($_xmlrpc_debuginfo!='') + // Tough encoding problem: which internal charset should we assume for debug info? + // It might contain a copy of raw data received from client, ie with unknown encoding, + // intermixed with php generated data and user generated data... + // so we split it: system debug is base 64 encoded, + // user debug info should be encoded by the end user using the INTERNAL_ENCODING + $out = ''; + if ($this->debug_info != '') { - return "<!-- DEBUG INFO:\n\n" . xmlrpc_encode_entitites($_xmlrpc_debuginfo) . "\n-->\n"; + $out .= "<!-- SERVER DEBUG INFO (BASE64 ENCODED):\n".base64_encode($this->debug_info)."\n-->\n"; } - else + if($GLOBALS['_xmlrpc_debuginfo']!='') { - return ''; + + $out .= "<!-- DEBUG INFO:\n" . xmlrpc_encode_entitites(str_replace('--', '_-', $GLOBALS['_xmlrpc_debuginfo']), $GLOBALS['xmlrpc_internalencoding'], $charset_encoding) . "\n-->\n"; + // NB: a better solution MIGHT be to use CDATA, but we need to insert it + // into return payload AFTER the beginning tag + //$out .= "<![CDATA[ DEBUG INFO:\n\n" . str_replace(']]>', ']_]_>', $GLOBALS['_xmlrpc_debuginfo']) . "\n]]>\n"; } + return $out; } - function service() + /** + * Execute the xmlrpc request, printing the response + * @param string $data the request body. If null, the http POST request will be examined + * @return xmlrpcresp the response object (usually not used by caller...) + * @access public + */ + function service($data=null, $return_payload=false) { - //global $xmlrpc_defencoding; + if ($data === null) + { + $data = isset($GLOBALS['HTTP_RAW_POST_DATA']) ? $GLOBALS['HTTP_RAW_POST_DATA'] : ''; + } + $raw_data = $data; + + // reset internal debug info + $this->debug_info = ''; + + // Echo back what we received, before parsing it + if($this->debug > 1) + { + $this->debugmsg("+++GOT+++\n" . $data . "\n+++END+++"); + } + + $r = $this->parseRequestHeaders($data, $req_charset, $resp_charset, $resp_encoding); + if (!$r) + { + $r=$this->parseRequest($data, $req_charset); + } + + // save full body of request into response, for more debugging usages + $r->raw_data = $raw_data; + + if($this->debug > 2 && $GLOBALS['_xmlrpcs_occurred_errors']) + { + $this->debugmsg("+++PROCESSING ERRORS AND WARNINGS+++\n" . + $GLOBALS['_xmlrpcs_occurred_errors'] . "+++END+++"); + } + + $payload=$this->xml_header($resp_charset); + if($this->debug > 0) + { + $payload = $payload . $this->serializeDebug($resp_charset); + } + + // G. Giunta 2006-01-27: do not create response serialization if it has + // already happened. Helps building json magic + if (empty($r->payload)) + { + $r->serialize($resp_charset); + } + $payload = $payload . $r->payload; + + if ($return_payload) + { + return $payload; + } + + // if we get a warning/error that has output some text before here, then we cannot + // add a new header. We cannot say we are sending xml, either... + if(!headers_sent()) + { + header('Content-Type: '.$r->content_type); + // we do not know if client actually told us an accepted charset, but if he did + // we have to tell him what we did + header("Vary: Accept-Charset"); + + // http compression of output: only + // if we can do it, and we want to do it, and client asked us to, + // and php ini settings do not force it already + $php_no_self_compress = ini_get('zlib.output_compression') == '' && (ini_get('output_handler') != 'ob_gzhandler'); + if($this->compress_response && function_exists('gzencode') && $resp_encoding != '' + && $php_no_self_compress) + { + if(strpos($resp_encoding, 'gzip') !== false) + { + $payload = gzencode($payload); + header("Content-Encoding: gzip"); + header("Vary: Accept-Encoding"); + } + elseif (strpos($resp_encoding, 'deflate') !== false) + { + $payload = gzcompress($payload); + header("Content-Encoding: deflate"); + header("Vary: Accept-Encoding"); + } + } + + // do not ouput content-length header if php is compressing output for us: + // it will mess up measurements + if($php_no_self_compress) + { + header('Content-Length: ' . (int)strlen($payload)); + } + } + else + { + error_log('XML-RPC: xmlrpc_server::service: http headers already sent before response is fully generated. Check for php warning or error messages'); + } - $r=$this->parseRequest(); - //$payload='<?xml version="1.0" encoding="' . $xmlrpc_defencoding . '"?' . '>' . "\n" - $payload='<?xml version="1.0" ?' . '>' . "\n" - . $this->serializeDebug() - . $r->serialize(); - header('Content-Type: text/xml'); - header('Content-Length: ' . (int)strlen($payload)); print $payload; + + // return request, in case subclasses want it + return $r; } - /* - add a method to the dispatch map + /** + * Add a method to the dispatch map + * @param string $methodname the name with which the method will be made available + * @param string $function the php function that will get invoked + * @param array $sig the array of valid method signatures + * @param string $doc method documentation + * @access public */ - function add_to_map($methodname,$function,$sig,$doc) + function add_to_map($methodname,$function,$sig=null,$doc='') { $this->dmap[$methodname] = array( - 'function' => $function, - 'signature' => $sig, + 'function' => $function, 'docstring' => $doc ); + if ($sig) + { + $this->dmap[$methodname]['signature'] = $sig; + } } + /** + * Verify type and number of parameters received against a list of known signatures + * @param array $in array of either xmlrpcval objects or xmlrpc type definitions + * @param array $sig array of known signatures to match against + * @access private + */ function verifySignature($in, $sig) { - for($i=0; $i<sizeof($sig); $i++) + // check each possible signature in turn + if (is_object($in)) { - // check each possible signature in turn - $cursig=$sig[$i]; - if (sizeof($cursig)==$in->getNumParams()+1) + $numParams = $in->getNumParams(); + } + else + { + $numParams = count($in); + } + foreach($sig as $cursig) + { + if(count($cursig)==$numParams+1) { $itsOK=1; - for($n=0; $n<$in->getNumParams(); $n++) + for($n=0; $n<$numParams; $n++) { - $p=$in->getParam($n); - // print "<!-- $p -->\n"; - if ($p->kindOf() == 'scalar') + if (is_object($in)) { - $pt=$p->scalartyp(); + $p=$in->getParam($n); + if($p->kindOf() == 'scalar') + { + $pt=$p->scalartyp(); + } + else + { + $pt=$p->kindOf(); + } } else { - $pt=$p->kindOf(); + $pt= $in[$n] == 'i4' ? 'int' : $in[$n]; // dispatch maps never use i4... } - // $n+1 as first type of sig is return type - if ($pt != $cursig[$n+1]) + + // param index is $n+1, as first member of sig is return type + if($pt != $cursig[$n+1] && $cursig[$n+1] != $GLOBALS['xmlrpcValue']) { $itsOK=0; - $pno=$n+1; $wanted=$cursig[$n+1]; $got=$pt; + $pno=$n+1; + $wanted=$cursig[$n+1]; + $got=$pt; break; } } - if ($itsOK) + if($itsOK) { return array(1,''); } } } - if (isset($wanted)) - return array(0, "Wanted ${wanted}, got ${got} at param ${pno})"); + if(isset($wanted)) + { + return array(0, "Wanted ${wanted}, got ${got} at param ${pno}"); + } else + { return array(0, "No method signature matches number of parameters"); + } } - function parseRequest($data='') + /** + * Parse http headers received along with xmlrpc request. If needed, inflate request + * @return null on success or an xmlrpcresp + * @access private + */ + function parseRequestHeaders(&$data, &$req_encoding, &$resp_encoding, &$resp_compression) { - global $_xh,$HTTP_RAW_POST_DATA; - global $xmlrpcerr, $xmlrpcstr, $xmlrpcerrxml, $xmlrpc_defencoding, - $_xmlrpcs_dmap, $xmlrpc_internalencoding; + // Play nice to PHP 4.0.x: superglobals were not yet invented... + if(!isset($_SERVER)) + { + $_SERVER = $GLOBALS['HTTP_SERVER_VARS']; + } + + if($this->debug > 1) + { + if(function_exists('getallheaders')) + { + $this->debugmsg(''); // empty line + foreach(getallheaders() as $name => $val) + { + $this->debugmsg("HEADER: $name: $val"); + } + } + + } + + if(isset($_SERVER['HTTP_CONTENT_ENCODING'])) + { + $content_encoding = str_replace('x-', '', $_SERVER['HTTP_CONTENT_ENCODING']); + } + else + { + $content_encoding = ''; + } + + // check if request body has been compressed and decompress it + if($content_encoding != '' && strlen($data)) + { + if($content_encoding == 'deflate' || $content_encoding == 'gzip') + { + // if decoding works, use it. else assume data wasn't gzencoded + if(function_exists('gzinflate') && in_array($content_encoding, $this->accepted_compression)) + { + if($content_encoding == 'deflate' && $degzdata = @gzuncompress($data)) + { + $data = $degzdata; + if($this->debug > 1) + { + $this->debugmsg("\n+++INFLATED REQUEST+++[".strlen($data)." chars]+++\n" . $data . "\n+++END+++"); + } + } + elseif($content_encoding == 'gzip' && $degzdata = @gzinflate(substr($data, 10))) + { + $data = $degzdata; + if($this->debug > 1) + $this->debugmsg("+++INFLATED REQUEST+++[".strlen($data)." chars]+++\n" . $data . "\n+++END+++"); + } + else + { + $r =& new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['server_decompress_fail'], $GLOBALS['xmlrpcstr']['server_decompress_fail']); + return $r; + } + } + else + { + //error_log('The server sent deflated data. Your php install must have the Zlib extension compiled in to support this.'); + $r =& new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['server_cannot_decompress'], $GLOBALS['xmlrpcstr']['server_cannot_decompress']); + return $r; + } + } + } + + // check if client specified accepted charsets, and if we know how to fulfill + // the request + if ($this->response_charset_encoding == 'auto') + { + $resp_encoding = ''; + if (isset($_SERVER['HTTP_ACCEPT_CHARSET'])) + { + // here we should check if we can match the client-requested encoding + // with the encodings we know we can generate. + /// @todo we should parse q=0.x preferences instead of getting first charset specified... + $client_accepted_charsets = explode(',', strtoupper($_SERVER['HTTP_ACCEPT_CHARSET'])); + // Give preference to internal encoding + $known_charsets = array($this->internal_encoding, 'UTF-8', 'ISO-8859-1', 'US-ASCII'); + foreach ($known_charsets as $charset) + { + foreach ($client_accepted_charsets as $accepted) + if (strpos($accepted, $charset) === 0) + { + $resp_encoding = $charset; + break; + } + if ($resp_encoding) + break; + } + } + } + else + { + $resp_encoding = $this->response_charset_encoding; + } - if ($data=='') + if (isset($_SERVER['HTTP_ACCEPT_ENCODING'])) { - $data=$HTTP_RAW_POST_DATA; + $resp_compression = $_SERVER['HTTP_ACCEPT_ENCODING']; } - // G. Giunta 2005/02/13: we do NOT expect to receive html entities - // so we do not try to convert them into xml character entities + else + { + $resp_compression = ''; + } + + // 'guestimate' request encoding + /// @todo check if mbstring is enabled and automagic input conversion is on: it might mingle with this check??? + $req_encoding = guess_encoding(isset($_SERVER['CONTENT_TYPE']) ? $_SERVER['CONTENT_TYPE'] : '', + $data); + + return null; + } + + /** + * Parse an xml chunk containing an xmlrpc request and execute the corresponding + * php function registered with the server + * @param string $data the xml request + * @param string $req_encoding (optional) the charset encoding of the xml request + * @return xmlrpcresp + * @access private + */ + function parseRequest($data, $req_encoding='') + { + // 2005/05/07 commented and moved into caller function code + //if($data=='') + //{ + // $data=$GLOBALS['HTTP_RAW_POST_DATA']; + //} + + // G. Giunta 2005/02/13: we do NOT expect to receive html entities + // so we do not try to convert them into xml character entities //$data = xmlrpc_html_entity_xlate($data); - $parser = xml_parser_create($xmlrpc_defencoding); - - $_xh[$parser]=array(); - //$_xh[$parser]['st']=''; - //$_xh[$parser]['cm']=0; - $_xh[$parser]['isf']=0; - $_xh[$parser]['isf_reason']=''; - $_xh[$parser]['params']=array(); - $_xh[$parser]['stack']=array(); - $_xh[$parser]['valuestack'] = array(); - $_xh[$parser]['method']=''; + + $GLOBALS['_xh']=array(); + $GLOBALS['_xh']['ac']=''; + $GLOBALS['_xh']['stack']=array(); + $GLOBALS['_xh']['valuestack'] = array(); + $GLOBALS['_xh']['params']=array(); + $GLOBALS['_xh']['pt']=array(); + $GLOBALS['_xh']['isf']=0; + $GLOBALS['_xh']['isf_reason']=''; + $GLOBALS['_xh']['method']=false; // so we can check later if we got a methodname or not + $GLOBALS['_xh']['rt']=''; // decompose incoming XML into request structure + if ($req_encoding != '') + { + if (!in_array($req_encoding, array('UTF-8', 'ISO-8859-1', 'US-ASCII'))) + // the following code might be better for mb_string enabled installs, but + // makes the lib about 200% slower... + //if (!is_valid_charset($req_encoding, array('UTF-8', 'ISO-8859-1', 'US-ASCII'))) + { + error_log('XML-RPC: xmlrpc_server::parseRequest: invalid charset encoding of received request: '.$req_encoding); + $req_encoding = $GLOBALS['xmlrpc_defencoding']; + } + /// @BUG this will fail on PHP 5 if charset is not specified in the xml prologue, + // the encoding is not UTF8 and there are non-ascii chars in the text... + $parser = xml_parser_create($req_encoding); + } + else + { + $parser = xml_parser_create(); + } xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true); - // G. Giunta 2005/02/13: PHP internally uses ISO-8859-1, so we have to tell - // the xml parser to give us back data in the expected charset - xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $xmlrpc_internalencoding); + // G. Giunta 2005/02/13: PHP internally uses ISO-8859-1, so we have to tell + // the xml parser to give us back data in the expected charset + xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $GLOBALS['xmlrpc_internalencoding']); - xml_set_element_handler($parser, 'xmlrpc_se', 'xmlrpc_ee'); + if ($this->functions_parameters_type != 'xmlrpcvals') + xml_set_element_handler($parser, 'xmlrpc_se', 'xmlrpc_ee_fast'); + else + xml_set_element_handler($parser, 'xmlrpc_se', 'xmlrpc_ee'); xml_set_character_data_handler($parser, 'xmlrpc_cd'); xml_set_default_handler($parser, 'xmlrpc_dh'); - if (!xml_parse($parser, $data, 1)) + if(!xml_parse($parser, $data, 1)) { // return XML error as a faultCode - $r=new xmlrpcresp(0, - $xmlrpcerrxml+xml_get_error_code($parser), - sprintf('XML error: %s at line %d', + $r=&new xmlrpcresp(0, + $GLOBALS['xmlrpcerrxml']+xml_get_error_code($parser), + sprintf('XML error: %s at line %d, column %d', xml_error_string(xml_get_error_code($parser)), - xml_get_current_line_number($parser))); + xml_get_current_line_number($parser), xml_get_current_column_number($parser))); xml_parser_free($parser); } - else - if ($_xh[$parser]['isf']) + elseif ($GLOBALS['_xh']['isf']) { xml_parser_free($parser); - $r=new xmlrpcresp(0, - $xmlrpcerr['invalid_request'], - $xmlrpcstr['invalid_request'] . ' ' . $_xh[$parser]['isf_reason']); + $r=&new xmlrpcresp(0, + $GLOBALS['xmlrpcerr']['invalid_request'], + $GLOBALS['xmlrpcstr']['invalid_request'] . ' ' . $GLOBALS['_xh']['isf_reason']); } else { xml_parser_free($parser); - - $m=new xmlrpcmsg($_xh[$parser]['method']); - // now add parameters in - $plist=''; - //$allOK = 1; - for($i=0; $i<sizeof($_xh[$parser]['params']); $i++) + if ($this->functions_parameters_type != 'xmlrpcvals') { - //print "<!-- " . $_xh[$parser]['params'][$i]. "-->\n"; - $plist.="$i - " . $_xh[$parser]['params'][$i]. ";\n"; - //$allOK = 0; - //@eval('$m->addParam(' . $_xh[$parser]['params'][$i]. '); $allOK=1;'); - @$m->addParam($_xh[$parser]['params'][$i]); - //if (!$allOK) - //{ - // break; - //} + if($this->debug > 1) + { + $this->debugmsg("\n+++PARSED+++\n".var_export($GLOBALS['_xh']['params'], true)."\n+++END+++"); + } + $r = $this->execute($GLOBALS['_xh']['method'], $GLOBALS['_xh']['params'], $GLOBALS['_xh']['pt']); } - // uncomment this to really see what the server's getting! - // xmlrpc_debugmsg($plist); - //if (!$allOK) - //{ - // $r = new xmlrpcresp(0, - // $xmlrpcerr['incorrect_params'], - // $xmlrpcstr['incorrect_params'] . ": xml error in param " . $i); - //} - //else - //{ + else + { + // build an xmlrpcmsg object with data parsed from xml + $m=&new xmlrpcmsg($GLOBALS['_xh']['method']); + // now add parameters in + for($i=0; $i<count($GLOBALS['_xh']['params']); $i++) + { + $m->addParam($GLOBALS['_xh']['params'][$i]); + } + + if($this->debug > 1) + { + $this->debugmsg("\n+++PARSED+++\n".var_export($m, true)."\n+++END+++"); + } + $r = $this->execute($m); - //} + } } return $r; } - function execute ($m) + /** + * Execute a method invoked by the client, checking parameters used + * @param mixed $m either an xmlrpcmsg obj or a method name + * @param array $params array with method parameters as php types (if m is method name only) + * @param array $paramtypes array with xmlrpc types of method parameters (if m is method name only) + * @return xmlrpcresp + * @access private + */ + function execute($m, $params=null, $paramtypes=null) { - global $xmlrpcerr, $xmlrpcstr, $_xmlrpcs_dmap; - // now to deal with the method - $methName = $m->method(); - $sysCall = ereg("^system\.", $methName); - $dmap = $sysCall ? $_xmlrpcs_dmap : $this->dmap; + if (is_object($m)) + { + $methName = $m->method(); + } + else + { + $methName = $m; + } + $sysCall = $this->allow_system_funcs && (strpos($methName, "system.") === 0); + $dmap = $sysCall ? $GLOBALS['_xmlrpcs_dmap'] : $this->dmap; - if (!isset($dmap[$methName]['function'])) + if(!isset($dmap[$methName]['function'])) { // No such method return new xmlrpcresp(0, - $xmlrpcerr['unknown_method'], - $xmlrpcstr['unknown_method']); + $GLOBALS['xmlrpcerr']['unknown_method'], + $GLOBALS['xmlrpcstr']['unknown_method']); } - // Check signature. - if (isset($dmap[$methName]['signature'])) + // Check signature + if(isset($dmap[$methName]['signature'])) { $sig = $dmap[$methName]['signature']; - list($ok, $errstr) = $this->verifySignature($m, $sig); + if (is_object($m)) + { + list($ok, $errstr) = $this->verifySignature($m, $sig); + } + else + { + list($ok, $errstr) = $this->verifySignature($paramtypes, $sig); + } if(!$ok) { // Didn't match. return new xmlrpcresp( 0, - $xmlrpcerr['incorrect_params'], - $xmlrpcstr['incorrect_params'] . ": ${errstr}" + $GLOBALS['xmlrpcerr']['incorrect_params'], + $GLOBALS['xmlrpcstr']['incorrect_params'] . ": ${errstr}" ); } } $func = $dmap[$methName]['function']; + // let the 'class::function' syntax be accepted in dispatch maps + if(is_string($func) && strpos($func, '::')) + { + $func = explode('::', $func); + } + // verify that function to be invoked is in fact callable + if(!is_callable($func)) + { + error_log("XML-RPC: xmlrpc_server::execute: function $func registered as method handler is not callable"); + return new xmlrpcresp( + 0, + $GLOBALS['xmlrpcerr']['server_error'], + $GLOBALS['xmlrpcstr']['server_error'] . ": no function matches method" + ); + } - if ($sysCall) + // If debug level is 3, we should catch all errors generated during + // processing of user function, and log them as part of response + if($this->debug > 2) { - return call_user_func($func, $this, $m); + $GLOBALS['_xmlrpcs_prev_ehandler'] = set_error_handler('_xmlrpcs_errorHandler'); + } + if (is_object($m)) + { + if($sysCall) + { + $r = call_user_func($func, $this, $m); + } + else + { + $r = call_user_func($func, $m); + } + if (!is_a($r, 'xmlrpcresp')) + { + error_log("XML-RPC: xmlrpc_server::execute: function $func registered as method handler does not return an xmlrpcresp object"); + if (is_a($r, 'xmlrpcval')) + { + $r =& new xmlrpcresp($r); + } + else + { + $r =& new xmlrpcresp( + 0, + $GLOBALS['xmlrpcerr']['server_error'], + $GLOBALS['xmlrpcstr']['server_error'] . ": function does not return xmlrpcresp object" + ); + } + } } else { - return call_user_func($func, $m); + // call a 'plain php' function + if($sysCall) + { + array_unshift($params, $this); + $r = call_user_func_array($func, $params); + } + else + { + // 3rd API convention for method-handling functions: EPI-style + if ($this->functions_parameters_type == 'epivals') + { + $r = call_user_func_array($func, array($methName, $params, $this->user_data)); + // mimic EPI behaviour: if we get an array that looks like an error, make it + // an eror response + if (is_array($r) && array_key_exists('faultCode', $r) && array_key_exists('faultString', $r)) + { + $r =& new xmlrpcresp(0, (integer)$r['faultCode'], (string)$r['faultString']); + } + else + { + // functions using EPI api should NOT return resp objects, + // so make sure we encode the return type correctly + $r =& new xmlrpcresp(php_xmlrpc_encode($r, array('extension_api'))); + } + } + else + { + $r = call_user_func_array($func, $params); + } + } + // the return type can be either an xmlrpcresp object or a plain php value... + if (!is_a($r, 'xmlrpcresp')) + { + // what should we assume here about automatic encoding of datetimes + // and php classes instances??? + $r =& new xmlrpcresp(php_xmlrpc_encode($r, array('auto_dates'))); + } } + if($this->debug > 2) + { + // note: restore the error handler we found before calling the + // user func, even if it has been changed inside the func itself + if($GLOBALS['_xmlrpcs_prev_ehandler']) + { + set_error_handler($GLOBALS['_xmlrpcs_prev_ehandler']); + } + else + { + restore_error_handler(); + } + } + return $r; } - function echoInput() + /** + * add a string to the 'internal debug message' (separate from 'user debug message') + * @param string $strings + * @access private + */ + function debugmsg($string) { - global $HTTP_RAW_POST_DATA; + $this->debug_info .= $string."\n"; + } - // a debugging routine: just echos back the input - // packet as a string value + /** + * @access private + */ + function xml_header($charset_encoding='') + { + if ($charset_encoding != '') + { + return "<?xml version=\"1.0\" encoding=\"$charset_encoding\"?" . ">\n"; + } + else + { + return "<?xml version=\"1.0\"?" . ">\n"; + } + } - $r=new xmlrpcresp; - $r->xv=new xmlrpcval( "'Aha said I: '" . $HTTP_RAW_POST_DATA, 'string'); + /** + * A debugging routine: just echoes back the input packet as a string value + * DEPRECATED! + */ + function echoInput() + { + $r=&new xmlrpcresp(new xmlrpcval( "'Aha said I: '" . $GLOBALS['HTTP_RAW_POST_DATA'], 'string')); print $r->serialize(); } } -?> +?>
\ No newline at end of file |