Using MetaWebLog with PHP-XMLRPC

Due to the fact that there is virtually no documentation available on how to get the MetaWebLog API working with the PHP-XMLRPC library, I decided to write this post. The MetaWebLog API is an application programming interface that allows data to be passed from a client to a server, and vice versa. It is used by all of the most popular blogging software, allowing the user to post blog entries from software like Microsoft Word or Windows Live Writer.

If you want to add MetaWebLog functionality to your custom blog or CMS, then this post will really help you. First off, download the PHP-XMLRPC library and upload the three files - xmlrpc.inc, xmlrpcs.inc, xmlrpc_wrappers.inc - found within the lib folder to your web server.

With that done, you can now start implementing the MetaWebLog functions. The first one you’ll need to implement is blogger.getUsersBlogs, otherwise software like Microsoft Word won’t recognise it as a valid MetaWebLog implementation. With that done, you can then start working on the functions that you might need to use.

To debug your code, make sure you take advantage of the XMLRPC debugger. And for more information on what each function is supposed to accept and return, check out Microsoft’s MSDN.

Below is the MetaWebLog implementation I developed to work with the PHP-XMLRPC library:


<?php // These three files are from the PHP-XMLRPC library.
    include(
“xmlrpc.inc”);
    include(
“xmlrpcs.inc”);
    include(
“xmlrpc_wrappers.inc”);

    /**
    * Used to test usage of object methods in dispatch maps
    */
    
class xmlrpc_server_methods_container
    
{

    }

  function userLogin($username$password$area) {

    // This is where you would check to see if the username and password are valid
    // and whether the user has rights to perform this action ($area)
    // Return true if so. Or false if the login info is wrong.

  }

    $getUsersBlogs_sig=array(array($xmlrpcArray$xmlrpcString$xmlrpcString$xmlrpcString));
    
$getUsersBlogs_doc=‘Returns a list of weblogs to which an author has posting privileges.’;
    function 
