<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3//EN" []> <book> <bookinfo> <title>XML-RPC for PHP</title> <subtitle>version 1.0b9</subtitle> <date>7th July 2001</date> <authorgroup> <author> <firstname>Edd</firstname> <surname>Dumbill</surname> <affiliation> <orgname><ulink url="http://usefulinc.com/">Useful Information Company</ulink></orgname> <address> <email>edd@usefulinc.com</email> </address> </affiliation> </author> </authorgroup> <copyright> <year>1999,2000,2001</year> <holder>Edd Dumbill, Useful Information Company</holder> </copyright> <legalnotice> <para>License is granted to use or modify this software ("XML-RPC for PHP") for commercial or non-commercial use provided the copyright of the author is preserved in any distributed or derivative work.</para> <para> THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</para> </legalnotice> </bookinfo> <toc> </toc> <chapter id="introduction"> <title>Introduction</title> <para>XML-RPC is a format devised by <ulink url="http://www.userland.com/">Userland Software</ulink> for achieving remote procedure call via XML. XML-RPC has its own web site, <ulink url="http://www.xmlrpc.com/">www.XmlRpc.com</ulink></para> <para>The most common implementations of XML-RPC available at the moment use HTTP as the transport. A list of implementations for other languages such as Perl and Python can be found on the <ulink url="http://www.xmlrpc.com/">www.XmlRpc.com</ulink>.</para> <para>This collection of PHP classes provides a framework for writing XML-RPC clients and servers in PHP.</para> <warning> <para>The <emphasis>server code</emphasis> works only with versions of PHP3 >= 3.0.12. The code is also known to work with PHP4. </para> </warning> <sect1> <title>Acknowledgements</title> <para>Jim Winstead <email>jimw@php.net</email></para> <para>Peter Kocks <email>peter.kocks@baygate.com</email></para> <para>Nicolay Mausz <email>mausz@flying-dog.com</email></para> <para>Ben Margolin <email>ben@wendy.auctionwatch.com</email></para> <para>Dan Libby <email>dan@libby.com</email></para> <para>Gaetano Giunta <email>g.giunta@libero.it</email></para> <para>Idan Sofer <email>i_sofer@yahoo.com</email></para> </sect1> </chapter> <chapter id="manifest"> <title>Files in the distribution</title> <glosslist> <glossentry> <glossterm>xmlrpc.inc</glossterm> <glossdef> <para>the XML-RPC classes. <function>include()</function> this in your PHP files to use the classes.</para> </glossdef> </glossentry> <glossentry> <glossterm>xmlrpcs.inc</glossterm> <glossdef> <para>the XML-RPC server class. <function>include()</function> this in addition to xmlrpc.inc to get server functionality</para> </glossdef> </glossentry> <glossentry> <glossterm>bettydemo.php</glossterm> <glossdef> <para>demo which retrieves a state name from a number using Dave Winer's XML-RPC server at betty.userland.com</para> </glossdef> </glossentry> <glossentry> <glossterm>server.php</glossterm> <glossdef> <para>a sample server hosting three functions: a US State lookup tool, a struct sorter and an echo function.</para> </glossdef> </glossentry> <glossentry> <glossterm>client.php, agesort.php, echotest.php</glossterm> <glossdef> <para>client code to exercise the various functions in server.php</para> </glossdef> </glossentry> <glossentry> <glossterm>base64test.php, stringtest.php</glossterm> <glossdef> <para> Tests to verify that encoding and decoding of base 64 and entities is functioning correctly. </para> </glossdef> </glossentry> <glossentry> <glossterm>vardemo.php</glossterm> <glossdef> <para>examples of how to construct xmlrpcval types</para> </glossdef> </glossentry> <glossentry> <glossterm>demo1.txt, demo2.txt, demo3.txt</glossterm> <glossdef> <para>XML-RPC responses captured in a file for testing purposes (you can use these to test the <function>xmlrpcmsg->parseResponse()</function> method).</para> </glossdef> </glossentry> <glossentry> <glossterm>httptest.php</glossterm> <glossdef> <para>Testing that HTTP response detection works OK.</para> </glossdef> </glossentry> <glossentry> <glossterm>test.pl, test.py</glossterm> <glossdef> <para>Perl and Python programs to exercise server.php to test that some of the methods work. Make sure you point these at your server, not mine!</para> </glossdef> </glossentry> <glossentry> <glossterm>workspace.testPhpServer.fttb</glossterm> <glossdef> <para>Frontier scripts to exercise the demo server. Thanks to Dave Winer for permission to include these. See <ulink url="http://www.xmlrpc.com/discuss/msgReader$853">Dave's announcement of these.</ulink></para> </glossdef> </glossentry> <glossentry> <glossterm>phpunit.php</glossterm> <glossdef> <para>Fred Yankowski's unit test framework for PHP.</para> </glossdef> </glossentry> <glossentry> <glossterm>testsuite.php</glossterm> <glossdef> <para>Start of a unit test suite for this software package. If you do development on this software, please consider submitting tests for this suite.</para> </glossdef> </glossentry> <glossentry> <glossterm>which.php</glossterm> <glossdef> <para>A demo of the <function>interopEchoTests.whichToolkit</function> method.</para> </glossdef> </glossentry> <glossentry> <glossterm>discuss.php, comment.php</glossterm> <glossdef> <para>Software used in the PHP chapter of <xref linkend="jellyfish"> to provide a comment server and allow the attachment of comments to stories from Meerkat's data store.</para> </glossdef> </glossentry> </glosslist> </chapter> <chapter id="bugs"> <title>Bugs</title> <para>This is a bare framework. The "nice" bits haven't been put in yet. Specifically, no HTTP response checking is performed, and no type validation or coercion has been put in. PHP being a loosely-typed language, this is going to have to be done explicitly.</para> <para>dateTime.iso8601 is supported opaquely. It can't be done natively as the XML-RPC specification explictly forbids passing of timezone specifiers in ISO8601 format dates. You can, however, use the <xref linkend="iso8601encode"> and <xref linkend="iso8601decode"> functions to do the encoding and decoding for you.</para> <para>If alternative character set encoding is sent in HTTP header than it will be ignored for the moment. We speak only UTF-8...</para> <para>If more than 32k of HTTP headers are encountered (like, why?) then the response parsing code will break.</para> </chapter> <chapter id="support"> <title>Support</title> <sect1> <title>Online Support</title> <para>XML-RPC for PHP is offered "as-is" without any warranty or commitment to support. However, informal advice and help is available via the XML-RPC for PHP mailing list and XML-RPC.com. </para> <itemizedlist> <listitem> <para>The <emphasis>PHP XML-RPC interest mailing list</emphasis> is run by the author. More details <ulink url="http://www.usefulinc.com/xmlrpc/list.html">can be found here</ulink>.</para> </listitem> <listitem><para>For more general XML-RPC questions, there is a Yahoo! Groups <ulink url="http://groups.yahoo.com/group/xml-rpc/">XML-RPC mailing list</ulink>.</para> <listitem> <para>The <ulink url="http://www.xmlrpc.com/discuss">XML-RPC.com</ulink> discussion group is a useful place to get help with using XML-RPC. This group is also gatewayed into the Yahoo! Groups mailing list.</para> </listitem> </itemizedlist> </sect1> <sect1 label="The Jellyfish Book" id="jellyfish" xreflabel="The Jellyfish Book"> <title>The Jellyfish Book</title> <para> <graphic fileref="http://www.oreilly.com/catalog/covers/progxmlrpc.s.gif" format="gif" width="145" depth="190" align="right"></graphic> Together with Simon St.Laurent and Joe Johnston, I wrote a book on XML-RPC for O'Reilly and Associates on XML-RPC. It features a rather fetching jellyfish on the cover. </para> <para>Complete details of the book are <ulink url="http://www.oreilly.com/catalog/progxmlrpc/">available from O'Reilly's web site.</ulink> </para> <para>I'm responsible for the chapter on PHP, which includes a worked example of creating a forum server, and hooking it up the O'Reilly's <ulink url="http://meerkat.oreillynet.com/">Meerkat</ulink> service in order to allow commenting on news stories from around the Web.</para> <para>If you've benefitted from the effort I've put into writing this software, then please consider buying the book!</para> </sect1> </chapter> <chapter id="apidocs"> <title>Class documentation</title> <sect1 id="xmlrpc-client" xreflabel="xmlrpc_client"> <title>xmlrpc_client</title> <para>This is the basic class used to represent a client of an XML-RPC server.</para> <sect2> <title>Creation</title> <para>The constructor has the following syntax:</para> <funcsynopsis> <funcprototype> <funcdef>$client=new xmlrpc_client</funcdef> <paramdef><parameter>$server_path</parameter></paramdef> <paramdef><parameter>$server_hostname</parameter></paramdef> <paramdef><parameter>$server_port</parameter></paramdef> </funcprototype> </funcsynopsis> <para>Here's an example client set up to query Userland's XML-RPC server at <emphasis>betty.userland.com</emphasis>:</para> <programlisting> $client=new xmlrpc_client("/RPC2", "betty.userland.com", 80);</programlisting> <para>The <parameter>server_port</parameter> parameter is optional, and if omitted will default to 80.</para> </sect2> <sect2> <title>Methods</title> <para>This class supports the following methods.</para> <sect3 id="xmlrpc-client-send" xreflabel="xmlrpc_client->send"> <title>send</title> <para>This method takes the form:</para> <funcsynopsis> <funcprototype> <funcdef>$response=$client->send</funcdef> <paramdef><parameter>$xmlrpc_message</parameter></paramdef> <paramdef><parameter>$timeout</parameter></paramdef> </funcprototype> </funcsynopsis> <para>Where <parameter>$xmlrpc_message</parameter> is an instance of <classname>xmlrpcmsg</classname> (see <xref linkend="xmlrpcmsg">), and <parameter>$response</parameter> is an instance of <classname>xmlrpcresp</classname> (see <xref linkend="xmlrpcresp">).</para> <para>The <parameter>$timeout</parameter> is optional, and will be set to <literal>0</literal> (wait forever) if omitted. This timeout value is passed to <function>fsockopen()</function>.</para> <para>If the value of <parameter>$response</parameter> is <literal>0</literal> rather than an <classname>xmlrpcresp</classname> object, then this signifies an I/O error has occured. You can find out what the I/O error was from the values <function>$client->errno</function> and <function>$client->errstring</function>. </para> <para>In addition to low-level errors, the XML-RPC server you were querying may return an error in the <classname>xmlrpcresp</classname> object. See <xref linkend="xmlrpcresp"> for details of how to handle these errors. </para> </sect3> <sect3> <title>setCredentials</title> <funcsynopsis> <funcprototype> <funcdef>$client->setCredentials</funcdef> <paramdef><parameter>$username</parameter></paramdef> <paramdef><parameter>$password</parameter></paramdef> </funcprototype> </funcsynopsis> <para>This method sets the username and password for authorizing the client to a server. With the default (HTTP) transport, this information is used for HTTP Basic authorization. </para> </sect3> <sect3> <title>setDebug</title> <funcsynopsis> <funcprototype> <funcdef>$client->setDebug</funcdef> <paramdef><parameter>$debugOn</parameter></paramdef> </funcprototype> </funcsynopsis> <para><parameter>$debugOn</parameter> is either <literal>0</literal> or <literal>1</literal> depending on whether you require the client to print debugging information to the browser. The default is not to output this information.</para> <para> The debugging information includes the raw data returned from the XML-RPC server it was querying, and the PHP value the client attempts to create to represent the value returned by the server. This option can be very useful when debugging servers as it allows you to see exactly what the server returns. </para> </sect3> </sect2> </sect1> <sect1 id="xmlrpcmsg" xreflabel="xmlrpcmsg"> <title>xmlrpcmsg</title> <para>This class provides a representation for a request to an XML-RPC server. A client sends an <classname>xmlrpcmsg</classname> to a server, and receives back an <classname>xmlrpcresp</classname> (see <xref linkend="xmlrpc-client-send">).</para> <sect2> <title>Creation</title> <para>The constructor takes the following form:</para> <funcsynopsis> <!-- one of (funcprototype funcdef) --> <funcprototype> <funcdef>$msg=new xmlrpcmsg</funcdef> <paramdef><parameter>$methodName</parameter></paramdef> <paramdef><parameter>$parameterArray</parameter></paramdef> </funcprototype> </funcsynopsis> <para>Where <parameter>$methodName</parameter> is a string indicating the name of the method you wish to invoke, and <parameter>$parameterArray</parameter> is a simple <classname>Array</classname> of <classname>xmlrpcval</classname> objects. Here's an example message to the <emphasis>US state name</emphasis> server: </para> <programlisting> $msg=new xmlrpcmsg("examples.getStateName", array(new xmlrpcval(23, "int"))); </programlisting> <para> This example requests the name of state number 23. For more information on <classname>xmlrpcval</classname> objects, see <xref linkend="xmlrpcval">. </para> </sect2> <sect2> <title>Methods</title> <sect3> <title>serialize</title> <funcsynopsis> <funcprototype> <funcdef>$outString=$msg->serialize</funcdef> <paramdef></paramdef> </funcprototype> </funcsynopsis> <para>Returns the an XML string representing the XML-RPC message.</para> </sect3> <sect3> <title>addParam</title> <funcsynopsis> <funcprototype> <funcdef>$msg->addParam</funcdef> <paramdef><parameter>$xmlrpcVal</parameter></paramdef> </funcprototype> </funcsynopsis> <para>Adds the <classname>xmlrpcval</classname> <parameter>$xmlrpcVal</parameter> to the parameter list for this method call.</para> </sect3> <sect3> <title>getParam</title> <funcsynopsis> <funcprototype> <funcdef>$xmlrpcVal=$msg->getParam</funcdef> <paramdef><parameter>$n</parameter></paramdef> </funcprototype> </funcsynopsis> <para>Gets the <parameter>$n</parameter>th parameter in the message. Use this method in server implementations. Returns the <literal>undef</literal> value if no such parameter exists.</para> </sect3> <sect3> <title>getNumParams</title> <funcsynopsis> <funcprototype> <funcdef>$n=$msg->getNumParams</funcdef> <paramdef></paramdef> </funcprototype> </funcsynopsis> <para> Returns the number of parameters attached to this message. </para> </sect3> <sect3> <title>method</title> <funcsynopsis> <funcprototype> <funcdef>$methName=$msg->method</funcdef> <paramdef></paramdef> </funcprototype> <funcprototype> <funcdef>$msg->method</funcdef> <paramdef><parameter>$methName</parameter></paramdef> </funcprototype> </funcsynopsis> <para>Gets or sets the method contained in the XML-RPC message.</para> </sect3> <sect3> <title>parseResponse</title> <funcsynopsis> <funcprototype> <funcdef>$response=$msg->parseResponse</funcdef> <paramdef><parameter>$xmlString</parameter></paramdef> </funcprototype> </funcsynopsis> <para>Given an incoming XML-RPC server response contained in the string <parameter>$xmlString</parameter>, this method constructs an <classname>xmlrpcresp</classname> response object and returns it, setting error codes as appropriate (see <xref linkend="xmlrpc-client-send">). </para> <para> This method processes any HTTP/MIME headers it finds. </para> </sect3> <sect3> <title>parseResponseFile</title> <funcsynopsis> <funcprototype> <funcdef>$response=$msg->parseResponseFile</funcdef> <paramdef><parameter>$fileHandle</parameter></paramdef> </funcprototype> </funcsynopsis> <para>Given an incoming XML-RPC server response on the file handle <parameter>$fileHandle</parameter>, this method reads the data and passes it to <function>parseResponse</function> </para> <para> This method is useful to construct responses from pre-prepared files (see files <literal>demo1.txt, demo2.txt, demo3.txt</literal> in this distribution). It processes any HTTP headers it finds. </para> </sect3> </sect2> </sect1> <sect1 id="xmlrpcresp" xreflabel="xmlrpcresp"> <title>xmlrpcresp</title> <para>This class is used to contain responses to XML-RPC requests. A server method handler will construct an <classname>xmlrpcresp</classname> and pass it as a return value. This same value will be returned by the result of an invocation of the <function>send</function> method of the <classname>xmlrpc_client</classname> class.</para> <sect2> <title>Creation</title> <funcsynopsis> <!-- one of (funcprototype funcdef) --> <funcprototype> <funcdef>$resp=new xmlrpcresp</funcdef> <!-- one of (paramdef varargs void) --> <paramdef><parameter>$xmlrpcval</parameter></paramdef> </funcprototype> <funcprototype> <funcdef>$resp=new xmlrpcresp</funcdef> <paramdef><parameter>0</parameter></paramdef> <paramdef><parameter >$errcode</parameter></paramdef> <paramdef><parameter >$errstring</parameter></paramdef> </funcprototype> </funcsynopsis> <para>The first instance is used when execution has happened without difficulty: <parameter>$xmlrpcval</parameter> is an <classname>xmlrpcval</classname> value with the result of the method execution contained in it.</para> <para> The second type of constructor is used in case of failure. <parameter>$errcode</parameter> and <parameter>$errstring</parameter> are used to provide indication of what has gone wrong. See <xref linkend="xmlrpc-server"> for more information on passing error codes. </para> </sect2> <sect2> <title>Methods</title> <sect3> <title>faultCode</title> <funcsynopsis> <funcprototype> <funcdef>$fn=$resp->faultCode</funcdef> <paramdef></paramdef> </funcprototype> </funcsynopsis> <para>Returns the integer fault code return from the XML-RPC response <parameter>$resp</parameter>. A zero value indicates success, any other value indicates a failure response.</para> </sect3> <sect3> <title>faultString</title> <funcsynopsis> <funcprototype> <funcdef>$fs=$resp->faultString</funcdef> <paramdef></paramdef> </funcprototype> </funcsynopsis> <para> Returns the human readable explanation of the fault indicated by <function>$resp->faultCode</function>. </para> </sect3> <sect3> <title>value</title> <funcsynopsis> <funcprototype> <funcdef>$xmlrpcVal=$resp->value</funcdef> <paramdef></paramdef> </funcprototype> </funcsynopsis> <para> Returns an <classname>xmlrpcval</classname> object containing the return value sent by the server. If the response's <function>faultCode</function> is non-zero then the value returned by this method should not be used (it may not even be an object). </para> </sect3> <sect3> <title>serialize</title><para></para> <funcsynopsis> <funcprototype> <funcdef>$outString=$resp->serialize</funcdef> <paramdef></paramdef> </funcprototype> </funcsynopsis> <para>Returns an XML string representation of the response.</para> </sect3> </sect2> </sect1> <sect1 id="xmlrpcval" xreflabel="xmlrpcval"> <title>xmlrpcval</title> <para>This is where a lot of the hard work gets done. This class enables the creation and encapsulation of values for XML-RPC. </para> <para> Ensure you've read the XML-RPC spec at <ulink url="http://www.xmlrpc.com/stories/storyReader$7">http://www.xmlrpc.com/stories/storyReader$7</ulink> before reading on as it will make things clearer. </para> <para>The <classname>xmlrpcval</classname> class can store arbitrarily complicated values using the following types: <literal>i4 int boolean string double dateTime.iso8601 base64 array struct</literal>. You should refer to the <ulink url="http://www.xmlrpc.com/stories/storyReader$7">spec</ulink> for more information on what each of these types mean. </para> <sect2> <title>Notes on types</title> <sect3> <title>int</title> <para>The type <classname>i4</classname> is accepted as a synonym for <classname>int</classname>. The value parsing code will always convert <classname>i4</classname> to <classname>int</classname>: <classname>int</classname> is regarded by this implementation as the canonical name for this type.</para> </sect3> <sect3> <title>base64</title> <para>Base 64 encoding is performed transparently to the caller when using this type. Therefore you ought to consider it as a "binary" data type, for use when you want to pass none 7-bit clean data. Decoding is also transparent. </para> </sect3> <sect3> <title>boolean</title> <para>The values <literal>true</literal> and <literal>1</literal> map to <literal>true</literal>. All other values (including the empty string) are converted to <literal>false</literal>. </para> </sect3> <sect3> <title>string</title> <para> The characters <literal>< > "</literal> and <literal>&</literal> are converted to their entity equivalents <literal>&lt; &gt; &quot;</literal> and <literal>&amp;</literal> for transport through XML-RPC. The current XML-RPC spec recommends only encoding <literal>< &</literal> but this implementation goes further, for reasons explained by <ulink url="http://www.w3.org/TR/REC-xml#syntax">the XML 1.0 recommendation</ulink>. </para><para>TODO: <literal> &apos;</literal> entity not yet supported</para> </sect3> </sect2> <sect2 id="xmlrpcval-creation" xreflabel="xmlrpcval constructors"> <title>Creation</title> <para>The constructor is the normal way to create an <classname>xmlrpcval</classname>. The constructor can take these forms: </para> <funcsynopsis> <!-- one of (funcprototype funcdef) --> <funcprototype> <funcdef>$myVal=new xmlrpcval</funcdef> <!-- one of (paramdef varargs void) --> <paramdef></paramdef> </funcprototype> <funcprototype> <funcdef>$myVal=new xmlrpcval</funcdef> <!-- one of (paramdef varargs void) --> <paramdef><parameter>$stringVal</parameter></paramdef> </funcprototype> <funcprototype> <funcdef>$myVal=new xmlrpcval</funcdef> <!-- one of (paramdef varargs void) --> <paramdef><parameter>$scalarVal</parameter></paramdef> <paramdef><parameter>"int" | "boolean" | "string" | "double" | "dateTime.iso8601" | "base64"</parameter></paramdef> </funcprototype> <funcprototype> <funcdef>$myVal=new xmlrpcval</funcdef> <!-- one of (paramdef varargs void) --> <paramdef><parameter>$arrayVal</parameter></paramdef> <paramdef><parameter>"array" | "struct"</parameter></paramdef> </funcprototype> </funcsynopsis> <para>The first constructor creates an empty value, which must be altered using the methods <function>addScalar</function>, <function>addArray</function> or <function>addStruct</function> before it can be used. </para> <para> The second constructor creates a simple string value. </para> <para> The third constructor is used to create a scalar value. The second parameter must be a name of an XML-RPC type. Examples: </para> <programlisting> $myInt=new xmlrpcvalue(1267, "int"); $myString=new xmlrpcvalue("Hello, World!", "string"); $myBool=new xmlrpcvalue(1, "boolean"); </programlisting> <para> The fourth constructor form can be used to compose complex XML-RPC values. The first argument is either a simple array in the case of an XML-RPC <classname>array</classname> or an associative array in the case of a <classname>struct</classname>. The elements of the array <emphasis>must be <classname>xmlrpcval</classname> objects themselves</emphasis>. Examples:</para> <programlisting> $myArray=new xmlrpcval(array( new xmlrpcval("Tom"), new xmlrpcval("Dick"), new xmlrpcval("Harry")), "array"); $myStruct=new xmlrpcval(array( "name" => new xmlrpcval("Tom"), "age" => new xmlrpcval(34, "int"), "geek" => new xmlrpcval(1, "boolean")), "struct"); </programlisting> <para>See the file <literal>vardemo.php</literal> in this distribution for more examples.</para> </sect2> <sect2 id="xmlrpcval-methods" xreflabel="xmlrpcval methods"> <title>Methods</title> <sect3> <title>addScalar</title> <funcsynopsis> <!-- one of (funcprototype funcdef) --> <funcprototype> <funcdef>$ok=$val->addScalar</funcdef> <!-- one of (paramdef varargs void) --> <paramdef><parameter>$stringVal</parameter></paramdef> </funcprototype> <funcprototype> <funcdef>$ok=$val->addScalar</funcdef> <!-- one of (paramdef varargs void) --> <paramdef><parameter>$scalarVal</parameter></paramdef> <paramdef><parameter>"int" | "boolean" | "string" | "double" | "dateTime.iso8601" | "base64"</parameter></paramdef> </funcprototype> </funcsynopsis> <para> If <parameter>$val</parameter> is an empty <classname>xmlrpcval</classname> this method makes it a scalar value, and sets that value. If <parameter>$val</parameter> is already a scalar value, then no more scalars can be added and <literal>0</literal> is returned. If all went OK, <literal>1</literal> is returned. </para> <para>There is a special case if <parameter>$val</parameter> is an <classname>array</classname>: the scalar value passed is appended to the array.</para> </sect3> <sect3> <title>addArray</title> <funcsynopsis> <funcprototype> <funcdef>$ok=$val->addArray</funcdef> <paramdef><parameter>$arrayVal</parameter></paramdef> </funcprototype> </funcsynopsis> <para>Turns an empty <classname>xmlrpcval</classname> into an <classname>array</classname> with contents as specified by <parameter>$arrayVal</parameter>. See the fourth constructor form for more information.</para> </sect3> <sect3> <title>addStruct</title> <funcsynopsis> <funcprototype> <funcdef>$ok=$val->addArray</funcdef> <paramdef><parameter>$assocArrayVal</parameter></paramdef> </funcprototype> </funcsynopsis> <para>Turns an empty <classname>xmlrpcval</classname> into a <classname>struct</classname> with contents as specified by <parameter>$assocArrayVal</parameter>. See the fourth constructor form for more information.</para> </sect3> <sect3> <title>kindOf</title> <funcsynopsis> <funcprototype> <funcdef>$kind=$val->kindOf</funcdef> <paramdef></paramdef> </funcprototype> </funcsynopsis> <para> Returns a string containing "struct", "array" or "scalar" describing the base type of the value. If it returns "undef" it means that the value hasn't been initialised. </para> </sect3> <sect3> <title>serialize</title> <funcsynopsis> <funcprototype> <funcdef>$outString=$val->serialize</funcdef> <paramdef></paramdef> </funcprototype> </funcsynopsis> <para> Returns a string containing the XML-RPC representation of this value. </para> </sect3> <sect3> <title>scalarval</title> <funcsynopsis> <funcprototype> <funcdef>$scalarVal=$val->scalarval</funcdef> <paramdef></paramdef> </funcprototype> </funcsynopsis> <para> If <function>$val->kindOf()=="scalar"</function>, this method returns the actual PHP-language value of the scalar (base 64 decoding is automatically handled here). </para> </sect3> <sect3> <title>scalartyp</title> <funcsynopsis> <funcprototype> <funcdef>$typeName=$val->scalartyp</funcdef> <paramdef></paramdef> </funcprototype> </funcsynopsis> <para> If <function>$val->kindOf()=="scalar"</function>, this method returns a string denoting the type of the scalar. As mentioned before, <literal>i4</literal> is always coerced to <literal>int</literal>. </para> </sect3> <sect3> <title>arraymem</title> <funcsynopsis> <funcprototype> <funcdef>$xmlrpcVal=$val->arraymem</funcdef> <paramdef><parameter>$n</parameter></paramdef> </funcprototype> </funcsynopsis> <para> Returns the <parameter>$n</parameter>th element in the array represented by the value <parameter>$val</parameter>. The value returned is an <classname>xmlrpcval</classname> object. </para> </sect3> <sect3> <title>arraysize</title> <funcsynopsis> <funcprototype> <funcdef>$len=$val->arraysize</funcdef> <paramdef></paramdef> </funcprototype> </funcsynopsis> <para>If <parameter>$val</parameter> is an <classname>array</classname>, returns the number of elements in that array. </para> </sect3> <sect3> <title>structmem</title> <funcsynopsis> <funcprototype> <funcdef>$xmlrpcVal=$val->structmem</funcdef> <paramdef><parameter>$memberName</parameter></paramdef> </funcprototype> </funcsynopsis> <para> Returns the element called <parameter>$memberName</parameter> from the struct represented by the value <parameter>$val</parameter>. The value returned is an <classname>xmlrpcval</classname> object. </para> </sect3> <sect3> <title>structeach</title> <funcsynopsis> <funcprototype> <funcdef>list($key,$value)=$val->structeach</funcdef> <paramdef></paramdef> </funcprototype> </funcsynopsis> <para> Returns the next (key,value) pair from the struct, when <parameter>$val</parameter> is a struct. See also <xref linkend="structreset">. </para> </sect3> <sect3 id="structreset" xreflabel="structreset()"> <title>structreset</title> <funcsynopsis> <funcprototype> <funcdef>$val->structreset</funcdef> <paramdef></paramdef> </funcprototype> </funcsynopsis> <para> Resets the internal pointer for <function>structeach()</function> to the beginning of the struct, where <parameter>$val</parameter> is a struct. </para> </sect3> </sect2> </sect1> <sect1 id="xmlrpc-server" xreflabel="xmlrpc_server"> <title>xmlrpc_server</title> <para>The current implementation of this class has been kept as simple as possible. The constructor for the server basically does all the work. Here's a minimal example:</para> <programlisting> function foo ($params) { ... } $s=new xmlrpc_server( array("examples.myFunc" => array("function" => "foo"))); </programlisting> <para> This performs everything you need to do with a server. The single argument is an associative array from method names to function names. The request is parsed and despatched to the relevant function, which is reponsible for returning a <classname>xmlrpcresp</classname> object, which gets serialized back to the caller. See server.php in this distribution for examples of how to do this. </para> <para>Here is a more detailed look at what the handler function <function>foo</function> may do:</para> <programlisting> function foo ($params) { global $xmlrpcerruser; // import user errcode value // $params is an Array of xmlrpcval objects if ($err) { // this is an error condition return new xmlrpcresp(0, $xmlrpcerruser+1, // user error 1 "There's a problem, Captain"); } else { // this is a successful value being returned return new xmlrpcresp(new xmlrpcval("All's fine!", "string")); } } </programlisting> <sect2> <title>The dispatch map</title> <para>The first argument to the <function>xmlrpc_server</function> constructor is an array, called the <emphasis>dispatch map</emphasis>. In this array is the information the server needs to service the XML-RPC methods you define.</para> <para> The dispatch map takes the form of an associative array of associative arrays: the outer array has one entry for each method, the key being the method name. The corresponding value is another associative array, which can have the following members: </para> <itemizedlist> <listitem> <para><function>function</function> - this entry is mandatory. It must be a name of a function in the global scope which services the XML-RPC method.</para> </listitem> <listitem> <para><function>signature</function> - this entry is an array containg the possible signatures (see <xref linkend="signatures">) for the method. If this entry is present then the server will check that the correct number and type of parameters have been sent for this method before dispatching it. </para> </listitem> <listitem> <para> <function>docstring</function> - this entry is a string containing documentation for the method. The documentation may contain HTML markup. </para> </listitem> </itemizedlist> <para>Look at the <filename>server.php</filename> example in the distribution to see what a dispatch map looks like.</para> </sect2> <sect2 id="signatures" xreflabel="Signatures"><title>Method signatures</title> <para>A signature is a description of a method's return type and its parameter types. A method may have more than one signature.</para> <para>Within a server's dispatch map, each method has an array of possible signatures. Each signature is an array of types. The first entry is the return type. For instance, the method <programlisting> string examples.getStateName(int) </programlisting> has the signature <programlisting> array($xmlrpcString, $xmlrpcInt) </programlisting> and, assuming that it the only possible signature for the method, might be used like this in server creation: <programlisting> $findstate_sig=array(array($xmlrpcString, $xmlrpcInt)); $findstate_doc='When passed an integer between 1 and 51 returns the name of a US state, where the integer is the index of that state name in an alphabetic order.'; $s=new xmlrpc_server( array( "examples.getStateName" => array("function" => "findstate", "signature" => $findstate_sig, "docstring" => $findstate_doc))); </programlisting> </para> <para>For convenience the strings representing the XML-RPC types have been encoded as global variables:<programlisting> $xmlrpcI4="i4"; $xmlrpcInt="int"; $xmlrpcBoolean="boolean"; $xmlrpcDouble="double"; $xmlrpcString="string"; $xmlrpcDateTime="dateTime.iso8601"; $xmlrpcBase64="base64"; $xmlrpcArray="array"; $xmlrpcStruct="struct"; </programlisting></para> </sect2> <sect2> <title>Delaying the server response</title> <para>You may want to construct the server, but for some reason not fulfill the request immediately (security verification, for instance). If you pass the constructor a second argument of <literal>0</literal> this will have the desired effect. You can then use the <function>service()</function> method of the server class to service the request. For example:</para> <programlisting> $s=new xmlrpc_server($myDispMap, 0); // ... some code that does other stuff here $s->service(); </programlisting> </sect2> <sect2> <title>Fault reporting</title> <para>Fault codes for your servers should start at the value indicated by the global <literal>$xmlrpcerruser</literal> + 1.</para> <para>Standard errors returned by the server include:</para> <variablelist> <varlistentry> <term><literal>1</literal> <phrase>Unknown method</phrase></term> <listitem> <para>Returned if the server was asked to dispatch a method it didn't know about</para> </listitem> </varlistentry> <varlistentry> <term><literal>2</literal> <phrase>Invalid return payload</phrase></term> <listitem> <para>This error is actually generated by the client, not server, code, but signifies that a server returned something it couldn't understand.</para> </listitem> </varlistentry> <varlistentry> <term><literal>3</literal> <phrase>Incorrect parameters</phrase></term> <listitem> <para>This error is generated when the server has signature(s) defined for a method, and the parameters passed by the client do not match any of signatures.</para> </listitem> </varlistentry> <varlistentry> <term><literal>4</literal> <phrase>Can't introspect: method unknown</phrase></term> <listitem> <para>This error is generated by the builtin <function>system.*</function> methods when any kind of introspection is attempted on a method undefined by the server.</para> </listitem> </varlistentry> <varlistentry> <term><literal>5</literal> <phrase>Didn't receive 200 OK from remote server</phrase></term> <listitem> <para>This error is generated by the client when a remote server doesn't return HTTP/1.1 200 OK in response to a request. A more detailed error report is added onto the end of the phrase above.</para> </listitem> </varlistentry> <varlistentry> <term><literal>100-</literal> <phrase>XML parse errors</phrase></term> <listitem> <para>Returns 100 plus the XML parser error code for the fault that occurred. The <function>faultString</function> returned explains where the parse error was in the incoming XML stream.</para> </listitem> </varlistentry> </variablelist> </sect2> </sect1> </chapter> <chapter id="helpers"> <title>Helper functions</title> <para>XML-RPC for PHP contains some helper functions which you can use to make processing of XML-RPC requests easier.</para> <sect1> <title>Date functions</title> <para>The XML-RPC specification has this to say on dates:</para> <blockquote> <para>Don't assume a timezone. It should be specified by the server in its documentation what assumptions it makes about timezones. </para> </blockquote> <para>Unfortunately, this means that date processing isn't straightforward. Although XML-RPC uses ISO 8601 format dates, it doesn't use the timezone specifier.</para> <para>We strongly recommend that in every case where you pass dates in XML-RPC calls, you use UTC (GMT) as your timezone. Most computer languages include routines for handling GMT times natively, and you won't have to translate between timezones.</para> <para>For more information about dates, see <ulink url="http://www.uic.edu/year2000/datefmt.html">ISO 8601: The Right Format for Dates</ulink>, which has a handy link to a PDF of the ISO 8601 specification. Note that XML-RPC uses exactly one of the available representations: CCYYMMDDTHH:MM:SS.</para> <sect2 id="iso8601encode" xreflabel="iso8601_encode()"> <title>iso8601_encode</title> <funcsynopsis> <funcprototype> <funcdef>$isoString=iso8601_encode</funcdef> <paramdef><parameter>$time_t</parameter><parameter>$utc=0</parameter></paramdef> </funcprototype> </funcsynopsis> <para>Returns an ISO 8601 formatted date generated from the UNIX timestamp <parameter>$time_t</parameter>, as returned by the PHP function <function>time()</function>. </para> <para>The argument <parameter>$utc</parameter> can be omitted, in which case it defaults to <literal>0</literal>. If it is set to <literal>1</literal>, then the function corrects the time passed in for UTC. Example: if you're in the GMT-6:00 timezone and set <parameter>$utc</parameter>, you will receive a date representation six hours ahead of your local time.</para> <para>The included demo program <filename>vardemo.php</filename> includes a demonstration of this function.</para> </sect2> <sect2 id="iso8601decode" xreflabel="iso8601_decode()"> <title>iso8601_decode</title> <funcsynopsis> <funcprototype> <funcdef>$time_t=iso8601_decode</funcdef> <paramdef><parameter>$isoString</parameter><parameter>$utc=0</parameter></paramdef> </funcprototype> </funcsynopsis> <para>Returns a UNIX timestamp from an ISO 8601 encoded time and date string passed in. If <parameter>$utc</parameter> is <literal>1</literal> then <parameter>$isoString</parameter> is assumed to be in the UTC timezone, and thus the <parameter>$time_t</parameter> result is also UTC: otherwise, the timezone is assumed to be your local timezone and you receive a local timestamp.</para> </sect2> </sect1> <sect1 id="arrayuse"> <title>Easy use with PHP arrays</title> <para>Dan Libby was kind enough to contribute two helper functions that make it easier to translate to and from PHP arrays. This makes it easier to deal with complex structures. At the moment support is limited to <type>int</type>, <type>double</type>, <type>string</type>, <type>array</type> and <type>struct</type> datatypes; note also that all PHP arrays are encoded as structs due to PHP not being able to tell the difference between a hash and a linear array.</para> <para>These functions reside in <filename>xmlrpc.inc</filename>.</para> <sect2 id="xmlrpcdecode"> <title>xmlrpc_decode</title> <funcsynopsis> <funcprototype> <funcdef>$arr=xmlrpc_decode</funcdef> <paramdef><parameter>$xmlrpc_val</parameter></paramdef> </funcprototype> </funcsynopsis> <para> Returns a PHP array stuffed with the values found in the <type>xmlrpcval</type> <parameter>$xmlrpc_val</parameter>, translated into native PHP types. </para> </sect2> <sect2 id="xmlrpcencode"> <title>xmlrpc_encode</title> <funcsynopsis> <funcprototype> <funcdef>$xmlrpc_val=xmlrpc_encode</funcdef> <paramdef><parameter>$phpval</parameter></paramdef> </funcprototype> </funcsynopsis> <para> Returns an <type>xmlrpcval</type> populated with the PHP values in <parameter>$phpval</parameter>. Works recursively on arrays and structs. Note that there's no support for non-base types like base-64 values or date-times. </para> </sect2> </sect1> <sect1 id="debugging"> <title>Debugging aids</title> <sect2> <title>xmlrpc_debugmsg</title> <funcsynopsis> <funcprototype> <funcdef>xmlrpc_debugmsg</funcdef> <paramdef><parameter>$debugstring</parameter></paramdef> </funcprototype> </funcsynopsis> <para>Sends the contents of <parameter>$debugstring</parameter> in XML comments in the server return payload. If a PHP client has debugging turned on, the user will be able to see server debug information.</para> <para>Use this function in your methods so you can pass back diagnostic information. It is only available from <filename>xmlrpcs.inc</filename>.</para> </sect2> </sect1> </chapter> <chapter id="reserved" xreflabel="Reserved methods"> <title>Reserved methods</title> <para>In order to extend the functionality offered by XML-RPC servers without impacting on the protocol, I've included experimental support in this release for reserved methods.</para> <para>All methods starting with <function>system.</function> are considered reserved by the server. PHP for XML-RPC itself provides three special methods, detailed in this chapter.</para> <sect1> <title>system.listMethods</title> <para>This method may be used to enumerate the methods implemented by the XML-RPC server.</para> <para>The <function>system.listMethods</function> method requires no parameters. It returns an array of strings, each of which is the name of a method implemented by the server.</para> </sect1> <sect1 id="sysmethodsig"> <title>system.methodSignature</title> <para>This method takes one parameter, the name of a method implemented by the XML-RPC server.</para> <para>It returns an array of possible signatures for this method. A signature is an array of types. The first of these types is the return type of the method, the rest are parameters.</para> <para>Multiple signatures (ie. overloading) are permitted: this is the reason that an array of signatures are returned by this method.</para> <para>Signatures themselves are restricted to the top level parameters expected by a method. For instance if a method expects one array of structs as a parameter, and it returns a string, its signature is simply "string, array". If it expects three integers, its signature is "string, int, int, int".</para> <para> If no signature is defined for the method, a none-array value is returned. Therefore this is the way to test for a non-signature, if <parameter>$resp</parameter> below is the response object from a method call to <function>system.methodSignature</function>: </para> <programlisting> $v=$resp->value(); if ($v->kindOf()!="array") { // then the method did not have a signature defined } </programlisting> <para> See the <filename>introspect.php</filename> demo included in this distribution for an example of using this method. </para> </sect1> <sect1 id="sysmethhelp"> <title>system.methodHelp</title> <para>This method takes one parameter, the name of a method implemented by the XML-RPC server.</para> <para> It returns a documentation string describing the use of that method. If no such string is available, an empty string is returned. </para> <para> The documentation string may contain HTML markup. </para> </sect1> </chapter> <chapter id="examples" xreflabel="Examples"> <title>Examples</title> <para>The best examples are to be found in the sample files included with the distribution. Some are included here.</para> <sect1 id="statename"> <title>XML-RPC client: state name query</title> <para>Code to get the corresponding state name from a number (1-50) from Dave Winer's server</para> <programlisting> $f=new xmlrpcmsg('examples.getStateName', array(new xmlrpcval($HTTP_POST_VARS["stateno"], "int"))); $c=new xmlrpc_client("/RPC2", "betty.userland.com", 80); $r=$c->send($f); $v=$r->value(); if (!$r->faultCode()) { print "State number ". $HTTP_POST_VARS["stateno"] . " is " . $v->scalarval() . "<BR>"; print "<HR>I got this value back<BR><PRE>" . htmlentities($r->serialize()). "</PRE><HR>\n"; } else { print "Fault: "; print "Code: " . $r->faultCode() . " Reason '" .$r->faultString()."'<BR>"; } </programlisting> </sect1> </chapter> </book> <!-- Keep this comment at the end of the file Local variables: mode: sgml sgml-omittag:nil sgml-shorttag:t sgml-minimize-attributes:nil sgml-always-quote-attributes:t sgml-indent-step:2 sgml-indent-data:t sgml-parent-document:nil sgml-exposed-tags:nil sgml-local-catalogs:nil sgml-local-ecat-files:nil sgml-namecase-general:t sgml-general-insert-case:lower End: -->