Community Documentation

Example: node.save and CCK fields in PHP client code

Last updated April 6, 2010. Created by DartonW on September 22, 2009.
Edited by heyrocker. Log in to edit this page.

Services 6.x-2.x-dev on Drupal 6.14. Uses the XML-RPC for PHP library at http://phpxmlrpc.sourceforge.net/. Thanks to clues from http://drupal.org/node/303285 and the services tester, it includes some code for populating CCK fields ("field_publication", "field_byline", etc.). This is pre-production code for importing articles to a newspaper website, designed to run on the command line. I just left the parseXML() function as an example.

<?php
 
require('./xmlrpc-3.0.0.beta/lib/xmlrpc.inc');
 
$username = "username";
 
$pass = "password";
 
$domain = "example.com";
 
$publication = "The Daily Drupal";
 
$servicehost = "example.com";
 
$servicepath = "services/xmlrpc";
 
$sessid = "";
 
$uid = 0;
 
$xmlpath = "/path/to/xml";
 
$processdir = "/path/to/processed";
 
$successdir = "$processdir/success";
 
$failuredir = "$processdir/failure";
 
 
// Make initial connection to get a session ID
 
$m = new xmlrpcmsg('system.connect', array());
 
$c = new xmlrpc_client($servicepath, $servicehost, 80);
 
$c->return_type = "phpvals";
 
 
$r = &$c->send($m);
  if(!
$r->faultCode()){
   
$v = $r->value();
   
$sessid = ($v['sessid']);
  }else{
    die(
"An error occurred on system.connect: ".$r->faultString()."\n");
  }

 
// Using the session ID from the first connection, log in to the server
 
$m = new xmlrpcmsg("user.login",
    array(
      new
xmlrpcval($sessid),
      new
xmlrpcval($username),
      new
xmlrpcval($pass))
  );
   
// If login is successful, user object and a new sessid will be returned
 
$r = &$c->send($m);
  if(!
$r->faultCode()){
   
$v = $r->value();
   
// Only need uid for our purposes
   
$uid = $v['user']['uid'];
   
$sessid = $v['sessid'];
  }else{
    die(
"An error occurred on user.login: ".$r->faultString()."\n");
  }
 
 
// Open the XML directory and iterate files
 
$dir_handle = @opendir($xmlpath) or die("Unable to open $xmlpath\n");
 
  while (
$file = readdir($dir_handle))
  {
   
// Only get files named *.xml
   
if(end(explode(".", $file)) != "xml")
      continue;
   
   
// Ignore parsing errors for now and continue
   
libxml_use_internal_errors(true);
   
$xmldoc = simplexml_load_file("$xmlpath/$file");
    if(!
$xmldoc){
     
rename("$xmlpath/$file", "$failuredir/$file");
      continue;
    }
   
   
// Pass the XML to be parsed and get back a PHP node structure
   
$node = parseXML(&$xmldoc);
   
// Call the service to create the node
   
$nid = createNode($sessid, &$node);
   
   
// Move file to success or failure directory
   
if($nid > 0){
     
rename("$xmlpath/$file", "$successdir/$file");
      print
"Node $nid created.\n";
    }
    else{
     
rename("$xmlpath/$file", "$failuredir/$file");
    }
  }
 
 
closedir($dir_handle);
 
  function
