KBD

Keith Devens .com

Friday, July 4, 2008 Flag waving
You can have premature generalization as well as premature optimization. – Bjarne Stroustrup
← feedParserBirthday present →

Daily link icon Monday, October 21, 2002

XML-RPC version 3.0

I'm working on version 3.0 of my XML-RPC library. No timetable for sure, since I have four midterms, a homework, and a paper due this week. But after the craziness of this week is over I may get to work on it this weekend. So either next week or the week after may be likely for a release.

I just wanted to take this opportunity to take feature requests. Leave a comment, even anonymously, and tell me what you'd like to see. The following features are planned:

  • I'm making it even easier to build servers. You may be able to do it in one line of code, we'll see Smiley winking
  • Include SSL support. I've gotten this request a few times. I'm planning to include a separate and optional method to make a connection which will use cURL and support SSL. Does it make sense to also support HTTP authentication?
  • You should never have to call XMLRPC_prepare yourself again.
  • I'm probably also going to include my "method not found" method, just to save you from having to write your own. Not that it's hard, but it's only about 3 additional lines in the library.

What else do you want? Now's your time to make yourself heard!

← feedParserBirthday present →

Comments XML gif

Lachlan Donald wrote:

Support for HTTP success codes. The current version of the library seems to not care if the xmlrpc server returned "302 Moved Temporarily" or "200 Success", which is irritating because it goes ahead and tries to serialize the web server error message into a response.

∴ Lachlan Donald | 6-Jan-2003 10:32am est | #1239

