Overview

Namespaces

  • Antavo
    • RestClient
      • Exceptions
    • SignedToken
      • Exceptions
  • PHP

Classes

  • Antavo\ApiClient
  • Antavo\CustomerToken
  • Antavo\RestClient\RestClient
  • Antavo\SignedToken\SignedToken

Exceptions

  • Antavo\ApiClientException
  • Antavo\RestClient\Exceptions\Exception
  • Antavo\RestClient\Exceptions\ParserException
  • Antavo\RestClient\Exceptions\StatusCodeException
  • Antavo\SignedToken\Exceptions\Exception
  • Antavo\SignedToken\Exceptions\ExpiredException
  • Antavo\SignedToken\Exceptions\InvalidDigestException
  • Antavo\SignedToken\Exceptions\InvalidPayloadException
  • Exception
  • RuntimeException
  • Overview
  • Namespace
  • Class
  1:   2:   3:   4:   5:   6:   7:   8:   9:  10:  11:  12:  13:  14:  15:  16:  17:  18:  19:  20:  21:  22:  23:  24:  25:  26:  27:  28:  29:  30:  31:  32:  33:  34:  35:  36:  37:  38:  39:  40:  41:  42:  43:  44:  45:  46:  47:  48:  49:  50:  51:  52:  53:  54:  55:  56:  57:  58:  59:  60:  61:  62:  63:  64:  65:  66:  67:  68:  69:  70:  71:  72:  73:  74:  75:  76:  77:  78:  79:  80:  81:  82:  83:  84:  85:  86:  87:  88:  89:  90:  91:  92:  93:  94:  95:  96:  97:  98:  99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220: 221: 222: 223: 224: 225: 226: 227: 228: 229: 230: 231: 232: 233: 234: 235: 236: 237: 238: 239: 240: 241: 242: 243: 244: 245: 246: 247: 248: 249: 250: 251: 252: 253: 254: 255: 256: 257: 258: 259: 260: 261: 262: 263: 264: 265: 266: 267: 268: 269: 270: 271: 272: 273: 274: 275: 276: 277: 278: 279: 280: 281: 282: 283: 284: 285: 286: 287: 288: 289: 290: 291: 292: 293: 294: 295: 296: 297: 298: 299: 300: 301: 302: 303: 304: 305: 306: 307: 308: 309: 310: 311: 312: 313: 314: 315: 316: 317: 318: 319: 320: 321: 322: 323: 324: 325: 326: 327: 328: 329: 330: 331: 332: 333: 334: 335: 336: 337: 338: 339: 340: 341: 
<?php
namespace Antavo\RestClient;

/**
 * A rather straightforward and lightweight, yet flexible helper class to
 * perform operations on a RESTful API with cURL.
 *
 * @method mixed get(string $url, mixed $data = NULL, array $curl_options = array())
 * Performs a GET request to the API.
 * @method mixed post(string $url, mixed $data = NULL, array $curl_options = array())
 * Performs a POST request to the API.
 * @method mixed put(string $url, mixed $data = NULL, array $curl_options = array())
 * Performs a PUT request to the API.
 * @method mixed delete(string $url, mixed $data = NULL, array $curl_options = array())
 * Performs a DELETE request to the API.
 */
class RestClient {
    /**
     * @var string  Base URL to prepend when a request is made with relative
     * path given.
     */
    protected $base_url;

    /**
     * @var array
     */
    protected $curl_options = array();

    /**
     * @var mixed
     */
    protected $last_result;

    /**
     * @var string
     */
    protected $last_result_headers;

    /**
     * @var array
     */
    protected $last_result_info;

    /**
     * @var \Antavo\RestClient\Exceptions\Exception  Stores the last processing
     * error.
     */
    protected $last_error;

    /**
     * Catches all invocations to inaccessible methods and forwards them to
     * <tt>call()</tt>, with the original method name as request method.
     *
     * @param string $name  Name of the invoked method.
     * @param array $arguments  Arguments.
     * @return mixed
     * @internal
     */
    public function __call($name, $arguments) {
        array_unshift($arguments, $name);
        return call_user_func_array(array($this, 'call'), $arguments);
    }

    /**
     * Performs an API request.
     *
     * @param string $method  HTTP method to use.
     * @param string $url  URL to send request to. It is prefixed with
     * the <tt>base_url</tt> unless it starts with a URL scheme.
     * @param array|string $data  Data to send with request. It is sent as a
     * request entity where allowed, or appended as a query string otherwise.
     * @param array $curl_options  Additional cURL options for current request
     * only.
     * @return mixed
     * @throws \Antavo\RestClient\Exceptions\Exception  If an error occurred
     * during processing response.
     */
    public function call($method, $url, $data = NULL, array $curl_options = array()) {
        // Converting HTTP method to uppercase.
        $method = strtoupper($method);

        // Converting data to application/x-www-form-urlencoded.
        if (is_array($data)) {
            $data = http_build_query($data);
        }

        // Extending URL.
        if (!preg_match('#https{0,1}://#', $url)) {
            $url = $this->base_url . '/' . ltrim($url, '/');
        }

        // Appending data as query string for requests that does not allow
        // sending an entity.
        if (strlen($data) && 'POST' != $method && 'PUT' != $method) {
            $url .= (strpos($url, '?') === false ? '?' : '&') . $data;
        }

        // Initiating cURL resource.
        $ch = curl_init();

        // Setting default cURL options.
        if (count($this->curl_options)) {
            curl_setopt_array($ch, $this->curl_options);
        }

        // Appending cURL options given for this request only.
        if (count($curl_options)) {
            curl_setopt_array($ch, $curl_options);
        }

        // Setting up cURL for a POST request.
        if ('POST' == $method || 'PUT' == $method) {
            if (strlen($data)) {
                curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
            }
            curl_setopt($ch, CURLOPT_POST, true);
        }

        // These cURL options are not overrideable.
        curl_setopt($ch, CURLOPT_HEADERFUNCTION, array($this, 'captureHeader'));
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_SSL_CIPHER_LIST, 'TLSv1');
        curl_setopt($ch, CURLINFO_HEADER_OUT, true);