parseXML($xmldoc){
    global
$publication;
   
// Initialize array container for node data
   
$node = array();
   
   
$node["publication"] = $publication;
   
$node["type"] = "story";
   
$node["format"] = 2;
   
   
$tmp = $xmldoc->xpath("//meta[@name='feed.doc.name']");
   
$node["filename"] = trim($tmp[0]['content']);
   
   
$tmp = $xmldoc->xpath("//meta[@name='feed.doc.id']");
   
$node["docid"] = trim($tmp[0]['content']);
   
   
$tmp = $xmldoc->xpath("//meta[@name='cms.section']");
   
$node["section"] = trim($tmp[0]['content']);

   
$tmp = $xmldoc->xpath("//meta[@name='cms.category']");
   
$node["category"] = trim($tmp[0]['content']);

   
$tmp = $xmldoc->xpath("//meta[@name='cms.release']");
   
$node["releasedate"] = trim($tmp[0]['content']);

   
$tmp = $xmldoc->xpath("//meta[@name='cms.expire']");
   
$node["expiredate"] = trim($tmp[0]['content']);

   
$tmp = $xmldoc->xpath("//meta[@name='position.rank']");
   
$node["positionrank"] = trim($tmp[0]['value']);
   
   
$tmp = $xmldoc->xpath("//pubdata");
   
$node["positionsection"] = trim($tmp[0]['position.section']);
   
$node["positionsequence"] = trim($tmp[0]['position.sequence']);
   
$node["pubdataname"] = trim($tmp[0]['name']);
   
   
$node["headline"] = $xmldoc->body->{'body.head'}->hedline->hl1;
   
   
$node["subhead"] = $xmldoc->body->{'body.head'}->hedline->hl2;
   
   
$node["byline"] = $xmldoc->body->{'body.head'}->byline->person;
   
   
$node["bylinecredit"] = $xmldoc->body->{'body.head'}->bylinecredit->site;
   
   
// Try to access the body in different ways to account for screwy XML
   
$tmp = $xmldoc->body->{'body.content'};
    foreach(
$tmp->children() as $element){
      if(
$element->getName() !== "media")
       
$node["body"] .= $element->asXML();
    }
   
    if(
$node["body"] === "")
     
$node["body"] = $xmldoc->body->{'body.content'};
   
   
// Ampersands are encoded but need to be unencoded for other HTML characters
   
$node["body"] = preg_replace("/&amp;/", "&", $node["body"]);
   
    return
$node;
  }
 
 
// Handle node.save and CCK fields
 
function createNode($sessid, $node){
    global
$c, $uid, $username;
   
   
$edit = new xmlrpcval(
      array(
       
"uid" => new xmlrpcval($uid, "int"),
       
"name" => new xmlrpcval($username),
       
"type" => new xmlrpcval($node["type"]),
       
"format" => new xmlrpcval($node["format"], "int"),
       
"title" => new xmlrpcval($node["headline"]),
       
"body" => new xmlrpcval($node["body"]),
       
"field_publication" => new xmlrpcval(array(new xmlrpcval(array("value" => new xmlrpcval($node["publication"])), "struct")), "array"),
       
"field_byline" => new xmlrpcval(array(new xmlrpcval(array("value" => new xmlrpcval($node["byline"])), "struct")), "array"),
       
"field_section" => new xmlrpcval(array(new xmlrpcval(array("value" => new xmlrpcval($node["section"])), "struct")), "array"),
       
"field_category" => new xmlrpcval(array(new xmlrpcval(array("value" => new xmlrpcval($node["category"])), "struct")), "array")
      ),
     
"struct"
   
);
   
   
$m = new xmlrpcmsg("node.save",
      array(
        new
xmlrpcval($sessid),
       
$edit
     
)
    );
   
   
$r = &$c->send($m);
    if(!
$r->faultCode()){
     
$nid = $r->value();
      return
$nid;
    }else{
      print (
"An error occurred on node.save: ".$r->faultString()."\n");
     
$nid = 0;
      return
$nid;
    }
  }
?>

Comments

Has anyone had luck with this

Has anyone had luck with this using drupal 6.15 and services 6.2 beta1 (I tried dev 6.2 as well but the same problem)? I have essentially replicated this, except of course not using the cck fields.

I had to remove $sessid from user.login msg too as it would not work with it, otherwise it's the same.