Keith (http://www.keithdevens.com/) wrote:

Hmm, interesting. So it should handle redirects. Good point. Does the XML-RPC spec have anything to say about this? If it's open to the implementation, then I'll implement it, along with support for other error codes like 404. Thanks for the input.

Keith | 6-Jan-2003 4:57pm est | http://www.keithdevens.com/ | #1240

Lachlan Donald wrote:

ftp://ftp.rfc-editor.org/in-notes/rfc2616.txt

Thats the relevant RFC. Even if you don't handle redirects, it would be nice to return false for success if there is anything except for a Successful 2xx status code.

As for the XMLRPC spec, all thats mentioned is this:
"Unless there's a lower-level error, always return 200 OK."

I would take this as, if you get anything other than a 200 OK its an error.

∴ Lachlan Donald | 13-Jan-2003 1:05am est | #1263

Robert Harder wrote:

Just a thanks for making simple function calls instead of too-complex OO objects.

∴ Robert Harder | 16-Jan-2003 9:18am est | #1274

Lachlan Donald wrote:

Basic HTTP Authentication

What I have done is basically add a user name and password to the XMLRPC_request method and then add in a Authentication header.

I will send u a patch if you are interested.

∴ Lachlan Donald | 24-Jan-2003 9:19am est | #1330

Mark Weston wrote:

Tabular/Dataset data.

I'm interested in using PHP as a front-end Web Services written on the .Net platform. Microsoft turn a .Net Dataset object to a complex XML (DiffGram) structure for transmission over the internet.

Is it feasible to create a PHP object that takes this XML and exposes methods & properties that allow me to navigate through the Dataset, get the original and current value for a particular column etc...

Ideally this object would have the same methods and properties as the Microsoft .Net Dataset object.

Cheers!

∴ Mark Weston | 25-Feb-2003 4:31pm est | #1493

Keith (http://www.keithdevens.com/) wrote:

Hi Mark, I'm not that familiar with the dataset stuff you're talking about, but while it seems like there's no reason it couldn't be written in PHP, it sounds like it's outside the scope of my XML-RPC library.

Keith | 26-Feb-2003 12:25am est | http://www.keithdevens.com/ | #1494

Patrick Boucher wrote:

How about utf8 support? I've got a hard time sending special characters from one end to the other of my distributed system because of encoding questions.

∴ Patrick Boucher | 7-Apr-2003 12:30pm est | #1764

Keith (http://www.keithdevens.com/) wrote:

utf8 support: PHP doesn't support Unicode. Furthermore, I'm just using PHP's built in XML parser, so if PHP did support Unicode I wouldn't have to make any changes to my library to have it work.

However, what are the "special characters" you're trying to send back and forth? Typically, when I have any +127 characters in text (like special single and double quotes, em and en dashes, etc.), PHP has no trouble dealing with it. I've never tried working with Korean, Japanese, Chinese, Thai, Arabic, etc. etc. though. Smiley

Keith | 7-Apr-2003 12:36pm est | http://www.keithdevens.com/ | #1765

Eliot (http://www.slower.net/) wrote:

When I include your file in my ISP's fairly standard PHP 4.2.2, I get a lot of "Call-time pass-by-reference has been deprecated" warnings. It's easy to suppress these with @, but perhaps you could strip out the pass by reference stuff.

Thanks for the software!

∴ Eliot | 18-Jun-2003 1:10am est | http://www.slower.net/ | #2217

Keith (http://www.keithdevens.com/) wrote:

Eliot - known problem. If I could only get myself to release version 3.0 none of that would happen Smiley At the very least, maybe I should put an "error_reporting(E_ALL & ~E_NOTICE)" at the beginning of the script (and restore it at the end) to patch it up for now.

Keith | 18-Jun-2003 4:23pm est | http://www.keithdevens.com/ | #2221

Chris Adams (http://improbable.org/chris/) wrote:

http://improbable.org/chris/xmlrpc.patch has the patch output of the changes I made to work around those call-time pass by reference warnings. The only tricky thing is accounting for our inability to change the prototype for array_unshift - I work around that by pushing a temporary value first and replacing it.

∴ Chris Adams | 6-Aug-2003 10:32pm est | http://improbable.org/chris/ | #2653

Hendrik wrote:

Kudos to Chris, your patch seems to do the trick! Thanks very much!

∴ Hendrik | 8-Aug-2003 7:33am est | #2660

lordwo (http://www.bblog.com) wrote:

I have a lot of concern about the compatibility of the XML-RPC library and PHP5.

Warning: Call-time pass-by-reference has been deprecated - argument passed by value; If you would like to pass it by reference, modify the declaration of XML_unserialize(). If you would like to enable call-time pass-by-reference, you can set allow_call_time_pass_reference to true in your INI file. However, future versions may not support this any longer.

That's popping everywhere. Since most of the users have no right to change php.ini directives on their host, it should be corrected for the future.
Thanks for you concern.

∴ lordwo | 22-Feb-2004 8:56am est | http://www.bblog.com | #3976

Keith (http://keithdevens.com/) wrote:

I know about it but there's nothing I can do under PHP 4. Note, however, that that feature can be changed in an .htaccess file, so pretty much anyone should be able to change it. I'm also almost completely sure the feature hasn't been removed in PHP 5, so there's nothing to worry about. Once PHP 5 comes out I'll be able to fix the code so it doesn't have that problem.

I've ranted about this particular deprecation before. I'm pretty furious about it because the PHP developers deprecated a feature -- and not only did they deprecate it and give NOTICE-level errors... they give WARNINGs -- while there are so many places in PHP that it impacts on, and they provided NO alternative to it. PHP, in version 4, is fundamentally broken in this way.

Rest assured, once PHP 5 comes out and fixes this problem by finally having a sensible object model I'll be able to fix the code. I plan on getting 3.0 done once that happens.

Keith | 22-Feb-2004 2:45pm est | http://keithdevens.com/ | #3977

Pallieter Koopmans (http://www.atQuest.nl/) wrote:

Additional sample code (implementations for RSS 0.92, Atom, Echo, etc) and API's (TypePad, Blogger, Nucleus, MovableType, etc) would make this packedge complete. Success with the next version!

∴ Pallieter Koopmans | 2-Mar-2004 3:40am est | http://www.atQuest.nl/ | #4064

Keith (http://keithdevens.com/) wrote:

implementations for RSS 0.92, Atom, Echo, etc

What do those have to do with XML-RPC?

and API's

Bindings for specific APIs don't belong in a library like this. Furthermore, they're specific to a particular CMS.

Keith | 2-Mar-2004 12:19pm est | http://keithdevens.com/ | #4065

Robert Castley wrote:

I would like to see support for multiple/unlimited method requests in a single xmlrpc session.

∴ Robert Castley | 16-Mar-2004 5:11am est | #4128

Keith (http://keithdevens.com/) wrote:

In a single session? What do you mean? In one HTTP connection? I don't think that's in the spec.

Keith | 16-Mar-2004 6:37am est | http://keithdevens.com/ | #4130

ash wrote:

Does it make sense to also support HTTP authentication?

Sure it does.

∴ ash | 18-Mar-2004 5:07am est | #4172

Ryan Johnson wrote:

Just like you're planning on including convience functions, I'd like to see built in (as in, packaged with the library), object wrappers for methods and requests. Unlike most OO freaks, I've actually thought about why this is a good idea, should I send my code along? I've found wrapping the various methods in objects (that are extended from a base XMLRPC_method) a much more reliable and extensible way to handle things.

∴ Ryan Johnson | 29-Mar-2004 2:17am est | #4247

Keith (http://keithdevens.com/) wrote:

object wrappers for methods and requests

You mean to automatically expose all the methods of an object as an XML-RPC service?

If not that, I'm not quite sure what you're talking about, but I'd be happy to listen to your idea and read any code you send along. I'll e-mail you a copy of this comment and you can reply by e-mail. Or -- and this would be easier for me since it would ensure that your idea is kept along with this entry -- you could elaborate right here and paste whatever code you'd like to. Your choice.

Keith | 29-Mar-2004 2:30am est | http://keithdevens.com/ | #4248

Ryan Johnson wrote:

What I developed is a bit different than the way you interpeted my vauge statement above, so I'll describe it a bit better =) Basically, I wanted a simple way for people to be able to add methods to an RPC server, without having tons of variables floating around. On top of that, the methods themselves don't even call any of the XMLRPC functions, so if you upgrade or change systems, it's a trivial change to your code in one place. So here goes:

<?php
/* Assume these are somewhere in the XMLRPC library file, and are loaded with the rest of it. There are some constants that I've defined (all in caps), but otherwise it should fit in anywhere. */

class XMLRPC_request{
    var 
$request;
    var 
$method;
    var 
$params;
    
    function 
XMLRPC_Request(){
        
$this->request XMLRPC_parse(file_get_contents("php://input"));
        
$this->method = @XMLRPC_getMethodName($this->request);
        
$this->params = @XMLRPC_getParams($this->request);
    }
    
    function 
invokeMethod(){
        @require_once(
PATH_TO_EXTENSIONS.'xmlrpc.'.$this->method.'.php');
        
$classname 'XMLRPC_'.str_replace('.','_',$this->method);
        
$function_name str_replace('.','_',$this->method);
        if(
class_exists($classname)){
            
$response = new $classname();
            
$response->setup($this->params,$this->request,$function_name);
            
$response->run();
            if(!
$response->error&&$response->response)
                
XMLRPC_response(XMLRPC_prepare($response->response),XMLPRPC_AGENT);
            elseif(
$response->error&&is_null($response->response))
                
XMLRPC_error(2,'Method returned a null response'.':'.$method,XMLPRPC_AGENT);
            else
                
XMLRPC_error(2,$repsonse->error.':'.$method,XMLPRPC_AGENT);
        } else {
            
XMLRPC_error(2,L_XML_UNDEFINED_METHOD.':'.$method,XMLPRPC_AGENT);
        }
    }
}

class 
XMLRPC_method {
    var 
$params;
    var 
$error;
    var 
$request;
    var 
$classname;
    var 
$response;
    
    function 
XMLRPC_method(){}
    
    function 
setup(&$params,&$request,$function_name){
        
$this->params            =& $params;
        
$this->request            =& $request;
        
$this->error            FALSE;
        
$this->function_name    $function_name;
        
$this->response            NULL;
    }
    
    function 
run(){
        
$this->{$this->function_name}();
    }
}

class 
XMLRPC_call {
    var 
$success;
    var 
$response;
    
    function 
XMLRPC_call($url,$dir,$method,$params,$debug=FALSE){
        if(
$debug)
            
define('XMLRPC_DEBUG'1);
            
        if(!
is_array($params)){
            
$this->response '$params must be passed as an array.';
            
$this->succes FALSE;
            return;
        }
        
        
$req = array();
        foreach(
$params as $p)
            
$req[] = XMLRPC_prepare($p);
        list(
$success,$response) = XMLRPC_request($url,$dir,$method,$req);
        
$this->success $success;
        
$this->response $response;
        
        if(
$debug)
            
XMLRPC_debug_print();
    }
}
?>

Now, in a file where the call will point to:

<?php
if(isset($_GET['rpc'])) {

    require_once(
PATH_TO_CORE.'driver.xmlrpc.php');
    
$request = new XMLRPC_Request();
    
$params $request->params;
    
$request->invokeMethod();

}
?>

So here is a sample method. It's located in lib/extensions/kiwi.numToString.php (PATH_TO_EXTENSIONS was defined as 'lib/extensions/' in my script.

Notice that the method is called as kiwi.NumToString, but that the class and function are named with underscores because a period would be an invalid name. Note that because of the base class above, the params and response and error variable are already set. $this->error is set to false with begin with, and you just have to set it to anything but false to trigger an error. The key to the design of this, is that the user (implimentor) doesn't have to worry about anything XMLRPC related, taking your abstraction of the datatypes between PHP and XMLRPC slightly further. If this doesn't make sense by reading it, I can further document it.

<?php
class XMLRPC_kiwi_NumToString extends XMLRPC_method{
    function 
kiwi_NumToString(){
        switch(
$this->params[0]){
            case 
'1':
                
$this->response 'One';
                break;
            case 
'2':
                
$this->response 'Two';
                break;
            case 
'3':
                
$this->response 'Three';
                break;
            default:
                
$this->error 'Please choose a number, 1-3. You chose: '.$this->params[0];
                break;
        }
    }
}
?>

And now here's code that actually works (as in, you can query the server right now using the code in this comment).

<?php
require_once('lib/core/driver.xmlrpc.php');

$params[] = 2;
$request = new XMLRPC_call('kiwi3.com','/kiwi/?rpc','kiwi.numToString',$params,FALSE);
echo 
$request->response;
/* Response is "Two" */
?>

A lot of code to get the string Two, but hey, it works really well with complex applications too =)

If any of that doesn't make sense I can explain my rationale further. I think with PHP5 being so OO, something like this should come as an option. Even if this looks like unnessecary and useless OO, it really does compartmentalize things much more nicely, and make the implimentation code MUCH more consistent, at least for large applications. It's complete overkill for anything simple, I would agree to anyone who is critizing at this moment. - Ryan

∴ Ryan Johnson | 29-Mar-2004 3:56am est | #4249

Ryan Johnson wrote:

Something I'm not sure I made clear (that I just remembered), is that all you need to do to make a new method available on your RPC server is just drop a file called

your.MethodName.php

with the appropriate class name ( XMLRPC_your_MethodName in this case), in the folder which the script is looking in (in this case PATH_TO_EXTENSIONS), and that method automagically becomes available.

∴ Ryan Johnson | 29-Mar-2004 3:59am est | #4250

Ryan Johnson wrote:

One more thing I also forgot (total scatterbrain, sorry), was that the reason the call is split up in the server script above (the one that calls invokeMethod() ), is because usually I run $params through my authentication function to see wether to continue or not. I yanked that out for simplicity of the example.

∴ Ryan Johnson | 29-Mar-2004 4:02am est | #4251

Hartmut Seichter (http://www.technotecture.com) wrote:

Thanks for the script, it helped me to implement a lot of features for my little project. Take-and-give, I've cleaned up the call-by-reference things:

Download from here

Best Regards,
Hartmut

∴ Hartmut Seichter | 27-Mar-2005 2:06am est | http://www.technotecture.com | #7307

Gwyneth Llewelyn (http://gwynethllewelyn.net/) wrote:

Hello,

I'm no professional programmer, so I've used your library for some two years now for the very very simple cases where I need to do some XML-RPC requests, since it's a tiny library, non-OO, uses native PHP data types, and well, it's universally installable — no tricky bits or messing with php.ini. It's also incredibly stable, under all versions of PHP I tried.

The only thing that seems to be missing is the ability to communicate using HTTPS Smiley Several XML servers now require the ability to do either TLS encoding or sometimes even more sophisticated mechanisms... which are handled easily by libCURL (natively), fortunately, allowing me to play around with them.

I've thus added the following function (XMLRPC_request_CURL) to use CURL to do the request:

<?php
// Added by Gwyneth Llewelyn 20060730
// Uses libCURL to handle special cases
function XMLRPC_request_CURL($site$location$methodName$params NULL$user_agent NULL){
    
$data["methodCall"]["methodName"] = $methodName;
    
$param_count count($params);
    if(!
$param_count){
        
$data["methodCall"]["params"] = NULL;
    }else{
        for(
$n 0$n<$param_count$n++){
            
$data["methodCall"]["params"]["param"][$n]["value"] = $params[$n];
        }
    }
    
$data XML_serialize($data);

    if(
defined('XMLRPC_DEBUG') and XMLRPC_DEBUG){
        
XMLRPC_debug('XMLRPC_request'"<p>Received the following parameter list to send:</p>" XMLRPC_show($params'print_r'true));
    }
    
    
$headers = array("Content-Type: text/xml""Content-Length: " strlen($data));
    
    
$ch curl_init();
    
curl_setopt($chCURLOPT_URL$site $location);
    
curl_setopt($chCURLOPT_POST1); 
    
curl_setopt($chCURLOPT_POSTFIELDS$data); 
    
curl_setopt($chCURLOPT_POSTFIELDSIZEstrlen($data)); 
    
curl_setopt($chCURLOPT_RETURNTRANSFER1);
    
curl_setopt($chCURLOPT_TIMEOUT9);
    
curl_setopt($chCURLOPT_SSL_VERIFYPEERFALSE);
    
curl_setopt($chCURLOPT_HTTPHEADER$headers);
        
    
$response curl_exec($ch);
        
    if (
curl_errno($ch))
        
XMLRPC_debug('XMLRPC_request''<p>Connection failed: ' curl_error($ch) . '</p>');
    else
        
curl_close($ch);

    if(
defined('XMLRPC_DEBUG') and XMLRPC_DEBUG){
        
XMLRPC_debug('XMLRPC_request'"<p>Sent the following request:</p>\n\n" XMLRPC_show($headers $data'print_r'true));
    }

    
$data XML_unserialize($response);

    if(
defined('XMLRPC_DEBUG') and XMLRPC_DEBUG){
        
XMLRPC_debug('XMLRPC_request'"<p>Received the following response:</p>\n\n" XMLRPC_show($response'print_r'true) . "<p>Which was serialized into the following data:</p>\n\n" XMLRPC_show($data'print_r'true));
    }
    if(isset(
$data['methodResponse']['fault'])){
        
$return =  array(falseXMLRPC_adjustValue(&$data['methodResponse']['fault']['value']));
        if(
defined('XMLRPC_DEBUG') and XMLRPC_DEBUG){
            
XMLRPC_debug('XMLRPC_request'"<p>Returning:</p>\n\n" XMLRPC_show($return'var_dump'true));
        }
        return 
$return;
    }else{
        
$return = array(trueXMLRPC_adjustValue(&$data['methodResponse']['params']['param']['value']));
        if(
defined('XMLRPC_DEBUG') and XMLRPC_DEBUG){
            
XMLRPC_debug('XMLRPC_request'"<p>Returning:</p>\n\n" XMLRPC_show($return'var_dump'true));
        }
        return 
$return;
    }
}
?>

It works for me Smiley Just use $site with things like https://mysite.com or tls://mysite.com or even ftp://mysite.com Smiley

Of course, I cannot tell how much of a performance hit this is, compared to other libraries doing XML-RPC (PEAR, XML-RPC EPI, etc.), although CURL is at least implemented in C... The beauty of this is having everything working flawlessly, and since CURL supports so many different protocols, at least one can use your library with all of them Smiley

Thanks for your wonderful library!

- Gwyn

∴ Gwyneth Llewelyn | 30-Jul-2006 6:54am est | http://gwynethllewelyn.net/ | #9575

Feel free to post a comment below. Please see my comment policy.

Formatting Rules (No HTML):

  • **bold**, *italic*, _underlined_, --strikeout--
  • "text"="url" creates a link, and URLs are auto-highlighted
  • Blockquote: Like e-mail, begin paragraph with > (greater-than sign)
  • Lists: begin paragraph with *,-, or + (unordered), or # (ordered)
  • Code block: ?!code:language=perl|php|sql|javascript|etc.{\n}...{\n}?!/code

:
(will be your IP address if blank)
: (optional)
(Will not be shown on site)

: (optional)
:

July 2008
SunMonTueWedThuFriSat
 12345
6789101112
13141516171819
20212223242526
2728293031 



RSS feed RSS feed for Keith's Weblog
Atom feed Atom feed for Keith's Weblog
Weblog archive
Recent comments
  on 5 posts

Recent comments XML

Girls, please don't get breast implants

> And no, you will not be receiving​a picture.

:-(...

Keith: Jul 2, 6:05am

Javascript clone function

This is a clever way to clone an​object if you are using YAHOO UI.​Same tec...

Antonio: Jul 1, 12:47pm

I hate Norton Antivirus

Oh just one other thing norton is​great at keeping people out of your​compu...

kevin.sands: Jul 1, 12:50am

Terminator 3 was awful

I think the biggest reason why T3​totally blew was because Edward​Furlong g...

76.167.172.64: Jun 29, 3:06am

Generated in about 0.161s.

(Used 8 db queries)

mobile phone