You are here

abstract class EntityShareServerRestAbstract in Entity Share 7

Abstract Class to manage the EntityShare Rest server.

Hierarchy

Expanded class hierarchy of EntityShareServerRestAbstract

File

modules/entity_share_server/includes/entity_share_server.rest.abstract.inc, line 11
Class for handling Entity Share Rest Server request.

View source
abstract class EntityShareServerRestAbstract {

  /**
   * Http request.
   *
   * @var array
   *   The HTTP request.
   */
  protected $request;

  /**
   * Http response.
   *
   * @var array
   *   The HTTP response.
   */
  protected $response;

  /**
   * Http headers.
   *
   * @var array
   *   The HTTP headers.
   */
  protected $headers = array();

  /**
   * Result.
   *
   * @var array
   *   The results.
   */
  protected $result;

  /**
   * Error.
   *
   * @var mixed
   *   The error.
   */
  protected $error;
  const STATUS_ERROR = 'KO';
  const STATUS_OK = 'OK';
  const HOOK_PREFIX = 'es_server_rest_';
  const WATCHDOG_TYPE = 'entity_share_server_rest';
  const IP_RESTRICTED_VARIABLE = 'entity_share_server_allowed_ips';

  /**
   * Constructor. Initialize properties.
   */
  public function __construct() {
    $this
      ->parseRequest();
  }

  /**
   * Get the parameter value.
   *
   * @param string $name
   *   Name of th parameter.
   *
   * @return mixed|null
   *   The parameter value, NULL otherwise.
   */
  public function getParam($name) {
    return isset($this->request[$name]) ? $this->request[$name] : NULL;
  }

  /**
   * Get the Request.
   *
   * @return array|null
   *   The HTTP request.
   */
  public function getRequest() {
    return $this->request;
  }

  /**
   * Get the method of the request.
   *
   * @return string
   *   The HTTP request method (GET, POST etc.).
   */
  public function getRequestMethod() {
    return $_SERVER['REQUEST_METHOD'];
  }

  /**
   * Get the result of the action.
   *
   * @return mixed
   *   The results.
   */
  public function getResult() {
    return $this->result;
  }

  /**
   * Set the result of the action.
   *
   * @param mixed $result
   *   The result to set.
   *
   * @return EntityShareServerRestAbstract
   *   The current class instance.
   */
  protected function setResult($result) {
    $this->result = $result;
    return $this;
  }

  /**
   * Get the error of the action.
   *
   * @return mixed
   *   The potential error.
   */
  public function getError() {
    return $this->error;
  }

  /**
   * Set the error of the action.
   *
   * @param string $error
   *   The potential error to set.
   * @param string $status
   *   The http error status.
   *
   * @return EntityShareServerRestAbstract
   *   The current class instance.
   */
  protected function setError($error, $status = '400 Bad Request') {
    $this->error = $error;
    $this
      ->setHeader('Status', $status);
    return $this;
  }

  /**
   * Handle the server.
   */
  public function handle() {
    try {

      // Security.
      if (!$this
        ->isRequestAllowed()) {
        $this
          ->setHeader('Status', '403 Forbidden');
        $this
          ->sendHeaders();
        return;
      }
      switch ($this
        ->getParam('type')) {
        case 'login':
          switch ($this
            ->getRequestMethod()) {
            case 'POST':

              // Manage login.
              $this
                ->doLogin();
              break;
            default:
              $this
                ->setError('HTTP Method not managed');
          }
          break;
        default:

          // HTTP_METHOD.
          switch ($this
            ->getRequestMethod()) {
            case 'GET':

              // Read an entity.
              $this
                ->handleGet();
              break;
            case 'POST':

              // Create a new entity.
              $this
                ->handlePost();
              break;
            case 'PUT':

              // Update an entity.
              $this
                ->handlePut();
              break;
            case 'DELETE':

              // Delete an entity.
              $this
                ->handleDelete();
              break;
            default:
              $this
                ->setError('HTTP Method not managed');
          }
      }
    } catch (Exception $e) {
      $this
        ->setError('Internal error', '500 Internal Server Error');
    }
    $this
      ->outputResponse();
  }

