Services 6.x-2.0 PHP xmlrpc example with api key

Last updated on
30 April 2025

Here's some working logic that I cobbled together from various partial examples online and the deploy module. It's rough, but works. The key difference in this example from others is the fact that this version only uses Drupal API routines, rather than the 'experimental' PHP routines such as xmlrpc_encode_request() ( see http://php.net/manual/en/function.xmlrpc-encode-request.php ) and xmlrpc_decode(). Such routines may not exist in some environments and are also subject to change.

<?php
/***************************************************/
class DrupalXmlrpc {
 
  function __construct( $domain = '', $apiKey = '', $endPoint = '', $verbose = FALSE ) 
  {
    // set local domain or IP address
    // this needs to match the domain set when you created the API key
    $this->domain = $domain;
   
    // set API key
    $this->kid = $apiKey;
   
    // set target web service endpoint
    $this->endpoint = $endPoint;

	// extended debugging
	$this->verbose = $verbose;
   
	// call system.connect to get our required anonymous sessionId:
	$retVal = $this->send( 'system.connect', array() );
    $this->session_id = $retVal['sessid'];

	if ($this->verbose) {
	   $func = 'DrupalXmlrpc->__construct:';
	   if ($this->session_id)
	        error_log( $func.' got anonymous session id fine' );
	   else error_log( $func.' failed to get anonymous session id!' );
	}
  }
 
  /***********************************************************************
  * Function for sending xmlrpc requests
  */
  public function send( $methodName, $functionArgs = array() )
  {
    $protocolArgs = array();
	// only the system.connect method does not require a sessionId:
    if ($methodName == 'system.connect') {
	   $protocolArgs = array( $this->endpoint, $methodName );
	}
	else {
       $timestamp = (string)time();
       $nonce = $this->getUniqueCode("10");
   
       // prepare a hash
       $hash_parameters = array( $timestamp, $this->domain, $nonce, $methodName );
       $hash = hash_hmac("sha256", implode(';', $hash_parameters), $this->kid);
   
       // prepared the arguments for this service:
	   // note, the sessid needs to be the one returned by user.login
       $protocolArgs = array( $this->endpoint, $methodName, $hash, $this->domain, $timestamp, $nonce, $this->session_id );
	}

	$params = array_merge( $protocolArgs, $functionArgs );
	return call_user_func_array( 'xmlrpc', $params );
  }

  /***************************************************
   * login and return user object
   */
  public function userLogin( $userName = '', $userPass = '' ) 
  {
	if ($this->verbose)
         error_log( 'DrupalXmlrpc->userLogin() called with userName "'.$userName.'" and pass "'.$userPass.'"' );

	// clear out any lingering xmlrpc errors:
	xmlrpc_error( NULL, NULL, TRUE );

    $retVal = $this->send( 'user.login', array($userName, $userPass) );
	if (!$retVal && xmlrpc_errno()) {
	   if ($this->verbose)
	      error_log( 'userLogin() failed! errno "'.xmlrpc_errno().'" msg "'.xmlrpc_error_msg().'"' );
	   return FALSE;
	}
	else {
	   // remember our logged in session id:
       $this->session_id = $retVal['sessid'];

       // we might need the user object later, so save it:
       $user = new stdClass();
       $user = (object)$response['user'];
       $this->authenticated_user = $user;
       return $user;
	}
  }

  /***************************************************
   * logout, returns 0 for okay, or -1 for error.
   */
  public function userLogout()
  {
    $retVal = $this->send( 'user.logout', array() );
	if (!$retVal) {
	   if ($this->verbose)
	      error_log( 'userLogout() failed! errno "'.xmlrpc_errno().'" msg "'.xmlrpc_error_msg().'"' );
	   return -1;
	}

    return 0; // meaning okay
  }

  /***************************************************
  * Function for generating a random string, used for
  * generating a token for the XML-RPC session
  */
  private function getUniqueCode($length = "") 
  {
    $code = md5(uniqid(rand(), true));
    if ($length != "") 
         return substr($code, 0, $length);
    else return $code;
  }
}
?>

Use it like this:

<?php
       // create a drupal session:
       $localDomain   = 'whatever domain you used when you created this api key';
       $apiKey        = 'Services generated api key string';
       $endPoint      = 'url to your destination endpoint';
       $drupalSession = new DrupalXmlrpc( $localDomain, $apiKey, $endPoint );
       if ($drupalSession->session_id) {

          $userName   = 'username used to login to remote system';
          $userPass   = 'password of user on remote system';
          $drupalUser = $drupalSession->userLogin( $userName, $userPass );
          if ($drupalUser) {

             $result = $drupalSession->send( 'method.name-of-remote-function, array(remote-functions-parameters-in-an-array) );

             if ($result == -1) 
                $retVal = SOME_SYMBOL_MEANING_REMOTE_WORK_FAILED;
  
             $drupalSession->userLogout(); // all done communicating, so logout
		  }
		  else {
			 $retVal = SOME_SYMBOL_MEANING_LOGIN_FAILED;
		  }
       }
       else {
          $retVal = SOME_SYMBOL_MEANING_CONNECTION_FAILED;
       }
?>

I hope this is useful for others.

Help improve this page

Page status: Not set

You can: