You are here

function services_method_call in Services 5

Same name and namespace in other branches
  1. 6 services.module \services_method_call()
  2. 6.2 services.module \services_method_call()
  3. 7 services.module \services_method_call()

This is the magic function through which all remote method calls must pass.

2 calls to services_method_call()
services_admin_browse_test_submit in ./services_admin_browse.inc
xmlrpc_server_call_wrapper in servers/xmlrpc_server/xmlrpc_server.module

File

./services.module, line 339
The module which provides the core code for drupal services

Code

function services_method_call($method_name, $args = array(), $ignore_hash = FALSE) {
  $method = services_method_get($method_name);

  // Check that method exists.
  if (empty($method)) {
    return services_error(t('Method %name does not exist.', array(
      '%name' => $method_name,
    )));
  }

  // Check for missing args and identify if arg is required in the hash.
  $hash_parameters = array();
  foreach ($method['#args'] as $key => $arg) {
    if (!$arg['#optional']) {
      if (!isset($args[$key]) && !is_array($args[$key]) && !is_bool($args[$key])) {
        if ($arg['#name'] == 'sessid' && session_id()) {
          $args[$key] = session_id();
        }
        else {
          return services_error(t('Missing required arguments.'));
        }
      }
    }

    // Key is part of the hash
    if ($arg['#signed'] == TRUE && variable_get('services_use_key', TRUE)) {
      if (is_numeric($args[$key]) || !empty($args[$key])) {
        if (is_array($args[$key]) || is_object($args[$key])) {
          $hash_parameters[] = serialize($args[$key]);
        }
        else {
          $hash_parameters[] = $args[$key];
        }
      }
      else {
        $hash_parameters[] = '';
      }
    }
  }

  // Add additonal processing for methods requiring api key.
  if ($method['#key'] && variable_get('services_use_key', TRUE)) {
    $hash = array_shift($args);
    $domain = array_shift($args);
    $timestamp = array_shift($args);
    $nonce = array_shift($args);
    $expiry_time = $timestamp + variable_get('services_key_expiry', 30);
    if ($expiry_time < time()) {
      return services_error(t('Token has expired.'));
    }

    // Still in time but has it been used before
    if (db_result(db_query("SELECT count(*) FROM {services_timestamp_nonce} WHERE domain = '%s' AND timestamp = %d AND nonce = '%s'", $domain, $timestamp, $nonce))) {
      return services_error(t('Token has been used previously for a request.'));
    }
    else {
      db_query("INSERT INTO {services_timestamp_nonce} (domain, timestamp, nonce) VALUES ('%s', %d, '%s')", $domain, $timestamp, $nonce);
    }
    $api_key = db_result(db_query("SELECT kid FROM {services_keys} WHERE domain = '%s'", $domain));
    if (!services_validate_key($api_key, $timestamp, $domain, $nonce, $method_name, $hash_parameters, $hash)) {
      return services_error(t('Invalid API key.'));
    }
  }

  // Add additonal processing for methods requiring authentication.
  $session_backup = NULL;
  if ($method['#auth'] && variable_get('services_use_sessid', TRUE)) {
    $sessid = array_shift($args);
    if (empty($sessid)) {
      return services_error(t('Invalid sessid.'));
    }
    $session_backup = services_session_load($sessid);
  }

  // Check access
  $access_arguments = isset($method['#access arguments']) ? $method['#access arguments'] : $args;

  // Call default or custom access callback
  if (call_user_func_array($method['#access callback'], $access_arguments) != TRUE) {
    return services_error(t('Access denied.'));
  }

  // Change working directory to drupal root to call drupal function,
  // then change it back to server module root to handle return.
  $server_root = getcwd();
  $server_info = services_get_server_info();
  if ($server_info) {
    chdir($server_info->drupal_path);
  }
  $result = call_user_func_array($method['#callback'], $args);
  if ($server_info) {
    chdir($server_root);
  }

  // Add additonal processing for methods requiring authentication.
  if ($session_backup !== NULL) {
    services_session_unload($session_backup);
  }
  return $result;
}