  /**
   * Handle the GET method action.
   *
   * Read an entity.
   */
  protected abstract function handleGet();

  /**
   * Handle the POST method action.
   *
   * Create a new entity.
   */
  protected abstract function handlePost();

  /**
   * Handle the PUT method action.
   *
   * Update an entity.
   */
  protected abstract function handlePut();

  /**
   * Handle the DELETE method action.
   *
   * Delete an entity.
   */
  protected abstract function handleDelete();

  /**
   * Default request parameters.
   *
   * @return array
   *   The request parameters.
   */
  protected function getDefaultRequest() {
    $menu_item = menu_get_item();
    $menu_path = $menu_item['path'];

    // Parse the request path to get args passed to entity share rest api.
    $short_path = request_path();
    $pos = strpos($short_path, $menu_path);
    if ($pos !== FALSE) {
      $short_path = substr($short_path, $pos + strlen($menu_path));
    }
    if (substr($short_path, 0, 1) == '/') {
      $short_path = substr($short_path, 1);
    }
    $args = arg(NULL, $short_path);

    // Ex: /node/{id} or node.
    $request = array(
      'type' => $args[0],
      'id' => isset($args[1]) ? $args[1] : NULL,
    );
    return $request;
  }

  /**
   * Parse the request.
   *
   * @return bool
   *   TRUE if the request is valid, FALSE otherwise.
   */
  protected function parseRequest() {
    $request = $this
      ->getDefaultRequest();
    switch ($this
      ->getRequestMethod()) {
      case 'POST':
      case 'PUT':
        $raw_data = file_get_contents('php://input');
        if (strstr($_SERVER['CONTENT_TYPE'], 'application/json')) {
          $request['datas'] = (object) drupal_json_decode($raw_data);
        }
        else {
          return FALSE;
        }
        break;
      case 'GET':
      case 'DELETE':
        break;
      default:
        $this
          ->setError('HTTP Method not managed');
        return FALSE;
    }
    $this->request = $request;
    return TRUE;
  }

  /**
   * Format the response in function of the accept header.
   */
  protected function formatResponse() {
    $result = array(
      'result' => $this
        ->getResult(),
      'error' => $this
        ->getError(),
      'status' => !$this
        ->getError() ? self::STATUS_OK : self::STATUS_ERROR,
    );

    // Default formatters.
    $formatter = array(
      'application/json' => function ($result, $server) {
        return drupal_json_encode($result);
      },
    );
    drupal_alter(self::HOOK_PREFIX . 'response_formatter', $formatter);

    // Call the formatter matching the request.
    foreach ($formatter as $http_accept => $callback) {
      if (strstr($_SERVER['HTTP_ACCEPT'], $http_accept)) {
        if (is_callable($callback)) {
          $this
            ->setHeader('Content-Type', $http_accept);
          $this->response = call_user_func_array($callback, array(
            $result,
            $this,
          ));
          break;
        }
        else {

          // Watchdog.
          watchdog(self::WATCHDOG_TYPE, 'The Content Type %type callback is not valid', array(
            '%type' => $http_accept,
          ), WATCHDOG_ERROR);
        }
      }
    }
    if (is_null($this->response)) {
      $this->response = t('HTTP_ACCEPT "@accept" not managed', array(
        '@accept' => $_SERVER['HTTP_ACCEPT'],
      ));
    }
  }

  /**
   * Output the response to the client.
   */
  protected function outputResponse() {
    $this
      ->formatResponse();
    $this
      ->sendHeaders();
    print $this->response;

    // Do not let this output.
    drupal_page_footer();
    exit;
  }

  /**
   * Set a header (but not send it).
   *
   * @param string $name
   *   Header name.
   * @param string $value
   *   Header value.
   */
  public function setHeader($name, $value) {
    $this->headers[$name] = $value;
  }

  /**
   * Send headers to the response.
   */
  protected function sendHeaders() {
    foreach ($this->headers as $name => $value) {
      drupal_add_http_header($name, $value);
    }
  }