        $this->setError();
        $this->last_result_headers = NULL;
        $this->last_result = curl_exec($ch);
        $this->last_result_info = curl_getinfo($ch);

        // Releasing resource.
        curl_close($ch);

        // Checking HTTP status code.
        if (200 != $this->last_result_info['http_code']) {
            $this->setError(new Exceptions\StatusCodeException(
                preg_match(
                    '/^HTTP\/1.[01] \d+ (.+)/i',
                    $this->last_result_headers,
                    $matches
                )
                    ? $matches[1]
                    : 'No headers',
                $this->last_result_info['http_code']
            ));
        }

        // Processing result.
        $this->last_result = $this->processResult(
            $this->last_result,
            strtok($this->last_result_info['content_type'], ';')
        );

        if ($error = $this->getLastError()) {
            throw $error;
        }

        return $this->last_result;
    }

    /**
     * Callback method for cURL to capture header data.
     *
     * @param resource $resource
     * @param string $string
     * @return int  Returns the number of bytes written.
     */
    protected function captureHeader($resource, $string) {
        $this->last_result_headers .= $string;
        return strlen($string);
    }

    /**
     * Returns base URL prepended to relative URL's for each request.
     *
     * @return string
     */
    public function getBaseUrl() {
        return $this->base_url;
    }

    /**
     * Returns the last error occurred during processing the response.
     *
     * @return \Antavo\RestClient\Exceptions\Exception  Returns <tt>NULL</tt>
     * if there was no error.
     */
    public function getLastError() {
        return $this->last_error;
    }

    /**
     * Returns body of last response, parsed according to
     * <tt>Content-Type</tt> header.
     *
     * @return mixed
     */
    public function getLastResult() {
        return $this->last_result;
    }

    /**
     * Returns headers of last response.
     *
     * @return string
     */
    public function getLastResultHeaders() {
        return $this->last_result_headers;
    }

    /**
     * Returns info on last request.
     *
     * @return array  For details see PHP <tt>curl_getinfo()</tt> manual.
     * @link http://php.net/curl_getinfo  PHP: curl_getinfo - Manual
     */
    public function getLastResultInfo() {
        return $this->last_result_info;
    }

    /**
     * Processes result according to its content type.
     *
     * @param string $result  Response body.
     * @param string $content_type  Content MIME-type without parameters (cut
     * off at first semicolon).
     * @return mixed
     */
    protected function processResult($result, $content_type) {
        switch ($content_type) {
            case 'application/json':
                return $this->processJsonResult($result);
            case 'application/xml':
            case 'text/xml':
                return $this->processXmlResult($result);
            default:
                return $result;
        }
    }

    /**
     * Processes and returns JSON result.
     *
     * On JSON parse error it sets an {@see \Antavo\RestParserException} with
     * error code & message then returns the original result string.
     *
     * @param string $result
     * @return mixed
     */
    protected function processJsonResult($result) {
        $parsed_result = json_decode($result);
        if (($error = json_last_error()) === JSON_ERROR_NONE) {
            return $parsed_result;
        }
        $this->setError(new Exceptions\ParserException(
            json_last_error_msg(),
            $error
        ));
        return $result;
    }

    /**
     * Processes XML result.
     *
     * @param string $result
     * @return mixed  Returns a {@see \SimpleXMLElement} object on successful
     * operation, or the original result string otherwise.
     * @throws \LogicException  If PHP SimpleXML extension is not loaded.
     * @static
     */
    protected function processXmlResult($result) {
        // Checking for PHP SimpleXML extension.
        if (!extension_loaded('SimpleXML')) {
            throw new \LogicException(sprintf(
                '%s needs the PHP SimpleXML extension in order to work',
                get_called_class()
            ));
        }
        if (($parsed_result = simplexml_load_string($result)) !== false) {
            return $parsed_result;
        }
        return $result;
    }

    /**
     * Appends cURL option to defaults.
     *
     * @param string $option  Option name. See cURL options for option names.
     * @param mixed $value  Option value. Providing a <tt>NULL</tt> removes an
     * already set option.
     * @return void
     * @link http://php.net/curl_setopt List of cURL options.
     */
    public function setCurlOption($option, $value = NULL) {
        if (isset($value)) {
            $this->curl_options[$option] = $value;
        } else {
            unset($this->curl_options[$option]);
        }
    }

    /**
     * Appends multiple cURL options to defaults.
     *
     * @param array $options  cURL options as key-value pairs. For keys and
     * their values see cURL options. Providing a <tt>NULL</tt> value removes
     * an already set option.
     * @return void
     * @link http://php.net/curl_setopt List of cURL options.
     */
    public function setCurlOptions(array $options) {
        foreach ($options as $option => $value) {
            $this->setCurlOption($option, $value);
        }
    }

    /**
     * Sets base URL which is to prepend to relative URL's for each request.
     *
     * @param string $base_url
     */
    public function setBaseUrl($base_url) {
        $this->base_url = $base_url;
    }

    /**
     * Used to set an error without exiting the normal flow of an API call.
     *
     * Calling without argument or with a <tt>NULL</tt> value resets the stored
     * last error.
     *
     * @param \Antavo\RestClient\Exceptions\Exception $exception
     * @return void
     * @see getLastError()
     */
    public function setError(Exceptions\Exception $exception = NULL) {
        $this->last_error = $exception;
    }
}
API documentation generated by ApiGen