I did open an issue (http://drupal.org/node/708508) with services, but I began to wonder if the problem is within the client?

did you set the

did you set the authentication module to 'Key authentication' and check the 'Use sessid' box in your services settings?

I can get past the user.login function but am stuck at node.save. I was getting a fatal error that looked like I didn't have xmlrpc enabled in my php install but found that I didn't have Node Service enabled - I enabled that and the errors went away. But it is still not creating the node. I dumped the data to make sure I was sending the required data. Does anyone have any insight?

Taxonomy

I'm trying to get taxonomy (predefined selection) terms with the node.save, but i seem not to do it right. Any directions on putting it in the right datastructure?

--
d-Media Web Professionals
http://d-media.nl

was trying to figure that out too

this is what worked for me yesterday using Services 6.x-2.0:

<?php
"taxonomy" => new xmlrpcval(
                array(
                   
$node['vid'] => new xmlrpcval(
                        array(
                            new
xmlrpcval($node['tid'],'int')
                        ),
                       
'array'),
                ),
           
'struct'),
?>

where $node['vid'] is the vocabulary id and $node['tid'] is the term id

this was for a single select non-tag vocabulary

Haven't tested this yet...

Haven't tested this yet... but seems right to me. I switched from an implementation with services to a in drupal solution where i was able to insert directly

--
d-Media Web Professionals
http://d-media.nl

Taxonomy tag on node.save

How to update a taxonomy tag name in node object using node.save via xmlrpc?

user.save based on the above script

Services 6.x-2.2 on Drupal 6.16. This code creates a user and changes that user's roles. (With thanks to the original author who saved me half a day's work)

<?php
 
require('./xmlrpc-3.0.0.beta/lib/xmlrpc.inc');

 
/*
    Example client program to change user settings.

    Install Services
    Enable modules: Services, Key Authentication, XMLRPC Server, System Service and User Service.
    Configuration:
      Services: in admin/build/services/settings
        set 'Authentication module:' to 'Key Authentication'
        uncheck 'Use Keys'
        check 'Use sessid'
      Permissions (for the Services user role): in admin/user/permissions
        under 'system_service module':
          check 'get available services'
          check 'log a system message from remote'
        under 'user module':
          check 'administer permissions' (actually roles)
          check 'administer users'
        under 'user_service module':
          check 'create new users'
          check 'get any user data'
          check 'get own user data'
          check 'update any user data'
          check 'update own user data'
    Check: in admin/build/services/browse check that the servers (XMLRPC) and services (system, user) are available.

    Note: other than 2 => "authenticated user", the role ids and names are specific to your Drupal application,
    and will need changing.
  */

  /**
   * Convert the user structure to an XML-RPC structure.
   *
   * @param $user the user data structure.
   * @return the XML-RPC data structure.
   */
 
function user_to_xmlrpc($user) {
   
$xmlrpc = array();

   
// might not have a uid yet
   
if ($user['uid']) {
     
$xmlrpc['uid'] = new xmlrpcval($user['uid'], "int");
    }
   
$xmlrpc['name'] = new xmlrpcval($user['name']);
    if (
$user['pass']) {
     
$xmlrpc['pass'] = new xmlrpcval($user['pass']);
    }
   
$xmlrpc['mail'] = new xmlrpcval($user['mail']);
   
$xmlrpc['status'] = new xmlrpcval($user['status'], "int");
   
$xmlrpc['timezone'] = new xmlrpcval($user['timezone'], "int");
   
$xmlrpc['language'] = new xmlrpcval($user['language']);
    if (
$user['roles']) {
     
$roles = array();
      foreach(
$user['roles'] as $role_id => $role_name) {
       
$roles[$role_id] = new xmlrpcval($role_name);
      }
     
$xmlrpc['roles'] = new xmlrpcval($roles, "struct");
    }
    return new
xmlrpcval($xmlrpc, "struct");
  }

 
/**
   * Get the roles we want to set.
   *
   * @return the roles.
   */
 
function get_roles() {
    return array(
     
2 => 'authenticated user',
     
11 => 'editore',
     
21 => 'banca',
     
31 => 'imprenditore'
   
);
  }

  print(
"Example XML-RPC client for Drupal Services\n");

 
$service_host = "dev.autonomous-sandbox"; // set to the actual domain (this is a local domain)
 
$service_path = "services/xmlrpc";

 
$session_id = "";
 
$username = "external"; // XML-RPC user
 
$password = "external"; // XML-RPC password
 
$uid = 0;

 
$created_uid = 50; // previously created uid (from a previous run of the script) otherwise use -1
 
$created_user = NULL;

 
// make initial connection and get the session id
 
$message = new xmlrpcmsg('system.connect', array());
 
$client = new xmlrpc_client($service_path, $service_host, 80);
 
