From 3a76efafdf42b1e39ac7fbe629e23e2dbf2c299c Mon Sep 17 00:00:00 2001 From: gggeek Date: Sat, 31 Dec 2022 17:11:15 +0000 Subject: [PATCH] WIP manual revamp --- README.md | 4 +- doc/build/generate.sh | 9 +- doc/manual/phpxmlrpc_manual.adoc | 1435 +++++++++++++++--------------- src/Value.php | 2 +- 4 files changed, 714 insertions(+), 736 deletions(-) diff --git a/README.md b/README.md index ac6aef9c..d53f8fa7 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ XMLRPC for PHP ============== + A php library for building xml-rpc clients and servers. Requirements and Installation @@ -17,7 +18,8 @@ library main features and all project related information, including information and demo servers. The user manual can be found in the doc/manual directory: [phpxmlrpc_manual.adoc](doc/manual/phpxmlrpc_manual.adoc). -It includes sections about upgrading from previous versions as well as running the library's testing suite. +It includes sections about upgrading from previous versions as well as running the library's testing suite and bundled +debugger. The manual is formatted as an asciidoc file - if viewing it locally, it is recommended to either use an IDE which can natively render asciidoc, or view it as html via in-browser rendering by serving it via a webserver and accessing /doc/manual/index.html diff --git a/doc/build/generate.sh b/doc/build/generate.sh index 87c6712e..1e13596c 100755 --- a/doc/build/generate.sh +++ b/doc/build/generate.sh @@ -4,16 +4,19 @@ set -e cd "$(dirname -- "$(dirname -- "${BASH_SOURCE[0]}")")" -# API docs +### API docs php ./build/vendor/bin/phpdoc run --cache-folder './build/.phpdoc' -d "$(realpath ../src/)" -t './api' --title PHP-XMLRPC --defaultpackagename PHPXMLRPC -# User Manual +### User Manual # HTML (single file) from asciidoc -asciidoctor -d book -o './manual/phpxmlrpc_manual.html' './manual/phpxmlrpc_manual.adoc' +# Not generated any more - the github rendering is good enough for online viewing, and for local viewing the html+asciidoc.js +# solution is preferred +#asciidoctor -d book -o './manual/phpxmlrpc_manual.html' './manual/phpxmlrpc_manual.adoc' # PDF file from asciidoc via docbook and apache fop +# @todo test: is it faster to use pandoc+texlive (including tools download time)? Does it render better? asciidoctor -d book -b docbook -o './build/phpxmlrpc_manual.xml' './manual/phpxmlrpc_manual.adoc' php ./build/convert.php './build/phpxmlrpc_manual.xml' './build/custom.fo.xsl' './manual/phpxmlrpc_manual.fo.xml' fop ./manual/phpxmlrpc_manual.fo.xml ./manual/phpxmlrpc_manual.pdf diff --git a/doc/manual/phpxmlrpc_manual.adoc b/doc/manual/phpxmlrpc_manual.adoc index 4cb4028b..e1177f41 100644 --- a/doc/manual/phpxmlrpc_manual.adoc +++ b/doc/manual/phpxmlrpc_manual.adoc @@ -11,50 +11,61 @@ debugger/*:: a graphical debugger which can be used to test calls to xmlrpc servers -doc/*:: the documentation, including this manual, and the list of API changes between versions 3 and 4 +demo/*:: example code for implementing both client and server functionality. Only included when installing with `--prefer-install=source` -demo/*:: example code for implementing both client and server functionality +doc/*:: the documentation, including this manual, and the list of API changes between versions 3 and 4 -extras/*:: php utility scripts, such as a benchmark suite and an environment compatibility checker +extras/*:: php utility scripts, such as a benchmark suite and an environment compatibility checker. Only included when installing with `--prefer-install=source` lib/*:: a compatibility layer for applications which still rely on version 3 of the API src/*:: the XML-RPC library classes. You can autoload these via Composer, or via a dedicated Autoloader class -tests/*:: the test suite for the library, written using PhpUnit, and the configuration to run it either on GitHub Actions or in a local Docker container +tests/*:: the test suite for the library, written using PhpUnit, and the configuration to run it in a local Docker container. Only included when installing with `--prefer-install=source` [[limitations]] == Known limitations -This started out as a bare framework. Many "nice" bits have been put in over time, but backwards compatibility has -always taken precedence over API cleanups. As such, you might find some API choices questionable. +This started out as a bare framework, a long time ago, when PHP coding practices were quite different from today's ones. +Many "nice bits" have been put in over time, but __backwards compatibility has always taken precedence over API cleanups__. +As such, you might find some API choices questionable. + +Extensions to the XMLRPC protocol, such as the `` tag, have to be manually enabled before usage. + +Very little HTTP response checking is performed (e.g. HTTP redirects are not followed by default and the Content-Length +HTTP header, mandated by the xml-rpc spec, is not validated); cookie support still involves quite a bit of coding on +the part of the user. -Specifically, very little type validation or coercion has been put in. PHP being a loosely-typed language, this is +Very little type validation or coercion has been put in. PHP being a loosely-typed language, this is going to have to be done explicitly (in other words: you can call a lot of library functions passing them arguments of the wrong type and receive an error message only much further down the code, where it will be difficult to understand). +...TODO VERIFY... dateTime.iso8601 is supported opaquely. Datetime conversion can't be done transparently as the XML-RPC specification explicitly forbids passing of timezone specifiers in ISO8601 format dates. You can, however, use the PhpXmlRpc\Helper\Date class to do the encoding and decoding for you. -Very little HTTP response checking is performed (e.g. HTTP redirects are not followed by default and the Content-Length -HTTP header, mandated by the xml-rpc spec, is not validated); cookie support still involves quite a bit of coding on -the part of the user. +Most class members have "public" access, even those only meant for internal usage. -Extensions to the XMLRPC protocol, such as the `++` tag, have to be manually enabled before usage. +There are a lot of static class variables which should be treated as if they were constants. + +A mix of snake_case and CamelCase naming is used. [[apidocs]] -== API documentation +== API usage [[types]] -=== Notes on types +=== Type conversion + +==== Notes on types +...TODO... ==== int -The type i4 is accepted as a synonym for int when creating xmlrpcval objects. The xml parsing code will always convert i4 +The type i4 is accepted as a synonym for int when creating Value objects. The xml parsing code will always convert i4 to int: int is regarded by this implementation as the canonical name for this type. The type i8 on the other hand is considered as a separate type. Note that the library will never output integers as 'i8' @@ -67,152 +78,170 @@ Therefore, you ought to consider it as a "binary" data type, for use when you wa ==== boolean -The php values `+true+` and `+1+` map to `+true+`. All other values (including the empty string) are converted to -`+false+`. +The php values `true` and `1` map to `true`. All other values (including the empty string) are converted to +`false`. ==== string Characters <, >;, ', ", &, are encoded using their entity reference as < > ' " and & All other characters outside the ASCII range are encoded using their character reference representation (e.g. -È for é). The XML-RPC spec recommends only encoding ++< >++ but this implementation goes further, for reasons +È for é). The XML-RPC spec recommends only encoding `< >` but this implementation goes further, for reasons explained by the http://www.w3.org/TR/REC-xml#syntax[XML 1.0 recommendation]. In particular, using character reference representation has the advantage of producing XML that is valid independently of the charset encoding assumed. ==== null -There is no support for encoding ++null++ values in the XML-RPC spec, but at least a couple of extensions (and -many toolkits) do support it. Before using ++null++ values in your messages, make sure that the responding party accepts +There is no support for encoding `null` values in the XML-RPC spec, but at least a couple of extensions (and +many toolkits) do support it. Before using `null` values in your messages, make sure that the responding party accepts them, and uses the same encoding convention (see ...). [[xmlrpc-value]] === Value creation -The constructor is the normal way to create an xmlrpcval. The constructor can take these forms: +The constructor is the normal way to create a Value. The constructor can take these forms: + + Value new Value + Value new Value(string $stringVal) + Value new Value(mixed $scalarVal, string $scalarTyp) + Value new Value(array $arrayVal, string $arrayTyp) -xmlrpcvalnew -xmlrpcval xmlrpcvalnew -xmlrpcval string $stringVal xmlrpcvalnew -xmlrpcval mixed $scalarVal string$scalartyp xmlrpcvalnew -xmlrpcval array $arrayVal string $arraytyp The first constructor creates an empty value, which must be - altered using the methods addScalar, - addArray or addStruct before - it can be used. +The first constructor creates an empty value, which must be altered using the methods addScalar, addArray or addStruct +before it can be used. The second constructor creates a simple string value. The third constructor is used to create a scalar value. The second parameter must be a name of an XML-RPC type. Valid -types are: "++int++", "++boolean++", "++string++", "++double++", "++dateTime.iso8601++", "++base64++" or "null". +types are: "`int`", "`boolean`", "`string`", "`double`", "`dateTime.iso8601`", "`base64`" or "null". Examples: [source, php] ---- -$myInt = new xmlrpcval(1267, "int"); -$myString = new xmlrpcval("Hello, World!", "string"); -$myBool = new xmlrpcval(1, "boolean"); -$myString2 = new xmlrpcval(1.24, "string"); // note: this will serialize a php float value as xmlrpc string +use PhpXmlRpc\Value; + +$myInt = new Value(1267, "int"); +$myString = new Value("Hello, World!", "string"); +$myBool = new Value(1, "boolean"); +$myString2 = new Value(1.24, "string"); // note: this will serialize a php float value as xmlrpc string ---- 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 array or an associative array in the case of a struct. The elements of the array __must be -xmlrpcval objects themselves__. +Value objects themselves__. -The second parameter must be either "++array++" or "++struct++". +The second parameter must be either "`array`" or "`struct`". Examples: [source, php] ---- -$myArray = new xmlrpcval( - array( - new xmlrpcval("Tom"), - new xmlrpcval("Dick"), - new xmlrpcval("Harry") - ), - "array"); +use PhpXmlRpc\Value; + +$myArray = new Value( + array( + new Value("Tom"), + new Value("Dick"), + new Value("Harry") + ), + "array" +); // recursive struct -$myStruct = new xmlrpcval( - array( - "name" => new xmlrpcval("Tom", "string"), - "age" => new xmlrpcval(34, "int"), - "address" => new xmlrpcval( - array( - "street" => new xmlrpcval("Fifht Ave", "string"), - "city" => new xmlrpcval("NY", "string") - ), - "struct") - ), - "struct"); +$myStruct = new Value( + array( + "name" => new Value("Tom", "string"), + "age" => new Value(34, "int"), + "address" => new Value( + array( + "street" => new Value("Fifht Ave", "string"), + "city" => new Value("NY", "string") + ), + "struct" + ) + ), + "struct" +); ---- -See the file ++vardemo.php++ in this distribution for more examples. +See the file `vardemo.php` in this distribution for more examples. [[xmlrpc-client]] -=== Client creation +=== Client + +==== Client creation -The constructor accepts one of two possible syntaxes: +The constructor accepts one of two possible syntax forms: -xmlrpc_clientnew -xmlrpc_clientstring$server_urlxmlrpc_clientnew -xmlrpc_clientstring$server_pathstring$server_hostnameint$server_port80string$transport'http' + Client new Client(string $server_url) + Client new Client(string $server_path, string $server_hostname, int $server_port = 80, string $transport = 'http') Here are a couple of usage examples of the first form: [source, php] ---- -$client = new xmlrpc_client("http://phpxmlrpc.sourceforge.net/server.php"); -$another_client = new xmlrpc_client("https://james:bond@secret.service.com:443/xmlrpcserver?agent=007"); +use PhpXmlRpc\Client; + +$client = new Client("http://phpxmlrpc.sourceforge.net/server.php"); +$another_client = new Client("https://james:bond@secret.service.com:443/xmlrpcserver?agent=007"); ---- The second syntax does not allow to express a username and password to be used for basic HTTP authorization as in the -second example above, but instead it allows to choose whether xmlrpc calls will be made using the HTTP 1.0 or 1.1 -protocol. +second example above, but instead it allows to choose whether xmlrpc calls will be made using the HTTP protocol version +1.0, 1.1 or 2. Here's another example client set up to query Userland's XML-RPC server at __betty.userland.com__: [source, php] ---- -$client = new xmlrpc_client("/RPC2", "betty.userland.com", 80); +use PhpXmlRpc\Client; + +$client = new Client("/RPC2", "betty.userland.com", 80); ---- -The server_port parameter is optional, and if omitted will default to 80 when using HTTP and 443 when using HTTPS. +The `$server_port` parameter is optional, and if omitted will default to '80' when using HTTP and '443' when using HTTPS or HTTP2. + +The `$transport` parameter is optional, and if omitted will default to 'http'. Allowed values are either 'http', 'https', +'http11', 'http2' or 'h2c'. Its value can be overridden with every call to the `send()` method. See the send method below +for more details about the meaning of the different values. -The transport parameter is optional, and if omitted will default to 'http'. Allowed values are either 'http', 'https' or -'http11'. Its value can be overridden with every call to the send method. See the send method below for more details -about the meaning of the different values. +==== Sending requests + +...TODO... [[xmlrpc-server]] === Server -The implementation of this class has been kept as simple to use as -possible. The constructor for the server basically does all the work. -Here's a minimal example: +The implementation of this class has been kept as simple to use as possible. The constructor for the server basically +does all the work. Here's a minimal example: [source, php] ---- - function foo ($xmlrpcmsg) { +use PhpXmlRpc\Response; +use PhpXmlRpc\Server; + +function foo($xmlrpc_request) { ... - return new xmlrpcresp($some_xmlrpc_val); - } + return new Response($some_xmlrpc_val); +} - class bar { - function foobar($xmlrpcmsg) { - ... - return new xmlrpcresp($some_xmlrpc_val); +class Bar { + function fooBar($xmlrpc_request) { + ... + return new Response($some_xmlrpc_val); } - } +} - $s = new xmlrpc_server( +$s = new Server( array( - "examples.myFunc1" => array("function" => "foo"), - "examples.myFunc2" => array("function" => "bar::foobar"), - )); + "examples.myFunc1" => array("function" => "foo"), + "examples.myFunc2" => array("function" => "Bar::fooBar"), + ) +); ---- This performs everything you need to do with a server. The single constructor argument is an associative array from xmlrpc method names to php function names. The incoming request is parsed and dispatched to the relevant php -function, which is responsible for returning a xmlrpcresp object, that will be serialized back to the caller. +function, which is responsible for returning a `Response` object, that will be serialized back to the caller. ==== Method handler functions @@ -220,17 +249,17 @@ Both php functions and class methods can be registered as xmlrpc method handlers The synopsis of a method handler function is: -xmlrpcresp $resp = function (xmlrpcmsg $msg) + Response $resp = function(Request $req) No text should be echoed 'to screen' by the handler function, or it will break the xml response sent back to the client. This applies also to error and warning messages that PHP prints to screen unless the appropriate parameters have been -set in the php.in file. Another way to prevent echoing of errors inside the response and facilitate debugging is to use -the server SetDebug method with debug level 3 (see ...). Exceptions thrown during execution of handler functions are +set in the `php.ini` file. Another way to prevent echoing of errors inside the response and facilitate debugging is to use +the server's `SetDebug` method with debug level 3 (see ...). Exceptions thrown during execution of handler functions are caught by default and a XML-RPC error response is generated instead. This behaviour can be fine-tuned by usage of the -exception_handling member variable (see ...). +`exception_handling` member variable (see ...). -Note that if you implement a method with a name prefixed by ++system.++ the handler function will be invoked by the -server with two parameters, the first being the server itself and the second being the xmlrpcmsg object. +Note that if you implement a method with a name prefixed by `system.` the handler function will be invoked by the +server with two parameters, the first being the server itself and the second being the Request object. The same php function can be registered as handler of multiple xmlrpc methods. @@ -238,9 +267,12 @@ Here is a more detailed example of what the handler function foo may do: [source, php] ---- - function foo ($xmlrpcmsg) { - global $xmlrpcerruser; // import user errcode base value +use PhpXmlRpc\PhpXmlRpc; +use PhpXmlRpc\Response; +use PhpXmlRpc\Value; +function foo ($xmlrpcmsg) +{ $meth = $xmlrpcmsg->method(); // retrieve method name $par = $xmlrpcmsg->getParam(0); // retrieve value of first parameter - assumes at least one param received $val = $par->scalarval(); // decode value of first parameter - assumes it is a scalar value @@ -248,61 +280,48 @@ Here is a more detailed example of what the handler function foo may do: ... if ($err) { - // this is an error condition - return new xmlrpcresp(0, $xmlrpcerruser+1, // user error 1 - "There's a problem, Captain"); + // this is an error condition + return new Response( + 0, + PhpXmlRpc::$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")); + // this is a successful value being returned + return new Response(new Value("All's fine!", "string")); } - } +} ---- See __server.php__ in this distribution for more examples of how to do this. -Since release 2.0RC3 there is a new, even simpler way of registering php functions with the server. See section ... -below - ==== The dispatch map -The first argument to the xmlrpc_server constructor is an array, called the __dispatch map__. +The first argument to the Server constructor is an array, called the __dispatch map__. In this array is the information the server needs to service the XML-RPC methods you define. 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: -* ++function++ - this - entry is mandatory. It must be either a name of a function in the - global scope which services the XML-RPC method, or an array - containing an instance of an object and a static method name (for - static class methods the 'class::method' syntax is also - supported). - -* ++signature++ - this - entry is an array containing the possible signatures (see <>) 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. - -* ++docstring++ - this - entry is a string containing documentation for the method. The - documentation may contain HTML markup. - -* ++$$signature_docs$$++ - this entry can be used - to provide documentation for the single parameters. It must match - in structure the 'signature' member. By default, only the - documenting_xmlrpc_server class in the - extras package will take advantage of this, since the - "system.methodHelp" protocol does not support documenting method - parameters individually. - - -* ++$$parameters_type$$++ - this entry can be used - when the server is working in 'xmlrpcvals' mode (see ...) to - define one or more entries in the dispatch map as being functions - that follow the 'phpvals' calling convention. The only useful - value is currently the string ++phpvals++. +* `function` - this entry is mandatory. It must be a callable: either a name of a function in the global scope which + services the XML-RPC method, an array containing an instance of an object and a method name, or an array containing + a class name and a static method name (for static class methods the 'class::method' syntax is also supported). + +* `signature` - this entry is an array containing the possible signatures (see <>) 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. + +* `docstring` - this entry is a string containing documentation for the method. The documentation may contain HTML + markup. + +* `signature_docs` - this entry can be used to provide documentation for the single parameters. It must match + in structure the 'signature' member. By default, only the `documenting_xmlrpc_server` class in the extras package will + take advantage of this, since the `system.methodHelp` protocol does not support documenting method parameters individually. + +* `parameters_type` - this entry can be used when the server is working in 'xmlrpcvals' mode (see ...) to define one + or more entries in the dispatch map as being functions that follow the 'phpvals' calling convention. The only useful + value is currently the string `phpvals`. Look at the __server.php__ example in the distribution to see what a dispatch map looks like. @@ -320,29 +339,34 @@ The first entry is the return type. For instance, the method string examples.getStateName(int) ---- - has the signature +has the signature [source, php] ---- -array($xmlrpcString, $xmlrpcInt) +use PhpXmlRpc\Value; + +array(Value::$xmlrpcString, Value::$xmlrpcInt) ---- and, assuming that it is the only possible signature for the method, it might be used like this in server creation: [source, php] ---- -$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 - ))); +use PhpXmlRpc\Server; +use PhpXmlRpc\Value; + +$findstate_sig = array(array(Value::$xmlrpcString, Value::$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 Server(array( + "examples.getStateName" => array( + "function" => "findstate", + "signature" => $findstate_sig, + "docstring" => $findstate_doc + ) +)); ---- Note that method signatures do not allow to check nested parameters, e.g. the number, names and types of the members of @@ -350,57 +374,62 @@ a struct param cannot be validated. If a method that you want to expose has a definite number of parameters, but each of those parameters could reasonably be of multiple types, the array of acceptable signatures will easily grow into a combinatorial explosion. To avoid such -a situation, the lib defines the global var $xmlrpcValue, which can be used in method signatures as a placeholder for -'any xmlrpc type': +a situation, the lib defines the class var `Value::$xmlrpcValue`, which can be used in method signatures as a placeholder +for 'any xmlrpc type': [source, php] ---- -$echoback_sig = array(array($xmlrpcValue, $xmlrpcValue)); +use PhpXmlRpc\Server; +use PhpXmlRpc\Value; + +$echoback_sig = array(array(Value::$xmlrpcValue, Value::$xmlrpcValue)); $findstate_doc = 'Echoes back to the client the received value, regardless of its type'; -$s = new xmlrpc_server( array( - "echoBack" => array( - "function" => "echoback", - "signature" => $echoback_sig, // this sig guarantees that the method handler will be called with one and only one parameter - "docstring" => $echoback_doc - ))); +$s = new Server(array( + "echoBack" => array( + "function" => "echoback", + "signature" => $echoback_sig, // this sig guarantees that the method handler will be called with one and only one parameter + "docstring" => $echoback_doc + ) +)); ---- -Methods system.listMethods, -system.methodHelp, -system.methodSignature and -system.multicall are already defined by the -server, and should not be reimplemented (see Reserved Methods -below). +Methods `system.listMethods`, `system.methodHelp`, `system.methodSignature` and `system.multicall` are already defined +by the server, and should not be reimplemented (see Reserved Methods below). ==== Delaying the server response You may want to construct the server, but for some reason not fulfill the request immediately (security verification, -for instance). If you omit to pass to the constructor the dispatch map or pass it a second argument of ++0++ this will -have the desired effect. You can then use the service() method of the server class to service the request. For example: +for instance). If you omit to pass to the constructor the dispatch map or pass it a second argument of `0` this will +have the desired effect. You can then use the `service` method of the server instance to service the request. For example: [source, php] ---- -$s = new xmlrpc_server($myDispMap, 0); // second parameter = 0 prevents automatic servicing of request +use PhpXmlRpc\Server; + +$s = new Server($myDispMap, 0); // second parameter = 0 prevents automatic servicing of request // ... some code that does other stuff here $s->service(); ---- -Note that the service method will print the complete result payload to screen and send appropriate HTTP headers back to +Note that the `service` method will print the complete result payload to screen and send appropriate HTTP headers back to the client, but also return the response object. This permits further manipulation of the response, possibly in combination with output buffering. To prevent the server from sending HTTP headers back to the client, you can pass a second parameter with a value of -++TRUE++ to the service method. In this case, the response payload will be returned instead of the response object. +`TRUE` to the service method (the first parameter being the payload of the incoming request; it can be left empty to +use automatically the HTTP POST body). In this case, the response payload will be returned instead of the response object. Xmlrpc requests retrieved by other means than HTTP POST bodies can also be processed. For example: [source, php] ---- -$s = new xmlrpc_server(); // not passing a dispatch map prevents automatic servicing of request +use PhpXmlRpc\Server; + +$s = new Server(); // not passing a dispatch map prevents automatic servicing of request // ... some code that does other stuff here, including setting dispatch map into server object @@ -422,138 +451,132 @@ the complete client request is added to the response, as part of the xml comments. At level 3, a new PHP error handler is set when executing user functions exposed as server methods, and all non-fatal errors are trapped and added as comments into the response. -===== allow_system_funcs +===== $allow_system_funcs -Default_value: TRUE. When set to FALSE, disables support for System.xxx functions in the server. It might be useful e.g. -if you do not wish the server to respond to requests to System.ListMethods. +Default_value: `TRUE`. When set to `FALSE`, disables support for `System.xxx` functions in the server. It might be useful e.g. +if you do not wish the server to respond to requests to `System.ListMethods`. -===== compress_response +===== $compress_response -When set to TRUE, enables the server to take advantage of HTTP compression, otherwise disables it. Responses will be +When set to `TRUE`, enables the server to take advantage of HTTP compression, otherwise disables it. Responses will be transparently compressed, but only when an xmlrpc-client declares its support for compression in the HTTP headers of the request. Note that the ZLIB php extension must be installed for this to work. If it is, compress_response will default to TRUE. -===== exception_handling +===== $exception_handling This variable controls the behaviour of the server when an exception is thrown by a method handler php function. Valid -values: 0,1,2, with 0 being the default. At level 0, the server catches the exception and return an 'internal error' -xmlrpc response; at 1 it catches the exceptions and return an xmlrpc response with the error code and error message +values: 0,1,2, with 0 being the default. At level 0, the server catches the exception and returns an 'internal error' +xmlrpc response; at 1 it catches the exception and returns an xmlrpc response with the error code and error message corresponding to the exception that was thrown; at 2 = the exception is floated to the upper layers in the code. -===== response_charset_encoding +===== $response_charset_encoding Charset encoding to be used for response (only affects string values). If it can, the server will convert the generated response from internal_encoding to the intended one. -Valid values are: a supported xml encoding (only UTF-8 and ISO-8859-1 at present, unless mbstring is enabled), null -(leave charset unspecified in response and 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 +Valid values are: a supported xml encoding (only `UTF-8` and `ISO-8859-1` at present, unless mbstring is enabled), `null` +(leave charset unspecified in response and convert output stream to US_ASCII), `default` (use xmlrpc library default as +specified in ...TODO..., 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). ==== Fault reporting -Fault codes for your servers should start at the value indicated by the global ++$xmlrpcerruser++ + 1. +Fault codes for your servers should start at the value indicated by the variable `PhpXmlRpc::$xmlrpcerruser` + 1. Standard errors returned by the server include: -++1++ Unknown method:: Returned if the server was asked to dispatch a method it - didn't know about +`1` Unknown method:: Returned if the server was asked to dispatch a method it didn't know about -++2++ Invalid return payload:: This error is actually generated by the client, not - server, code, but signifies that a server returned something it - couldn't understand. A more detailed error report is sometimes - added onto the end of the phrase above. +`2` Invalid return payload:: This error is actually generated by the client, not server, code, but signifies that a + server returned something it couldn't understand. A more detailed error report is sometimes added onto the end of + the phrase above. -++3++ Incorrect parameters:: 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. +`3` Incorrect parameters:: 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. -++4++ Can't introspect: method unknown:: This error is generated by the builtin - system.* methods when any kind of - introspection is attempted on a method undefined by the - server. +`4` Can't introspect: method unknown:: This error is generated by the builtin system.* methods when any kind of + introspection is attempted on a method undefined by the server. -++5++ Didn't receive 200 OK from remote server:: 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. +`5` Didn't receive 200 OK from remote server:: 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. -++6++ No data received from server:: This error is generated by the client when a remote server - returns HTTP/1.1 200 OK in response to a request, but no - response body follows the HTTP headers. +`6` No data received from server:: This error is generated by the client when a remote server returns HTTP/1.1 200 OK in + response to a request, but no response body follows the HTTP headers. -++7++ No SSL support compiled in:: This error is generated by the client when trying to send - a request with HTTPS and the CURL extension is not available to - PHP. +`7` No SSL support compiled in:: This error is generated by the client when trying to send a request with HTTPS and the + CURL extension is not available to PHP. -++8++ CURL error:: This error is generated by the client when trying to send - a request with HTTPS and the HTTPS communication fails. +`8` CURL error:: This error is generated by the client when trying to send a request with HTTPS and the HTTPS + communication fails. -++9-14++ multicall errors:: These errors are generated by the server when something - fails inside a system.multicall request. +`9-14` multicall errors:: These errors are generated by the server when something fails inside a system.multicall request. -++100-++ XML parse errors:: Returns 100 plus the XML parser error code for the fault - that occurred. The faultString returned - explains where the parse error was in the incoming XML - stream. +`100-` XML parse errors:: Returns 100 plus the XML parser error code for the fault that occurred. The faultString returned + explains where the parse error was in the incoming XML stream. ==== 'New style' servers -In the same spirit of simplification that inspired the xmlrpc_client::return_type class variable, a new class variable -has been added to the server class: functions_parameters_type. When set to 'phpvals', the functions registered in the -server dispatch map will be called with plain php values as parameters, instead of a single xmlrpcmsg instance parameter. +In the same spirit of simplification that inspired the `Client::$return_type` class variable, a new class variable +has been added to the server class: `$functions_parameters_type`. When set to `phpvals`, the functions registered in the +server dispatch map will be called with plain php values as parameters, instead of a single Request instance parameter. The return value of those functions is expected to be a plain php value, too. An example is worth a thousand words: [source, php] ---- - function foo($usr_id, $out_lang='en') { +use PhpXmlRpc\Response; +use PhpXmlRpc\Server; +use PhpXmlRpc\Value; + +function foo($usr_id, $out_lang='en') +{ global $xmlrpcerruser; ... if ($someErrorCondition) - return new xmlrpcresp(0, $xmlrpcerruser+1, 'DOH!'); + return new Response(0, $xmlrpcerruser+1, 'DOH!'); else - return array( - 'name' => 'Joe', - 'age' => 27, - 'picture' => new xmlrpcval(file_get_contents($picOfTheGuy), 'base64') - ); - } - - $s = new xmlrpc_server( + return array( + 'name' => 'Joe', + 'age' => 27, + 'picture' => new Value(file_get_contents($picOfTheGuy), 'base64') + ); +} + +$s = new Server( array( - "examples.myFunc" => array( - "function" => "bar::foobar", - "signature" => array( - array($xmlrpcString, $xmlrpcInt), - array($xmlrpcString, $xmlrpcInt, $xmlrpcString) + "examples.myFunc" => array( + "function" => "foo", + "signature" => array( + array($xmlrpcString, $xmlrpcInt), + array($xmlrpcString, $xmlrpcInt, $xmlrpcString) + ) ) - ) - ), false); - $s->functions_parameters_type = 'phpvals'; - $s->service(); + ), +false); +$s->functions_parameters_type = 'phpvals'; +$s->service(); ---- There are a few things to keep in mind when using this simplified syntax: -to return an xmlrpc error, the method handler function must return an instance of xmlrpcresp. The only -other way for the server to know when an error response should be served to the client is to throw an exception and set -the server's exception_handling member var to 1; +to return an xmlrpc error, the method handler function must return an instance of Response. The only other way for the +server to know when an error response should be served to the client is to throw an exception and set the server's +`exception_handling` member var to 1; -to return a base64 value, the method handler function must encode it on its own, creating an instance of an xmlrpcval +to return a base64 value, the method handler function must encode it on its own, creating an instance of a Value object; the method handler function cannot determine the name of the xmlrpc method it is serving, unlike standard handler -functions that can retrieve it from the message object; +functions that can retrieve it from the Request object; when receiving nested parameters, the method handler function has no way to distinguish a php string that was sent as base64 value from one that was sent as a string value; -this has a direct consequence on the support of system.multicall: a method whose signature contains datetime or base64 +this has a direct consequence on the support of `system.multicall`: a method whose signature contains datetime or base64 values will not be available to multicall calls; last but not least, the direct parsing of xml to php values is much faster than using xmlrpcvals, and allows the library @@ -565,15 +588,17 @@ to handle much bigger messages without allocating all available server memory or In order to extend the functionality offered by XML-RPC servers without impacting on the protocol, reserved methods are supported. -All methods starting with system. are considered reserved by the server. PHP for XML-RPC itself provides four +All methods starting with __system.__ are considered reserved by the server. PHP for XML-RPC itself provides four special methods, detailed in this chapter. Note that all server objects will automatically respond to clients querying these methods, unless the property -allow_system_funcs has been set to false before calling the service() method. This might pose a security risk +`allow_system_funcs` has been set to false before calling the `service()` method. This might pose a security risk if the server is exposed to public access, e.g. on the internet. ==== system.getCapabilities +... + ==== system.listMethods This method may be used to enumerate the methods implemented by the XML-RPC server. @@ -589,14 +614,14 @@ This method takes one parameter, the name of a method implemented by the XML-RPC 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. -Multiple signatures (i.e. overloading) are permitted: this is the reason that an array of signatures are returned by this +Multiple signatures (i.e. overloading) are permitted: this is the reason that an array of signatures is returned by this method. 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". +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". -For parameters that can be of more than one type, the "undefined" string is supported. +For parameters that can be of more than one type, the `undefined` string is supported. If no signature is defined for the method, a not-array value is returned. Therefore, this is the way to test for a non-signature, if $resp below is the response object from a method call to system.methodSignature: @@ -605,7 +630,7 @@ non-signature, if $resp below is the response object from a method call to syste ---- $v = $resp->value(); if ($v->kindOf() != "array") { - // then the method did not have a signature defined + // then the method did not have a signature defined } ---- @@ -623,135 +648,121 @@ The documentation string may contain HTML markup. ==== system.multicall -This method takes one parameter, an array of 'request' struct types. Each request struct must contain a methodName -member of type string and a params member of type array, and corresponds to the invocation of the corresponding method. +This method takes one parameter, an array of 'request' struct types. Each request struct must contain a `methodName` +member of type string and a `params` member of type array, and corresponds to the invocation of the corresponding method. -It returns a response of type array, with each value of the array being either an error struct (containing the faultCode -and faultString members) or the successful response value of the corresponding single method call. +It returns a response of type array, with each value of the array being either an error struct (containing the `faultCode` +and `faultString` members) or the successful response value of the corresponding single method call. [[globalvars]] -=== Global variables +=== Static class variables -Many global variables are defined in the xmlrpc.inc file. Some of -those are meant to be used as constants (and modifying their value might -cause unpredictable behaviour), while some others can be modified in your -php scripts to alter the behaviour of the xml-rpc client and -server. +Many static variables are defined in the `PhpxmlRpc\PhpXmlRpc` and other classes. Some of those are meant to be used as +constants (and modifying their value might cause unpredictable behaviour), while some others can be modified in your +php scripts to alter the behaviour of the xml-rpc client and server. ==== "Constant" variables ===== $xmlrpcerruser -$xmlrpcerruser800The minimum value for errors reported by user -implemented XML-RPC servers. Error numbers lower than that are -reserved for library usage. + PhpxmlRpc\PhpXmlRpc::$xmlrpcerruser = 800 + +The minimum value for errors reported by user implemented XML-RPC servers. Error numbers lower than that are reserved +for library usage. ===== $xmlrpcI4, $xmlrpcI8 $xmlrpcInt, $xmlrpcBoolean, $xmlrpcDouble, $xmlrpcString, $xmlrpcDateTime, $xmlrpcBase64, $xmlrpcArray, $xmlrpcStruct, $xmlrpcValue, $xmlrpcNull -For convenience the strings representing the XML-RPC types have been encoded as global variables: +For convenience the strings representing the XML-RPC types have been encoded as static class variables of `PhpxmlRpc\Value`: + [source, php] ---- -$xmlrpcI4="i4"; -$xmlrpcI8="i8"; -$xmlrpcInt="int"; -$xmlrpcBoolean="boolean"; -$xmlrpcDouble="double"; -$xmlrpcString="string"; -$xmlrpcDateTime="dateTime.iso8601"; -$xmlrpcBase64="base64"; -$xmlrpcArray="array"; -$xmlrpcStruct="struct"; -$xmlrpcValue="undefined"; -$xmlrpcNull="null"; +Value::$xmlrpcI4 = "i4"; +Value::$xmlrpcI8 = "i8"; +Value::$xmlrpcInt = "int"; +Value::$xmlrpcBoolean = "boolean"; +Value::$xmlrpcDouble = "double"; +Value::$xmlrpcString = "string"; +Value::$xmlrpcDateTime = "dateTime.iso8601"; +Value::$xmlrpcBase64 = "base64"; +Value::$xmlrpcArray = "array"; +Value::$xmlrpcStruct = "struct"; +Value::$xmlrpcValue = "undefined"; +Value::$xmlrpcNull = "null"; ---- -===== $xmlrpcTypes, $xmlrpc_valid_parents, $xmlrpcerr, $xmlrpcstr, $xmlrpcerrxml, $xmlrpc_backslash, $_xh, $xml_iso88591_Entities, $xmlEntities, $xmlrpcs_capabilities - -Reserved for internal usage. - ==== Variables whose value can be modified [[xmlrpc-defencoding]] ===== xmlrpc_defencoding -$xmlrpc_defencoding"UTF8"This variable defines the character set encoding that will be -used by the xml-rpc client and server to decode the received messages, -when a specific charset declaration is not found (in the messages sent -non-ascii chars are always encoded using character references, so that -the produced xml is valid regardless of the charset encoding -assumed). + PhpxmlRpc\PhpXmlRpc::$xmlrpc_defencoding = "UTF8" -Allowed values: ++"UTF8"++, ++"ISO-8859-1"++, ++"ASCII".++ +This variable defines the character set encoding that will be used by the xml-rpc client and server to decode the +received messages, when a specific charset declaration is not found (in the messages sent non-ascii chars are always +encoded using character references, so that the produced xml is valid regardless of the charset encoding assumed). -Note that the appropriate RFC actually mandates that XML -received over HTTP without indication of charset encoding be treated -as US-ASCII, but many servers and clients 'in the wild' violate the -standard, and assume the default encoding is UTF-8. +Allowed values: 'UTF8', 'ISO-8859-1', 'ASCII'. + +Note that the appropriate RFC actually mandates that XML received over HTTP without indication of charset encoding be +treated as US-ASCII, but many servers and clients 'in the wild' violate the standard, and assume the default encoding is +UTF-8. ===== xmlrpc_internalencoding -$xmlrpc_internalencoding"ISO-8859-1"This variable defines the character set encoding -that the library uses to transparently encode into valid XML the -xml-rpc values created by the user and to re-encode the received -xml-rpc values when it passes them to the PHP application. It only -affects xml-rpc values of string type. It is a separate value from -xmlrpc_defencoding, allowing e.g. to send/receive xml messages encoded -on-the-wire in US-ASCII and process them as UTF-8. It defaults to the -character set used internally by PHP (unless you are running an -MBString-enabled installation), so you should change it only in -special situations, if e.g. the string values exchanged in the xml-rpc -messages are directly inserted into / fetched from a database -configured to return UTF8 encoded strings to PHP. Example + PhpxmlRpc\PhpXmlRpc::$xmlrpc_internalencoding = "UTF-8" + +This variable defines the character set encoding that the library uses to transparently encode into valid XML the +xml-rpc values created by the user and to re-encode the received xml-rpc values when it passes them to the PHP application. +It only affects xml-rpc values of string type. It is a separate value from xmlrpc_defencoding, allowing e.g. to send/receive +xml messages encoded on-the-wire in US-ASCII and process them as UTF-8. It defaults to the character set used internally +by PHP (unless you are running an MBString-enabled installation), so you should change it only in special situations, if +e.g. the string values exchanged in the xml-rpc messages are directly inserted into / fetched from a database +configured to return non-UTF8 encoded strings to PHP. Example usage: [source, php] ---- - (and ) xmlrpc value, as -per the extension to the standard proposed here. This means that - and tags received will be parsed as valid -xmlrpc, and the corresponding xmlrpcvals will return "null" for -scalarTyp(). + PhpxmlRpc\PhpXmlRpc::$xmlrpc_null_extension = FALSE + +When set to `TRUE`, the lib will enable support for the `` (and ``) xmlrpc value, as per the extension to +the standard proposed here. This means that `` and `` tags received will be parsed as valid +xmlrpc, and the corresponding xmlrpcvals will return "null" for scalarTyp(). ===== xmlrpc_null_apache_encoding -When set to ++TRUE++, php NULL values encoded -into xmlrpcval objects get serialized using the -++++ tag instead of -++++. Please note that both forms are -always accepted as input regardless of the value of this -variable. + PhpxmlRpc\PhpXmlRpc::$$xmlrpc_null_apache_encoding = FALSE + +When set to `TRUE`, php NULL values encoded into Value objects will get serialized using the `` tag instead of +``. Please note that both forms are always accepted as input regardless of the value of this variable. [[helpers]] === Helper functions -XML-RPC for PHP contains some helper functions which you can use to -make processing of XML-RPC requests easier. +XML-RPC for PHP contains some helper functions which you can use to make processing of XML-RPC requests easier. ==== Date functions @@ -759,171 +770,153 @@ The XML-RPC specification has this to say on dates: [quote] ____ -[[wrap_xmlrpc_method]] -Don't assume a timezone. It should be -specified by the server in its documentation what assumptions it makes -about timezones. +Don't assume a timezone. It should be specified by the server in its documentation what assumptions it makes about +timezones. ____ -Unfortunately, this means that date processing isn't -straightforward. Although XML-RPC uses ISO 8601 format dates, it doesn't -use the timezone specifier. +Unfortunately, this means that date processing isn't straightforward. Although XML-RPC uses ISO 8601 format dates, it +doesn't use the timezone specifier. -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. +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. -For more information about dates, see link:$$http://www.uic.edu/year2000/datefmt.html$$[ISO 8601: The Right Format for Dates], 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. +For more information about dates, see http://www.uic.edu/year2000/datefmt.html[ISO 8601: The Right Format for Dates], +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`. [[iso8601encode]] ===== iso8601_encode -stringiso8601_encodestring$time_tint$utc0Returns an ISO 8601 formatted date generated from the UNIX -timestamp $time_t, as returned by the PHP -function time(). + string iso8601_encode(string $time_t, int $utc = 0) -The argument $utc can be omitted, in -which case it defaults to ++0++. If it is set to -++1++, then the function corrects the time passed in -for UTC. Example: if you're in the GMT-6:00 timezone and set -$utc, you will receive a date representation +Returns an ISO 8601 formatted date generated from the UNIX timestamp $time_t, as returned by the PHP function `time()`. + +The argument $utc can be omitted, in which case it defaults to `0`. If it is set to `1`, then the function corrects the +time passed in for UTC. Example: if you're in the GMT-6:00 timezone and set $utc, you will receive a date representation six hours ahead of your local time. -The included demo program __vardemo.php__ -includes a demonstration of this function. +The included demo program __vardemo.php__ includes a demonstration of this function. [[iso8601decode]] ===== iso8601_decode -intiso8601_decodestring$isoStringint$utc0Returns a UNIX timestamp from an ISO 8601 encoded time and date -string passed in. If $utc is -++1++ then $isoString is assumed -to be in the UTC timezone, and thus the result is also UTC: otherwise, -the timezone is assumed to be your local timezone and you receive a -local timestamp. + int iso8601_decode(string $isoString, int $utc = 0) + +Returns a UNIX timestamp from an ISO 8601 encoded time and date string passed in. If $utc is `1` then $isoString is assumed +to be in the UTC timezone, and thus the result is also UTC: otherwise, the timezone is assumed to be your local timezone +and you receive a local timestamp. [[arrayuse]] ==== Easy use with nested PHP values -Dan Libby was kind enough to contribute two helper functions that -make it easier to translate to and from PHP values. This makes it easier -to deal with complex structures. At the moment support is limited to -int, double, string, -array, datetime and struct -datatypes; note also that all PHP arrays are encoded as structs, except -arrays whose keys are integer numbers starting with 0 and incremented by -1. +Dan Libby was kind enough to contribute two helper functions that make it easier to translate to and from PHP values. +This makes it easier to deal with complex structures. At the moment support is limited to int, double, string, +array, datetime and struct datatypes; note also that all PHP arrays are encoded as structs, except arrays whose keys are +integer numbers starting with 0 and incremented by 1. These functions reside in __xmlrpc.inc__. [[phpxmlrpcdecode]] ===== php_xmlrpc_decode -mixedphp_xmlrpc_decodexmlrpcval$xmlrpc_valarray$optionsarrayphp_xmlrpc_decodexmlrpcmsg$xmlrpcmsg_valstring$optionsReturns a native PHP value corresponding to the values found in -the xmlrpcval $xmlrpc_val, -translated into PHP types. Base-64 and datetime values are -automatically decoded to strings. - -In the second form, returns an array containing the parameters -of the given -xmlrpcmsg_val, decoded -to php types. - -The options parameter is optional. If -specified, it must consist of an array of options to be enabled in the -decoding process. At the moment the only valid option are -decode_php_objs and -++$$dates_as_objects$$++. When the first is set, php -objects that have been converted to xml-rpc structs using the -php_xmlrpc_encode function and a corresponding -encoding option will be converted back into object values instead of -arrays (provided that the class definition is available at -reconstruction time). When the second is set, XML-RPC datetime values -will be converted into native dateTime objects -instead of strings. - -____WARNING__:__ please take -extreme care before enabling the decode_php_objs -option: when php objects are rebuilt from the received xml, their -constructor function will be silently invoked. This means that you are -allowing the remote end to trigger execution of uncontrolled PHP code -on your server, opening the door to code injection exploits. Only -enable this option when you have complete trust of the remote -server/client. + mixed php_xmlrpc_decode(Value $xmlrpc_val, array $options) + array php_xmlrpc_decode(xmlrpcmsg $xmlrpcmsg_val, string $options) + +Returns a native PHP value corresponding to the values found in the Value $xmlrpc_val, translated into PHP types. Base-64 +and datetime values are automatically decoded to strings. + +In the second form, returns an array containing the parameters of the given xmlrpcmsg_val, decoded to php types. + +The options parameter is optional. If specified, it must consist of an array of options to be enabled in the decoding +process. At the moment the only valid option are decode_php_objs and `dates_as_objects`. When the first is set, php +objects that have been converted to xml-rpc structs using the php_xmlrpc_encode function and a corresponding +encoding option will be converted back into object values instead of arrays (provided that the class definition is +available at reconstruction time). When the second is set, XML-RPC datetime values will be converted into native dateTime +objects instead of strings. + +____WARNING__:__ please take extreme care before enabling the decode_php_objs option: when php objects are rebuilt from +the received xml, their constructor function will be silently invoked. This means that you are allowing the remote end +to trigger execution of uncontrolled PHP code on your server, opening the door to code injection exploits. Only +enable this option when you have complete trust of the remote server/client. Example: [source, php] ---- +use PhpXmlRpc\Response; +use PhpXmlRpc\Server; +use PhpXmlRpc\Value; + // wrapper to expose an existing php function as xmlrpc method handler function foo_wrapper($m) { - $params = php_xmlrpc_decode($m); - $retval = call_user_func_array('foo', $params); - return new xmlrpcresp(new xmlrpcval($retval)); // foo return value will be serialized as string + $params = php_xmlrpc_decode($m); + $retval = call_user_func_array('foo', $params); + return new Response(new Value($retval)); // foo return value will be serialized as string } -$s = new xmlrpc_server(array( - "examples.myFunc1" => array( - "function" => "foo_wrapper", - "signatures" => ... - ))); +$s = new Server(array( + "examples.myFunc1" => array( + "function" => "foo_wrapper", + "signatures" => ... + ) +)); ---- [[phpxmlrpcencode]] ===== php_xmlrpc_encode -xmlrpcvalphp_xmlrpc_encodemixed$phpvalarray$optionsReturns an xmlrpcval object populated with the PHP + Value php_xmlrpc_encode(mixed $phpval, array $options) + +Returns a Value object populated with the PHP values in $phpval. Works recursively on arrays and objects, encoding numerically indexed php arrays into array-type -xmlrpcval objects and non numerically indexed php arrays into -struct-type xmlrpcval objects. Php objects are encoded into +Value objects and non numerically indexed php arrays into +struct-type Value objects. Php objects are encoded into struct-type xmlrpcvals, excepted for php values that are already -instances of the xmlrpcval class or descendants thereof, which will +instances of the Value class or descendants thereof, which will not be further encoded. Note that there's no support for encoding php values into base-64 values. Encoding of date-times is optionally carried on on php strings with the correct format. -The options parameter is optional. If -specified, it must consist of an array of options to be enabled in the -encoding process. At the moment the only valid options are -encode_php_objs, ++$$null_extension$$++ -and auto_dates. +The options parameter is optional. If specified, it must consist of an array of options to be enabled in the +encoding process. At the moment the only valid options are encode_php_objs, `null_extension` and auto_dates. -The first will enable the creation of 'particular' xmlrpcval +The first will enable the creation of 'particular' Value objects out of php objects, that add a "php_class" xml attribute to their serialized representation. This attribute allows the function php_xmlrpc_decode to rebuild the native php objects (provided that the same class definition exists on both sides of the communication). The -second allows to encode php ++NULL++ values to the -++++ (or -++++, see ...) tag. The last encodes any +second allows to encode php `NULL` values to the +`` (or +``, see ...) tag. The last encodes any string that matches the ISO8601 format into an XML-RPC datetime. Example: [source, php] ---- +use PhpXmlRpc\Server; + // the easy way to build a complex xml-rpc struct, showing nested base64 value and datetime values -$val = php_xmlrpc_encode(array( - 'first struct_element: an int' => 666, - 'second: an array' => array ('apple', 'orange', 'banana'), - 'third: a base64 element' => new xmlrpcval('hello world', 'base64'), - 'fourth: a datetime' => '20060107T01:53:00' - ), array('auto_dates')); +$val = php_xmlrpc_encode( + array( + 'first struct_element: an int' => 666, + 'second: an array' => array ('apple', 'orange', 'banana'), + 'third: a base64 element' => new Value('hello world', 'base64'), + 'fourth: a datetime' => '20060107T01:53:00' + ), + array('auto_dates') +); ---- ===== php_xmlrpc_decode_xml -xmlrpcval | xmlrpcresp | - xmlrpcmsgphp_xmlrpc_decode_xmlstring$xmlarray$optionsDecodes the xml representation of either an xmlrpc request, - response or single value, returning the corresponding php-xmlrpc - object, or ++FALSE++ in case of an error. + Value | Response | xmlrpcmsg php_xmlrpc_decode_xml(string $xml, array $options) + +Decodes the xml representation of either an xmlrpc request, response or single value, returning the corresponding +php-xmlrpc object, or `FALSE` in case of an error. -The options parameter is optional. If -specified, it must consist of an array of options to be enabled in the +The options parameter is optional. If specified, it must consist of an array of options to be enabled in the decoding process. At the moment, no option is supported. Example: @@ -941,48 +934,42 @@ that allow to convert a php function into an xmlrpc method, and a remotely exposed xmlrpc method into a local php function - or a set of methods into a php class. Note that these comes with many caveat. +[[wrap_xmlrpc_method]] ===== wrap_xmlrpc_method -stringwrap_xmlrpc_method$client$methodname$extra_optionsstringwrap_xmlrpc_method$client$methodname$signum$timeout$protocol$funcnameGiven an xmlrpc server and a method name, creates a php wrapper + string wrap_xmlrpc_method($client, $methodname, $extra_options) + string wrap_xmlrpc_method($client, $methodname, $signum, $timeout, $protocol, $funcname) + +Given an xmlrpc server and a method name, creates a php wrapper function that will call the remote method and return results using native php types for both params and results. The generated php -function will return an xmlrpcresp object for failed xmlrpc +function will return an Response object for failed xmlrpc calls. -The second syntax is deprecated, and is listed here only for -backward compatibility. +The second syntax is deprecated, and is listed here only for backward compatibility. -The server must support the -system.methodSignature xmlrpc method call for -this function to work. +The server must support the system.methodSignature xmlrpc method call for this function to work. -The client param must be a valid -xmlrpc_client object, previously created with the address of the -target xmlrpc server, and to which the preferred communication options -have been set. +The client param must be a valid Client object, previously created with the address of the target xmlrpc server, and to +which the preferred communication options have been set. -The optional parameters can be passed as array key,value pairs -in the extra_options param. +The optional parameters can be passed as array key,value pairs in the extra_options param. The signum optional param has the purpose of indicating which method signature to use, if the given server method has multiple signatures (defaults to 0). -The timeout and -protocol optional params are the same as in the -xmlrpc_client::send() method. +The timeout and protocol optional params are the same as in the Client::send() method. -If set, the optional new_function_name -parameter indicates which name should be used for the generated -function. In case it is not set the function name will be -auto-generated. +If set, the optional new_function_name parameter indicates which name should be used for the generated function. In case +it is not set the function name will be auto-generated. -If the ++$$return_source$$++ optional parameter is +If the `return_source` optional parameter is set, the function will return the php source code to build the wrapper function, instead of evaluating it (useful to save the code and use it later as stand-alone xmlrpc client). -If the ++$$encode_php_objs$$++ optional parameter is +If the `encode_php_objs` optional parameter is set, instances of php objects later passed as parameters to the newly created function will receive a 'special' treatment that allows the server to rebuild them as php objects instead of simple arrays. Note @@ -990,7 +977,7 @@ that this entails using a "slightly augmented" version of the xmlrpc protocol (ie. using element attributes), which might not be understood by xmlrpc servers implemented using other libraries. -If the ++$$decode_php_objs$$++ optional parameter is +If the `decode_php_objs` optional parameter is set, instances of php objects that have been appropriately encoded by the server using a coordinate option will be deserialized as php objects instead of simple arrays (the same class definition should be @@ -1025,66 +1012,61 @@ Example usage: [source, php] ---- -$c = new xmlrpc_client('http://phpxmlrpc.sourceforge.net/server.php'); +use PhpXmlRpc\Client; + +$c = new Client('http://phpxmlrpc.sourceforge.net/server.php'); $function = wrap_xmlrpc_method($client, 'examples.getStateName'); if (!$function) - die('Cannot introspect remote method'); + die('Cannot introspect remote method'); else { - $stateno = 15; - $statename = $function($a); - if (is_a($statename, 'xmlrpcresp')) // call failed - { - echo 'Call failed: '.$statename->faultCode().'. Calling again with debug on'; - $function($a, true); - } - else - echo "OK, state nr. $stateno is $statename"; + $stateno = 15; + $statename = $function($a); + // NB: in real life, you should make sure you escape the received data with `htmlspecialchars` when echoing it as html + if (is_a($statename, 'Response')) { // call failed + echo 'Call failed: '.$statename->faultCode().'. Calling again with debug on'; + $function($a, true); + } + else + echo "OK, state nr. $stateno is $statename"; } ---- [[wrap_php_function]] ===== wrap_php_function -arraywrap_php_functionstring$funcnamestring$wrapper_function_namearray$extra_optionsGiven a user-defined PHP function, -create a PHP 'wrapper' -function that can be exposed as xmlrpc method from an xmlrpc_server -object and called from remote clients, and return the appropriate -definition to be added to a server's dispatch map. + array wrap_php_function(string $funcname, string $wrapper_function_name, array $extra_options) -The optional $wrapper_function_name -specifies the name that will be used for the auto-generated -function. +Given a user-defined PHP function, create a PHP 'wrapper' function that can be exposed as xmlrpc method from a Server +object and called from remote clients, and return the appropriate definition to be added to a server's dispatch map. + +The optional $wrapper_function_name specifies the name that will be used for the auto-generated function. -Since php is a typeless language, to infer types of input and -output parameters, it relies on parsing the javadoc-style comment -block associated with the given function. Usage of xmlrpc native types -(such as datetime.dateTime.iso8601 and base64) in the docblock @param -tag is also allowed, if you need the php function to receive/send data -in that particular format (note that base64 encoding/decoding is -transparently carried out by the lib, while datetime vals are passed +Since php is a typeless language, to infer types of input and output parameters, it relies on parsing the javadoc-style +comment block associated with the given function. Usage of xmlrpc native types (such as datetime.dateTime.iso8601 and +base64) in the docblock @param tag is also allowed, if you need the php function to receive/send data in that particular +format (note that base64 encoding/decoding is transparently carried out by the lib, while datetime vals are passed around as strings). -Known limitations: only works for -user-defined functions, not for PHP internal functions (reflection +Known limitations: only works for user-defined functions, not for PHP internal functions (reflection does not support retrieving number/type of params for those); the wrapped php function will not be able to programmatically return an xmlrpc error response. -If the ++$$return_source$$++ optional parameter is +If the `return_source` optional parameter is set, the function will return the php source code to build the wrapper function, instead of evaluating it (useful to save the code and use it later in a stand-alone xmlrpc server). It will be in the stored in the -++source++ member of the returned array. +`source` member of the returned array. -If the ++$$suppress_warnings$$++ optional parameter +If the `suppress_warnings` optional parameter is set, any runtime warning generated while processing the user-defined php function will be caught and not be printed in the generated xml response. If the extra_options array contains the -++$$encode_php_objs$$++ value, wrapped functions returning +`encode_php_objs` value, wrapped functions returning php objects will generate "special" xmlrpc responses: when the xmlrpc decoding of those responses is carried out by this same lib, using the appropriate param in php_xmlrpc_decode(), the objects will be @@ -1095,7 +1077,7 @@ resource members), using this function. Other libs might choke on the very same xml that will be generated in this case (i.e. it has a nonstandard attribute on struct element tags) -If the ++$$decode_php_objs$$++ optional parameter is +If the `decode_php_objs` optional parameter is set, instances of php objects that have been appropriately encoded by the client using a coordinate option will be deserialized and passed to the user function as php objects instead of simple arrays (the same @@ -1113,6 +1095,8 @@ Example usage: [source, php] ---- +use PhpXmlRpc\Server; + /** * State name from state number decoder. NB: do NOT remove this comment block. * @param integer $stateno the state number @@ -1120,23 +1104,23 @@ Example usage: */ function findstate($stateno) { - global $stateNames; - if (isset($stateNames[$stateno-1])) - { - return $stateNames[$stateno-1]; - } - else - { - return "I don't have a state for the index '" . $stateno . "'"; - } + global $stateNames; + if (isset($stateNames[$stateno-1])) + { + return $stateNames[$stateno-1]; + } + else + { + return "I don't have a state for the index '" . $stateno . "'"; + } } // wrap php function, build xmlrpc server $methods = array(); $findstate_sig = wrap_php_function('findstate'); if ($findstate_sig) - $methods['examples.getStateName'] = $findstate_sig; -$srv = new xmlrpc_server($methods); + $methods['examples.getStateName'] = $findstate_sig; +$srv = new Server($methods); ---- [[debugging]] @@ -1144,13 +1128,12 @@ $srv = new xmlrpc_server($methods); ==== xmlrpc_debugmsg -void xmlrpc_debugmsgstring$debugstringSends the contents of $debugstring 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. + void xmlrpc_debugmsg(string $debug) + +Sends the contents of $debugstring 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. -Use this function in your methods so you can pass back -diagnostic information. It is only available from +Use this function in your methods so you can pass back diagnostic information. It is only available from __xmlrpcs.inc__. [[enough]] @@ -1158,75 +1141,163 @@ __xmlrpcs.inc__. To be documented... -In the meantime, see docs about xmlrpc_client::return_type and -xmlrpc_server::functions_parameters_types, as well as php_xmlrpc_encode, +In the meantime, see docs about Client::return_type and Server::functions_parameters_types, as well as php_xmlrpc_encode, php_xmlrpc_decode and php_xmlrpc_decode_xml [[examples]] === Examples -The best examples are to be found in the sample files included with - the distribution. Some are included here. +The best examples are to be found in the sample files included with the distribution. Some are included here. [[statename]] ==== XML-RPC client: state name query -Code to get the corresponding state name from a number (1-50) from - the demo server available on SourceForge +Code to get the corresponding state name from a number (1-50) from the demo server available on SourceForge [source, php] ---- - $m = new xmlrpcmsg('examples.getStateName', - array(new xmlrpcval($HTTP_POST_VARS["stateno"], "int"))); - $c = new xmlrpc_client("/server.php", "phpxmlrpc.sourceforge.net", 80); - $r = $c->send($m); - if (!$r->faultCode()) { - $v = $r->value(); - print "State number " . htmlentities($HTTP_POST_VARS["stateno"]) . " is " . +use PhpXmlRpc\Client; +use PhpXmlRpc\Request; +use PhpXmlRpc\Value; + +$m = new Request('examples.getStateName', array(new Value((int)$_POST["stateno"], "int"))); +$c = new Client("/server.php", "phpxmlrpc.sourceforge.net", 80); +$r = $c->send($m); +if (!$r->faultCode()) { + $v = $r->value(); + print "State number " . htmlentities($_POST["stateno"]) . " is " . htmlentities($v->scalarval()) . "
"; - print "
I got this value back
" .
+    print "
I got this value back
" .
         htmlentities($r->serialize()) . "