getUsersBlogs($xmlrpcmsg)
    {
    
$structArray = array();
    
$structArray[] = new xmlrpcval(array(
      
‘isAdmin’        => new xmlrpcval(true‘boolean’),
      
‘url’        => new xmlrpcval(‘http://blogurl’’string’),
      
‘blogid’    => new xmlrpcval(“The Blog ID”’string’),
      
‘blogName’    => new xmlrpcval(‘The Blog Name’’string’),
      
‘xmlrpc’    => new xmlrpcval(‘http://LocationOfThisFile’’string’)
      ), 
’struct’);    
        return new 
xmlrpcresp(new xmlrpcval($structArray,‘array’));
    }

    $newPost_sig=array(array($xmlrpcBoolean$xmlrpcString$xmlrpcString$xmlrpcString$xmlrpcStruct$xmlrpcBoolean));
    
$newPost_doc=‘Post a new item to the blog.’;
    function 
newPost($xmlrpcmsg)
    {
    
$blogid=$xmlrpcmsg->getParam(0)->scalarval();
    
$username=$xmlrpcmsg->getParam(1)->scalarval();
    
$password=$xmlrpcmsg->getParam(2)->scalarval();
    
    if(
userLogin($username$password‘addnews’) == true) {
      
$content=$xmlrpcmsg->getParam(3);
      
$title $content->structMem(‘title’)->scalarval();
      
$description $content->structMem(‘description’)->scalarval();
      
//$dateCreated = $content->structMem(’dateCreated’)->serialize();   // Not all clients send dateCreated info. So add if statement here if you want to use it.
      //$timestamp = iso8601_decode($dateCreated);  // To convert to unix timestamp
      
if($content->structMem(‘categories’)->arraySize() > 0) {
        
$categories $content->structMem(‘categories’)->arrayMem(0)->scalarval();
      }
      
$published=$xmlrpcmsg->getParam(4)->scalarval();

      // Put your DB queries in here to store the new post.       

      return new xmlrpcresp(new xmlrpcval($postid,’string’)); // Return the id of the post just inserted into the DB. See mysql_insert_id() in the PHP manual.
        } else {
      return new 
xmlrpcresp(0$xmlrpcerruser+1“Login Failed”);
        }
    }
    
    
    
$editPost_sig=array(array($xmlrpcBoolean$xmlrpcString$xmlrpcString$xmlrpcString$xmlrpcStruct$xmlrpcBoolean));
    
$editPost_doc=‘Edit an item on the blog.’;
    function 
editPost($xmlrpcmsg)
    {
    
$postid=$xmlrpcmsg->getParam(0)->scalarval();
    
$username=$xmlrpcmsg->getParam(1)->scalarval();
    
$password=$xmlrpcmsg->getParam(2)->scalarval();
    
    if(
userLogin($username$password‘editnews’) == true) {
      
$content=$xmlrpcmsg->getParam(3);
      
      
$title $content->structMem(‘title’)->scalarval();
      
$description $content->structMem(‘description’)->scalarval();
      
//$dateCreated = $content->structMem(’dateCreated’)->serialize();   // Not all clients send dateCreated info. So add if statement here if you want to use it.
      //$timestamp = iso8601_decode($dateCreated);  // To convert to unix timestamp
      
if($content->structMem(‘categories’)->arraySize() > 0) {
        
$categories $content->structMem(‘categories’)->arrayMem(0)->scalarval();
      }
      
$published=$xmlrpcmsg->getParam(4)->scalarval();
      
      
// Put your DB queries in here to update the post corresponding to the $postid.  

      return new xmlrpcresp(new xmlrpcval(true,‘boolean’));
        } else {
      return new 
xmlrpcresp(0$xmlrpcerruser+1“Login Failed”);
        }
    }
    

    $getPost_sig=array(array($xmlrpcStruct$xmlrpcString$xmlrpcString$xmlrpcString));
    
$getPost_doc=‘Get an item on the blog.’;
    function 
getPost($xmlrpcmsg)
    {
    
$postid=$xmlrpcmsg->getParam(0)->scalarval();
    
$username=$xmlrpcmsg->getParam(1)->scalarval();
    
$password=$xmlrpcmsg->getParam(2)->scalarval();
    
    if(
userLogin($username$password‘editnews’) == true) {
      
      
$result mysql_query(“SELECT * FROM sometable WHERE id=’$postid’ LIMIT 1″);
      while (
$row mysql_fetch_assoc($result)) {
        return new 
xmlrpcresp(new xmlrpcval(array(
            
‘postid’        => new xmlrpcval($row[‘id’], ’string’),
            
‘dateCreated’        => new xmlrpcval(iso8601_encode($row[‘timestamp’]), ‘dateTime.iso8601′),
            
‘title’        => new xmlrpcval($row[‘title’], ’string’),
            
‘description’        => new xmlrpcval($row[‘content’], ’string’),
            
‘categories’        => new xmlrpcval(array(new xmlrpcval($row[‘category’], ’string’)), ‘array’),
            
‘publish’        => new xmlrpcval($row[‘published’], ‘boolean’)
            ), 
’struct’));
      }
        } else {
      return new 
xmlrpcresp(0$xmlrpcerruser+1“Login Failed”);
        }
    }
    

    function deletePost($xmlrpcmsg)
    {
    
$postid=$xmlrpcmsg->getParam(1)->scalarval();
    
$username=$xmlrpcmsg->getParam(2)->scalarval();
    
$password=$xmlrpcmsg->getParam(3)->scalarval();
    
    if(
userLogin($username$password‘editnews’) == true) {
      
      
$query “DELETE FROM sometable WHERE id=$postid LIMIT 1″;
      
mysql_query($query) or die (mail(“your@email.com”,“Error with MetaWebLog deleting new post”,$query ‘ | ’ mysql_error()));
      
      return new 
xmlrpcresp(new xmlrpcval(true,‘boolean’));
        } else {
      return new 
xmlrpcresp(0$xmlrpcerruser+1“Login Failed”);
        }
    }
    
    
    
$getRecentPosts_sig=array(array($xmlrpcArray$xmlrpcString$xmlrpcString$xmlrpcString$xmlrpcInt));
    
$getRecentPosts_doc=‘Get the recent posts on the blog.’;
    function 
getRecentPosts($xmlrpcmsg)
    {
    
$blogid=$xmlrpcmsg->getParam(0)->scalarval();
    
$username=$xmlrpcmsg->getParam(1)->scalarval();
    
$password=$xmlrpcmsg->getParam(2)->scalarval();
    
    if(
userLogin($username$password‘addnews’) == true) {
      
$numposts=$xmlrpcmsg->getParam(3)->scalarval();

      $structArray = array();
      
      
$result mysql_query(“SELECT * FROM sometable ORDER BY timestamp DESC LIMIT $numposts”);
      while (
$row mysql_fetch_assoc($result)) {
        
$structArray[] = new xmlrpcval(array(
          
‘postid’        => new xmlrpcval($row[‘id’], ’string’),
          
‘dateCreated’        => new xmlrpcval(iso8601_encode($row[‘timestamp’]), ‘dateTime.iso8601′),
          
‘title’        => new xmlrpcval($row[‘title’], ’string’),
          
‘description’        => new xmlrpcval($row[‘content’]),
          
‘categories’        => new xmlrpcval(array(new xmlrpcval($row[‘category’], ’string’)), ‘array’),
          
‘publish’        => new xmlrpcval($row[‘published’], ‘boolean’)
          ), 
’struct’);    
       }
      return new 
xmlrpcresp(new xmlrpcval($structArray ‘array’)); // Return type is struct[] (array of struct)
        } else {
      return new 
xmlrpcresp(0$xmlrpcerruser+1“Login Failed”);
        }
    }
    
    
$getCategories_sig=array(array($xmlrpcArray$xmlrpcString$xmlrpcString$xmlrpcString));
    
$getCategories_doc=‘Get the categories on the blog.’;
    function 
getCategories($xmlrpcmsg) {
    
    
$username=$xmlrpcmsg->getParam(1)->scalarval();
    
$password=$xmlrpcmsg->getParam(2)->scalarval();
    
    if(
userLogin($username$password‘addnews’) == true) {
    
      
$structArray = array();
      
      
$result mysql_query(“SELECT * FROM categories”);
      while (
$row mysql_fetch_assoc($result)) {
        
$structArray[] = new xmlrpcval(array(
          
‘title’        => new xmlrpcval($row[‘title’], ’string’),
          
‘description’        => new xmlrpcval($row[‘description’], ’string’)
          ), 
’struct’);    
       }
      return new 
xmlrpcresp(new xmlrpcval($structArray ‘array’)); // Return type is struct[] (array of struct)
    } else {
      return new 
xmlrpcresp(0$xmlrpcerruser+1“Login Failed”);
        }
        
    }
    
    
$newMediaObject_sig=array(array($xmlrpcStruct$xmlrpcString$xmlrpcString$xmlrpcString$xmlrpcStruct));
    
$newMediaObject_doc=‘Upload media files onto the blog server.’;
    function 
newMediaObject($xmlrpcmsg)
    {
    
$username=$xmlrpcmsg->getParam(1)->scalarval();
    
$password=$xmlrpcmsg->getParam(2)->scalarval();
    
    if(
userLogin($username$password‘addnews’) == true) {
      
      
$file=$xmlrpcmsg->getParam(3);
      
$filename $file->structMem(‘name’)->scalarval();
      
$filename substr($filename, (strrpos($filename,“/”)+1));
      
//$type = $file->structMem(’type’)->scalarval(); // The type of the file
      
$bits $file->structMem(‘bits’)->serialize();
      
$bits str_replace(“<value><base64>”,“”,$bits);
      
$bits str_replace(“</base64></value>”,“”,$bits);
      
$uploaddir ‘/home/yourhostingusername/public_html/uploads/’; // Make sure this folder has been chmoded to 777.
      if(
fwrite(fopen($uploaddir $filename“xb”), base64_decode($bits)) == false) {
        return new 
xmlrpcresp(0$xmlrpcerruser+1“File Failed to Write”);
      } else {
        return new 
xmlrpcresp(new xmlrpcval(array(‘url’ => new xmlrpcval(‘http://blogurl.com/uploads/’.$filename’string’)),’struct’));
      }
        } else {
      return new 
xmlrpcresp(0$xmlrpcerruser+1“Login Failed”);
        }
    }

    $o=new xmlrpc_server_methods_container;
    
$a=array(
    
‘blogger.getUsersBlogs’ => array(
      
‘function’ => ‘getUsersBlogs’,
      
‘docstring’ => $getUsersBlogs_doc,
      
’signature’ => $getUsersBlogs_sig
    
),
        
“metaWeblog.newPost” => array(
            
“function” => “newPost”,
            
“signature” => $newPost_sig,
            
“docstring” => $newPost_doc
        
), 
        
“metaWeblog.editPost” => array(
            
“function” => “editPost”,
            
“signature” => $editPost_sig,
            
“docstring” => $editPost_doc
        
),
        
“metaWeblog.getPost” => array(
            
“function” => “getPost”,
            
“signature” => $getPost_sig,
            
“docstring” => $getPost_doc
        
),
        
“metaWeblog.getRecentPosts” => array(
            
“function” => “getRecentPosts”,
            
“signature” => $getRecentPosts_sig,
            
“docstring” => $getRecentPosts_doc
        
),
        
“metaWeblog.getCategories” => array(
            
“function” => “getCategories”,
            
“signature” => $getCategories_sig,
            
“docstring” => $getCategories_doc
        
),
        
“metaWeblog.newMediaObject” => array(
            
“function” => “newMediaObject”,
            
“signature” => $newMediaObject_sig,
            
“docstring” => $newMediaObject_doc
        
),/*
            ’blogger.getUserInfo’ => array(
                ’function’ => ’getUserInfo’,
                ’docstring’ => ”Returns information about an author in the system.”,
                ’signature’ => array(array($xmlrpcStruct, $xmlrpcString, $xmlrpcString, $xmlrpcString))
            )*/
            
‘blogger.deletePost’ => array(
                
‘function’ => ‘deletePost’,
                
‘docstring’ => ‘Deletes a post.’,
                
’signature’ => array(array($xmlrpcBoolean$xmlrpcString$xmlrpcString$xmlrpcString$xmlrpcString$xmlrpcBoolean)) 
            )
    );

    $s=new xmlrpc_server($afalse);
    
$s->setdebug(2);

    $s->service();
    
// that should do all we need!
?>

I hope that helps you. :)

1 Comment »

The URI to TrackBack this entry is: http://ryanhemelaar.blogsome.com/2009/01/29/using-metaweblog-with-php-xmlrpc/trackback/

  1. thanks for this code. this really help meh.

    Comment by Parantar — February 26, 2009 @ 2:13 pm

RSS feed for comments on this post.

Leave a comment

Line and paragraph breaks automatic, e-mail address never displayed, HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>