$client->return_type = "phpvals";

  print(
"Connecting to: ". $service_host ."/". $service_path ."\n");

 
$result = &$client->send($message);
  if (!
$result->faultCode()) {
   
$value = $result->value();
   
$session_id = $value['sessid'];
  }
  else {
    die(
"An error occurred on system.connect: ". $result->faultCode() .": ". $result->faultString() ."\n");
  }

 
// log in to the server using the session id
 
$message = new xmlrpcmsg("user.login",
    array(
      new
xmlrpcval($session_id),
      new
xmlrpcval($username),
      new
xmlrpcval($password)
    )
  );

  print(
"Logging in as: ". $username ."\n");

 
// if login is successful, user object and a new session id will be returned
 
$result = &$client->send($message);
  if (!
$result->faultCode()) {
   
$value = $result->value();
   
// Only need uid for our purposes
   
$uid = $value['user']['uid'];
   
$session_id = $value['sessid'];
  }
  else {
    die(
"An error occurred on user.login: ". $result->faultCode() .": ". $result->faultString() ."\n");
  }

  print(
"Logged in uid is: ". $uid ."\n");

 
//
  // test examples - check if a user exists, if not create it, then set a (known role)
  //

  // check if the created user id exists, if not create it
 
$message = new xmlrpcmsg("user.get",
    array(
      new
xmlrpcval($session_id),
      new
xmlrpcval($created_uid)
    )
  );

 
// if user.get is successful, user object will be returned
 
$result = &$client->send($message);
  if (!
$result->faultCode()) {
   
$created_user = $result->value();
   
$created_uid = $created_user['uid'];
    print(
"Found user: ". print_r($created_user, TRUE). "\n");
    unset(
$created_user['pass']); // remove the password
 
}
  else {
   
// assume the fault is caused by the user not existing
   
$created_user = array(
     
'name' => 'created_user',
     
'pass' => 'created_user',
     
'mail' => 'created_user@example.com',
     
'status' => 1,
     
'timezone' => 7200, // GMT + 2
     
'language' => 'it',
     
'roles' => get_roles()
    );

   
$message = new xmlrpcmsg("user.save",
      array(
        new
xmlrpcval($session_id),
       
user_to_xmlrpc($created_user)
      )
    );

   
// if user.save is successful, user id will be returned
   
$result = &$client->send($message);
    if (!
$result->faultCode()) {
     
$created_uid = $result->value();
      print(
"Created user: ". print_r($created_user, TRUE) ."\n");

     
$message = new xmlrpcmsg("user.get",
        array(
          new
xmlrpcval($session_id),
          new
xmlrpcval($created_uid)
        )
      );

     
// if user.get is successful, user object will be returned
     
$result = &$client->send($message);
      if (!
$result->faultCode()) {
       
$created_user = $result->value();
        print(
"Retrieved user(". $created_uid ."): ". print_r($created_user, TRUE). "\n");
        unset(
$created_user['pass']); // remove the password
     
}
      else {
        die(
"An error occurred on user.get(". $created_uid ."): ". $result->faultCode() .": ". $result->faultString() ."\n");
      }
    }
    else {
      die(
"An error occurred on user.save: ". $result->faultCode() .": ". $result->faultString() ."\n");
    }
  }

 
//
  // end test examples
  //

  // logout from the connection
 
$message = new xmlrpcmsg("user.logout",
    array(
      new
xmlrpcval($session_id)
    )
  );

  print(
"Logging out\n");

 
$result = &$client->send($message);
  if (!
$result->faultCode()) {
   
// $value = $result->value();
 
}
  else {
    die(
"An error occurred on user.logout: ". $result->faultCode() .": ". $result->faultString() ."\n");
  }
?>

Più imparo, più dubito. The more I learn, the more I doubt.

Page status

No known problems

Log in to edit this page

About this page

Drupal version
Drupal 6.x
Audience
Contributors, Programmers

Develop for Drupal

Drupal’s online documentation is © 2000-2013 by the individual contributors and can be used in accordance with the Creative Commons License, Attribution-ShareAlike 2.0. PHP code is distributed under the GNU General Public License. Comments on documentation pages are used to improve content and then deleted.
nobody click here