\n"; - } else { - print "Fault
"; - print "Code: " . htmlentities($r->faultCode()) . "
" . - "Reason: '" . htmlentities($r->faultString()) . "'
"; - } +} else { + print "Fault
"; + print "Code: " . htmlentities($r->faultCode()) . "
" . + "Reason: '" . htmlentities($r->faultString()) . "'
"; +} ---- ==== Executing a multicall call To be documented... + +== Upgrading + +If you are upgrading to version 4 from version 3 or earlier you have two options: + +1. adapt your code to the new API (all changes needed are described in https://github.com/gggeek/phpxmlrpc/blob/master/doc/api_changes_v4.md) + +2. use instead the *compatibility layer* which is provided. Instructions and pitfalls described at https://github.com/gggeek/phpxmlrpc/blob/master/doc/api_changes_v4.md#enabling-compatibility-with-legacy-code + +In any case, read carefully the docs available online and report back any undocumented issue using GitHub. + [[deprecated]] === Removed from the library -The following two functions have been deprecated in version 1.1 of -the library, and removed in version 2, in order to avoid conflicts with -the EPI xml-rpc library, which also defines two functions with the same -names. +The following two functions have been deprecated in version 1.1 of the library, and removed in version 2, in order to +avoid conflicts with the PHP xml-rpc extension, which also defines two functions with the same names. -To ease the transition to the new naming scheme and avoid breaking -existing implementations, the following scheme has been adopted: +To ease the transition to the new naming scheme and avoid breaking existing implementations, the following scheme has +been adopted: -* If EPI-XMLRPC is not active in the current PHP installation, -the constant `+XMLRPC_EPI_ENABLED+` will be set to '0' +* If EPI-XMLRPC is not active in the current PHP installation, the constant `XMLRPC_EPI_ENABLED` will be set to '0' -* If EPI-XMLRPC is active in the current PHP installation, the -constant `+XMLRPC_EPI_ENABLED+` will be set to '1' +* If EPI-XMLRPC is active in the current PHP installation, the constant `XMLRPC_EPI_ENABLED` will be set to '1' -The following documentation is kept for historical -reference: +The following documentation is kept for historical reference: [[xmlrpcdecode]] ==== xmlrpc_decode -mixedx mlrpc_decode xmlrpcval $xmlrpc_val Alias for php_xmlrpc_decode. + mixed mlrpc_decode(Value $xmlrpc_val) + +Alias for `php_xmlrpc_decode`. [[xmlrpcencode]] ==== xmlrpc_encode -xmlrpcval xmlrpc_encode mixed $phpvalAlias for php_xmlrpc_encode. + Value xmlrpc_encode(mixed $phpval) + +Alias for `php_xmlrpc_encode`. + + +[[debugger]] +== Bundled debugger + +A webservice debugger is included in the library to help during development and testing. + +=== Debugger setup + +**NB** to avoid turning your webserver into an open relay for http calls, please keep the debugger outside your +webserver's document root by default / in production deployments! + +In order to make usage of the debugger, you will need to have a webserver configured to run php code, and make it serve +the `/debugger` folder within the library. + +The simplest method is to start the php command-line webserver, but if you do so, you should make use of the experimental +multi-process setup. Ex: + + cd debugger; PHP_CLI_SERVER_WORKERS=2 php -S 127.0.0.1:8081 + +then access the debugger by pointing your browser at __http://127.0.0.1:8081__ + +=== Debugger usage + +The interface should be self-explicative enough to need little documentation. + +image::debugger.gif[,,,,align="center"] + +To make sure that the debugger is working properly, you can use it make f.e. a "list available methods" call against the +public demo server available at: Address: __gggeek.altervista.org__, Path: __/sw/xmlrpc/demo/server/server.php__ + +The most useful feature of the debugger is without doubt the "Show debug info" option. It allows to have a screen dump +of the complete http communication between client and server, including the http headers as well as the request and +response payloads, and is invaluable when troubleshooting problems with charset encoding, authentication or http +compression. + +=== Using the debugger against a local server + +If the webserver used to run the debugger is prevented from making http calls to the internet at large for security or +connectivity reasons, one way to make sure that it is working as expected and get acquainted with the library's workings +is to test against the "demo" server which comes bundled with the library: + +- install the library using the Composer option `--prefer-install=source`, to make sure the demo files are also downloaded +- make sure both the `/debugger` and the `/demo` folders are within your webserver's root folder, eg. run + `PHP_CLI_SERVER_WORKERS=2 php -S 127.0.0.1:8081` from the root of the phpxmlrpc library +- access the debugger at __http://127.0.0.1:8081/debugger__ and use it with Address: __127.0.0.1__, + Path: __/demo/server/server.php__ + +=== Debugger extension + +The debugger can take advantage of the JSXMLRPC library's visual editor component to allow easy mouse-driven construction +of the payload for remote methods. To enable the extra functionality, it has have to be downloaded separately and copied +to the debugger directory: ...TODO... + + +== Running tests + +The recommended way to run the library's test suite is via the provided Docker containers. +A handy shell script is available that simplifies usage of Docker. + +The full sequence of operations is: + + ./tests/ci/vm.sh build + ./tests/ci/vm.sh start + ./tests/ci/vm.sh runtests + ./tests/ci/vm.sh stop + + # and, once you have finished all testing related work: + ./tests/ci/vm.sh cleanup + +By default, tests are run using php 7.4 in a Container based on Ubuntu 20 Focal. +You can change the version of PHP and Ubuntu in use by setting the environment variables PHP_VERSION and UBUNTU_VERSION +before building the Container. + +To generate the code-coverage report, run `./tests/ci/vm.sh runcoverage` + +Note: to reduce the size of the download, the test suite is not part of the default package installed with Composer. +In order to have it onboard, install the library using Composer option `--prefer-install=source`. [[qanda]] @@ -1234,43 +1305,32 @@ xmlrpcval xmlrpc_encode mixed $phpvalAlias for php_xmlrpc_encode. === How to send custom XML as payload of a method call -Unfortunately, at the time the XML-RPC spec was designed, support -for namespaces in XML was not as ubiquitous as it is now. As a -consequence, no support was provided in the protocol for embedding XML -elements from other namespaces into an xmlrpc request. - -To send an XML "chunk" as payload of a method call or response, -two options are available: either send the complete XML block as a -string xmlrpc value, or as a base64 value. Since the '<' character in -string values is encoded as '<' in the xml payload of the method -call, the XML string will not break the surrounding xmlrpc, unless -characters outside the assumed character set are used. The second -method has the added benefits of working independently of the charset -encoding used for the xml to be transmitted, and preserving exactly -whitespace, whilst incurring in some extra message length and cpu load -(for carrying out the base64 encoding/decoding). +Unfortunately, at the time the XML-RPC spec was designed, support for namespaces in XML was not as ubiquitous as it +became later. As a consequence, no support was provided in the protocol for embedding XML elements from other namespaces +into an xmlrpc request. + +To send an XML "chunk" as payload of a method call or response, two options are available: either send the complete XML +block as a string xmlrpc value, or as a base64 value. Since the '<' character in string values is encoded as '<' in +the xml payload of the method call, the XML string will not break the surrounding xmlrpc, unless characters outside the +assumed character set are used. The second method has the added benefits of working independently of the charset +encoding used for the xml to be transmitted, and preserving exactly whitespace, whilst incurring in some extra message +length and cpu load (for carrying out the base64 encoding/decoding). === Is there any limitation on the size of the requests / responses that can be successfully sent? -Yes. But I have no hard figure to give; it most likely will depend -on the version of PHP in usage and its configuration. +Yes. But I have no hard figure to give; it most likely will depend on the version of PHP in usage and its configuration. -Keep in mind that this library is not optimized for speed nor for -memory usage. Better alternatives exist when there are strict -requirements on throughput or resource usage, such as the php native -xmlrpc extension (see the PHP manual for more information). +Keep in mind that this library is not optimized for speed nor for memory usage. Better alternatives exist when there are +strict requirements on throughput or resource usage, such as the php native xmlrpc extension (see the PHP manual for +more information). -Keep in mind also that HTTP is probably not the best choice in -such a situation, and XML is a deadly enemy. CSV formatted data over -socket would be much more efficient. +Keep in mind also that HTTP is probably not the best choice in such a situation, and XML is a deadly enemy. CSV formatted +data over socket would be much more efficient. Or even Googles' ProtoBuffer. -If you really need to move a massive amount of data around, and -you are crazy enough to do it using phpxmlrpc, your best bet is to -bypass usage of the xmlrpcval objects, at least in the decoding phase, -and have the server (or client) object return to the calling function -directly php values (see xmlrpc_client::return_type -and xmlrpc_server::functions_parameters_type for more -details). +If you really need to move a massive amount of data around, and you are crazy enough to do it using phpxmlrpc, your best +bet is to bypass usage of the Value objects, at least in the decoding phase, and have the server (or client) object +return to the calling function directly php values (see `Client::return_type` and `Server::functions_parameters_type` +for more details). === My server (client) returns an error whenever the client (server) returns accented characters @@ -1282,23 +1342,18 @@ To be documented... === My client returns "XML-RPC Fault #2: Invalid return payload: enable debugging to examine incoming payload": what should I do? -The response you are seeing is a default error response that the -client object returns to the php application when the server did not -respond to the call with a valid xmlrpc response. +The response you are seeing is a default error response that the client object returns to the php application when the +server did not respond to the call with a valid xmlrpc response. -The most likely cause is that you are not using the correct URL -when creating the client object, or you do not have appropriate access -rights to the web page you are requesting, or some other common http -misconfiguration. +The most likely cause is that you are not using the correct URL when creating the client object, or you do not have +appropriate access rights to the web page you are requesting, or some other common http misconfiguration. -To find out what the server is really returning to your client, -you have to enable the debug mode of the client, using -`+$client->setDebug(1)+`; +To find out what the server is really returning to your client, you have to enable the debug mode of the client, using +`$client->setDebug(1)`; === How can I save to a file the xml of the xmlrpc responses received from servers? -If what you need is to save the responses received from the server -as xml, you have two options: +If what you need is to save the responses received from the server as xml, you have two options: 1- use the serialize() method on the response object. @@ -1309,209 +1364,127 @@ if (!$resp->faultCode()) $data_to_be_saved = $resp->serialize(); ---- -Note that this will not be 100% accurate, since the xml generated -by the response object can be different from the xml received, -especially if there is some character set conversion involved, or such -(eg. if you receive an empty string tag as , serialize() -will output ), or if the server sent back -as response something invalid (in which case the xml generated client -side using serialize() will correspond to the error response generated +Note that this will not be 100% accurate, since the xml generated by the response object can be different from the xml +received, especially if there is some character set conversion involved, or such (eg. if you receive an empty string tag +as "", `serialize()` will output ""), or if the server sent back as response something invalid (in +which case the xml generated client side using serialize() will correspond to the error response generated internally by the lib). -2 - set the client object to return the raw xml received instead - of the decoded objects: +2 - set the client object to return the raw xml received instead of the decoded objects: [source, php] ---- -$client = new xmlrpc_client($url); +$client = new Client($url); $client->return_type = 'xml'; $resp = $client->send($msg); if (!$resp->faultCode()) - $data_to_be_saved = $resp->value(); + $data_to_be_saved = $resp->value(); ---- -Note that using this method the xml response will not be -parsed at all by the library, only the http communication protocol will -be checked. This means that xmlrpc responses sent by the server that -would have generated an error response on the client (eg. malformed xml, -responses that have faultcode set, etc...) now will not be flagged as -invalid, and you might end up saving not valid xml but random -junk... +Note that using this method the xml response will not be parsed at all by the library, only the http communication +protocol will be checked. This means that xmlrpc responses sent by the server that would have generated an error +response on the client (eg. malformed xml, responses that have faultCode set, etc...) now will not be flagged as +invalid, and you might end up saving not valid xml but random junk... -=== Can I use the ms windows character set?:: +=== Can I use the MS Windows character set?:: -If the data your application is using comes from a Microsoft -application, there are some chances that the character set used to -encode it is CP1252 (the same might apply to data received from an -external xmlrpc server/client, but it is quite rare to find xmlrpc -toolkits that encode to CP1252 instead of UTF8). It is a character set -which is "almost" compatible with ISO 8859-1, but for a few extra -characters. +If the data your application is using comes from a Microsoft application, there are some chances that the character set +used to encode it is CP1252 (the same might apply to data received from an external xmlrpc server/client, but it is quite +rare to find xmlrpc toolkits that encode to CP1252 instead of UTF8). It is a character set which is "almost" compatible +with ISO 8859-1, but for a few extra characters. PHP-XMLRPC only supports the ISO 8859-1 and UTF8 character sets. -The net result of this situation is that those extra characters will not -be properly encoded, and will be received at the other end of the -XML-RPC transmission as "garbled data". Unfortunately the library cannot -provide real support for CP1252 because of limitations in the PHP 4 xml -parser. Luckily, we tried our best to support this character set anyway, -and, since version 2.2.1, there is some form of support, left commented -in the code. - -To properly encode outgoing data that is natively in CP1252, you -will have to uncomment all relative code in the file -__xmlrpc.inc__ (you can search for the string "1252"), -then set `+GLOBALS['xmlrpc_internalencoding']='CP1252';+` -Please note that all incoming data will then be fed to your application -as UTF-8 to avoid any potential data loss. +The net result of this situation is that those extra characters will not be properly encoded, and will be received at +the other end of the XML-RPC transmission as "garbled data". Unfortunately the library cannot provide real support for +CP1252 because of limitations in the PHP 4 xml parser. Luckily, we tried our best to support this character set anyway, +and, since version 2.2.1, there is some form of support, left commented out in the code. + +To properly encode outgoing data that is natively in CP1252, you will have to uncomment all relative code in the file +__xmlrpc.inc__ (you can search for the string "1252"), then set `GLOBALS['xmlrpc_internalencoding']='CP1252';` +Please note that all incoming data will then be fed to your application as UTF-8 to avoid any potential data loss. === Does the library support using cookies / http sessions?:: In short: yes, but a little coding is needed to make it happen. -The code below uses sessions to e.g. let the client store a value -on the server and retrieve it later. +The code below uses sessions to e.g. let the client store a value on the server and retrieve it later. [source, php] ---- -$resp = $client->send(new xmlrpcmsg('registervalue', array(new xmlrpcval('foo'), new xmlrpcval('bar')))); +use PhpXmlRpc/Request; +use PhpXmlRpc/Value; + +$resp = $client->send(new Request('registervalue', array(new Value('foo'), new Value('bar')))); if (!$resp->faultCode()) { - $cookies = $resp->cookies(); - if (array_key_exists('PHPSESSID', $cookies)) // nb: make sure to use the correct session cookie name - { - $session_id = $cookies['PHPSESSID']['value']; + $cookies = $resp->cookies(); + if (array_key_exists('PHPSESSID', $cookies)) // nb: make sure to use the correct session cookie name + { + $session_id = $cookies['PHPSESSID']['value']; - // do some other stuff here... + // do some other stuff here... - $client->setcookie('PHPSESSID', $session_id); - $val = $client->send(new xmlrpcmsg('getvalue', array(new xmlrpcval('foo'))); - } + $client->setcookie('PHPSESSID', $session_id); + $val = $client->send(new Request('getvalue', array(new Value('foo'))); + } } ---- -Server-side sessions are handled normally like in any other -php application. Please see the php manual for more information about -sessions. +Server-side sessions are handled normally like in any other php application. Please see the php manual for more +information about sessions. -NB: unlike web browsers, not all xmlrpc clients support usage of -http cookies. If you have troubles with sessions and control only the -server side of the communication, please check with the makers of the -xmlrpc client in use. +NB: unlike web browsers, not all xmlrpc clients support usage of http cookies. If you have troubles with sessions and +control only the server side of the communication, please check with the makers of the xmlrpc client in use. === Integration with the PHP xmlrpc extension To be documented more... -In short: for the fastest execution possible, you can enable the php -native xmlrpc extension, and use it in conjunction with phpxmlrpc. The -following code snippet gives an example of such integration +In short: for the fastest execution possible, you can enable the php native xmlrpc extension, and use it in conjunction +with phpxmlrpc. The following code snippet gives an example of such integration [source, php] ---- /*** client side ***/ -$c = new xmlrpc_client('http://phpxmlrpc.sourceforge.net/server.php'); +$c = new Client('http://phpxmlrpc.sourceforge.net/server.php'); // tell the client to return raw xml as response value $c->return_type = 'xml'; // let the native xmlrpc extension take care of encoding request parameters -$r = $c->send(xmlrpc_encode_request('examples.getStateName', $_POST['stateno'])); - -if ($r->faultCode()) - // HTTP transport error - echo 'Got error '.$r->faultCode(); -else -{ - // HTTP request OK, but XML returned from server not parsed yet - $v = xmlrpc_decode($r->value()); - // check if we got a valid xmlrpc response from server - if ($v === NULL) - echo 'Got invalid response'; - else - // check if server sent a fault response - if (xmlrpc_is_fault($v)) - echo 'Got xmlrpc fault '.$v['faultCode']; - else - echo'Got response: '.htmlentities($v); +$r = $c->send(xmlrpc_encode_request('examples.getStateName', (int)$_POST['stateno'])); + +if ($r->faultCode()) { + // HTTP transport error + echo 'Got error ' . $r->faultCode(); +} else { + // HTTP request OK, but XML returned from server not parsed yet + $v = xmlrpc_decode($r->value()); + // check if we got a valid xmlrpc response from server + if ($v === NULL) + echo 'Got invalid response'; + else + // check if server sent a fault response + if (xmlrpc_is_fault($v)) + echo 'Got xmlrpc fault '.$v['faultCode']; + else + echo'Got response: '.htmlentities($v); } ---- === Substitution of the PHP xmlrpc extension -Yet another interesting situation is when you are using a ready-made -php application, that provides support for the XMLRPC protocol via the -native php xmlrpc extension, but the extension is not available on your -php install (e.g. because of shared hosting constraints). - -Since version 2.1, the PHP-XMLRPC library provides a compatibility -layer that aims to be 100% compliant with the xmlrpc extension API. This -means that any code written to run on the extension should obtain the -exact same results, albeit using more resources and a longer processing -time, using the PHP-XMLRPC library and the extension compatibility module. -The module is part of the EXTRAS package, available as a separate download -from the sourceforge.net website, since version 0.2 - - -[[debugger]] -== Usage of the debugger - -A webservice debugger is included in the library to help during development and testing. - -The interface should be self-explicative enough to need little documentation. - -image::debugger.gif[,,,,align="center"] - -The most useful feature of the debugger is without doubt the "Show debug info" option. It allows to have a screen dump -of the complete http communication between client and server, including the http headers as well as the request and -response payloads, and is invaluable when troubleshooting problems with charset encoding, authentication or http -compression. - -The debugger can take advantage of the JSONRPC library extension, to allow debugging of JSON-RPC webservices, and of the -JSXMLRPC library visual editor to allow easy mouse-driven construction of the payload for remote methods. Both -components have to be downloaded separately and copied to the debugger directory to enable the extra functionality: - -* to enable jsonrpc functionality, download the PHP-XMLRPC EXTRAS package, and copy the file __jsonrpc.inc__ - either to the same directory as the debugger or somewhere in your php include path - -* to enable the visual value editing dialog, download the JS-XMLRPC library, and copy somewhere in the web root files - __visualeditor.php__, __visualeditor.css__ and the folders __yui__ and __img__. Then edit the debugger file __controller.php__ - and set appropriately the variable `+$editorpath+`. - - -== Upgrading - -If you are upgrading from version 3 or earlier you have two options: - -1. adapt your code to the new API (all changes needed are described in [doc/api_changes_v4.md](doc/api_changes_v4.md)) +Yet another interesting situation is when you are using a ready-made php application, that provides support for the +XMLRPC protocol via the native php xmlrpc extension, but the extension is not available on your php install (e.g. +because of shared hosting constraints). -2. use instead the *compatibility layer* which is provided. Instructions and pitfalls described in [doc/api_changes_v4.md](doc/api_changes_v4.md##enabling-compatibility-with-legacy-code) +Since version 2.1, the PHP-XMLRPC library provides a compatibility layer that aims to be 100% compliant with the xmlrpc +extension API. This means that any code written to run on the extension should obtain the exact same results, albeit +using more resources and a longer processing time, using the PHP-XMLRPC library and the extension compatibility module. -In any case, read carefully the docs available online at https://github.com/gggeek/phpxmlrpc/blob/master/doc/api_changes_v4.md -and report back any undocumented issue using GitHub. - -== Running tests - -The recommended way to run the library's test suite is via the provided Docker containers. -A handy shell script is available that simplifies usage of Docker. - -The full sequence of operations is: - - ./tests/ci/vm.sh build - ./tests/ci/vm.sh start - ./tests/ci/vm.sh runtests - ./tests/ci/vm.sh stop - - # and, once you have finished all testing related work: - ./tests/ci/vm.sh cleanup - -By default, tests are run using php 7.4 in a Container based on Ubuntu 20 Focal. -You can change the version of PHP and Ubuntu in use by setting the environment variables PHP_VERSION and UBUNTU_VERSION -before building the Container. - -To generate the code-coverage report, run `./tests/ci/vm.sh runcoverage` - -Note: to reduce the size of the download, the test suite is not part of the default package installed with Composer. -In order to have it onboard, install the library using Composer option `--prefer-install=source`. +The module was originally part of the EXTRAS package, available as a separate download from the sourceforge.net website; +it has since become available aa Packagist package `phpxmlrpc/polyfill-xmlrpc ` and can be found on GitHub at +https://github.com/gggeek/polyfill-xmlrpc ++++++++++++++++++++++++++++++++++++++