  /**
   * Security control.
   *
   * To allow the call, you have to authorize the ip of the calling server in
   * the "entity_share_server_allowed_ips" variable.
   *
   * @return bool
   *   TRUE if the request can be performed, FALSE otherwise.
   */
  protected function isRequestAllowed() {

    // IP address allowed.
    $allowed_ips = variable_get(self::IP_RESTRICTED_VARIABLE, array());
    if (!in_array(ip_address(), $allowed_ips)) {
      watchdog(self::WATCHDOG_TYPE, 'The IP %ip is not allowed', array(
        '%ip' => ip_address(),
      ), WATCHDOG_ERROR);
      return FALSE;
    }

    // Do not check user if we are in the login step.
    if ($this
      ->getParam('type') != 'login') {

      // User connected and have the correct permissions.
      if (!(user_is_logged_in() && user_access('access entityshare server'))) {
        watchdog(self::WATCHDOG_TYPE, 'The user is not allowed', array(), WATCHDOG_ERROR);
        return FALSE;
      }
    }
    return TRUE;
  }

  /**
   * Authenticate the user.
   */
  protected function doLogin() {

    // Get the login and password.
    $login = $this
      ->getParam('datas')->login;
    $password = $this
      ->getParam('datas')->password;

    // Authenticate user in drupal.
    global $user;
    $account = user_authenticate($login, $password);
    if (!$account) {
      $this
        ->setError('Invalid user');
      return;
    }

    // Update the drupal loaded user.
    $user = user_load($account, TRUE);

    // Regenerate the session for security reason.
    drupal_session_regenerate();

    // Get the session informations.
    $session_name = session_name();
    $session_id = session_id();
    if (!empty($session_name) && !empty($session_id)) {
      $this
        ->setResult(array(
        'session_name' => $session_name,
        'session_id' => $session_id,
      ));
    }
    else {
      $this
        ->setError('User session invalid');
    }
  }

}

Members

Namesort descending Modifiers Type Description Overrides
EntityShareServerRestAbstract::$error protected property Error.
EntityShareServerRestAbstract::$headers protected property Http headers.
EntityShareServerRestAbstract::$request protected property Http request.
EntityShareServerRestAbstract::$response protected property Http response.
EntityShareServerRestAbstract::$result protected property Result.
EntityShareServerRestAbstract::doLogin protected function Authenticate the user.
EntityShareServerRestAbstract::formatResponse protected function Format the response in function of the accept header.
EntityShareServerRestAbstract::getDefaultRequest protected function Default request parameters.
EntityShareServerRestAbstract::getError public function Get the error of the action.
EntityShareServerRestAbstract::getParam public function Get the parameter value.
EntityShareServerRestAbstract::getRequest public function Get the Request.
EntityShareServerRestAbstract::getRequestMethod public function Get the method of the request.
EntityShareServerRestAbstract::getResult public function Get the result of the action.
EntityShareServerRestAbstract::handle public function Handle the server.
EntityShareServerRestAbstract::handleDelete abstract protected function Handle the DELETE method action. 1
EntityShareServerRestAbstract::handleGet abstract protected function Handle the GET method action. 1
EntityShareServerRestAbstract::handlePost abstract protected function Handle the POST method action. 1
EntityShareServerRestAbstract::handlePut abstract protected function Handle the PUT method action. 1
EntityShareServerRestAbstract::HOOK_PREFIX constant
EntityShareServerRestAbstract::IP_RESTRICTED_VARIABLE constant
EntityShareServerRestAbstract::isRequestAllowed protected function Security control.
EntityShareServerRestAbstract::outputResponse protected function Output the response to the client.
EntityShareServerRestAbstract::parseRequest protected function Parse the request.
EntityShareServerRestAbstract::sendHeaders protected function Send headers to the response.
EntityShareServerRestAbstract::setError protected function Set the error of the action.
EntityShareServerRestAbstract::setHeader public function Set a header (but not send it).
EntityShareServerRestAbstract::setResult protected function Set the result of the action.
EntityShareServerRestAbstract::STATUS_ERROR constant
EntityShareServerRestAbstract::STATUS_OK constant
EntityShareServerRestAbstract::WATCHDOG_TYPE constant
EntityShareServerRestAbstract::__construct public function Constructor. Initialize properties.