/modules/api/rest.php
PHP | 407 lines | 196 code | 52 blank | 159 comment | 28 complexity | f1721f9331842ddec9fe5bf353431dae MD5 | raw file
- <?php
- /**
- * This class allow easy usage of a service via a REST API.
- *
- * For now, the implemantation rely on PHP HTTP streams only.
- *
- * @package API_REST
- */
- class kore_api_rest
- {
- private $_scheme = 'http';
- private $_host = 'localhost';
- private $_port;
- private $_path = '';
- protected $_dataContentType = 'application/x-www-form-urlencoded';
- private $_contextOpts = [ 'http' => [
- 'ignore_errors' => true,
- 'protocol_version' => '1.1' ]];
- private $_headers = [
- 'Accept-Encoding' => 'gzip',
- 'Connection' => 'close' ];
- /**
- * Init a kore_api_rest object, specifying the baseUrl of all futures
- * *relatives* queries.
- *
- * @param $baseUrl
- */
- public function __construct($baseUrl)
- {
- $u = parse_url($baseUrl);
- if (isset($u['scheme']))
- $this->_scheme = strtolower($u['scheme']);
- if (isset($u['host']))
- $this->_host = $u['host'];
- if (isset($u['port']))
- $this->_port = (int) $u['port'];
- elseif ($this->_scheme === 'https')
- $this->_port = 443;
- else
- $this->_port = 80;
- if (isset($u['path']))
- $this->_path = $u['path'];
- }
- /**
- * Define a specific HTTP header to add to all queries
- *
- * @param $name
- * @param $value
- */
- public function setHeader($name, $value)
- {
- $this->_headers[$name] = $value;
- }
- /**
- * Get the value of an HTTP header, which is added to all queries
- *
- * @see kore_api_rest::setHeader()
- * @param $name
- */
- public function getHeader($name)
- {
- return @$this->_headers[$name];
- }
- /**
- * Remove an HTTP header, previously added throught setHeader()
- *
- * @see kore_api_rest::setHeader()
- * @param $name
- */
- public function delHeader($name)
- {
- unset($this->_headers[$name]);
- }
- /**
- * Use HTTP authentication via "basic" method.
- *
- * @param $login
- * @param $password
- */
- public function setHTTPBasicAuth($login, $password)
- {
- $this->setHeader('Authorization', 'Basic ' .
- base64_encode("$login:$password"));
- }
- /**
- * Disable HTTP authentication.
- *
- */
- public function delHTTPAuth()
- {
- $this->delHeader('Authorization');
- }
- /**
- * Build defaults context options
- *
- * @param $method
- * @param $miscHeaders
- * @return array
- */
- protected function _getContextOpts($method, array $miscHeaders = null)
- {
- $opts = $this->_contextOpts;
- $opts['http']['method'] = $method;
- $headers = $this->_headers;
- if ($miscHeaders)
- $headers = $miscHeaders + $headers;
- if ($headers){
- if (!isset($opts['http']['header']))
- $opts['http']['header'] = '';
- foreach ($headers as $name => $value)
- $opts['http']['header'] .= "{$name}: $value\r\n";
- }
- return $opts;
- }
- /**
- * Create a stream context based on given options.
- *
- * @param array $contextOpts
- * @return resource
- */
- protected function _createContext(array $contextOpts)
- {
- return stream_context_create($contextOpts);
- }
- /**
- * Process the query.
- *
- * @param string $url
- * @param array $contextOpts
- * @return kore_api_restResult
- * @throws kore_api_restException
- */
- protected function _query($url, array $contextOpts)
- {
- $stream = fopen($url, 'r', false, $this->_createContext($contextOpts));
- if (!$stream)
- throw new kore_api_restException("error while querying $url");
- $result = new kore_api_restResult();
- $metas = stream_get_meta_data($stream);
- foreach ($metas['wrapper_data'] as $header){
- if (preg_match('#^HTTP/[0-9.]+ ([0-9]{3})(?:\\s+(.*))?$#', $header, $m)){
- $result->code = (int) $m[1];
- if (isset($m[2]))
- $result->codeMessage = $m[2];
- else
- $result->codeMessage = null;
- } elseif (preg_match('#^([a-zA-Z0-9_\\-]+):\\s*(.*)$#', $header, $m)){
- $result->headers[strtolower($m[1])] = $m[2];
- }
- }
- if (!$metas['eof'])
- $result->contents = stream_get_contents($stream);
- if ($result->code >= 400)
- $this->_handleHTTPError($result);
- return $this->_fetchContents($result);
- }
- /**
- * Handle HTTP errors.
- *
- * @param kore_api_restResult $result
- * @throws kore_api_restException
- */
- protected function _handleHTTPError(kore_api_restResult $result)
- {
- if ($result->codeMessage)
- $message = $result->codeMessage;
- else
- $message = "http code #".$result->code;
- throw new kore_api_restException("REST: ".$message, $result->code);
- }
- /**
- * Fetch the result, and transform/convert it if needed.
- *
- * @param kore_api_restResult $result
- * @return kore_api_restResult
- */
- protected function _fetchContents(kore_api_restResult $result)
- {
- /*
- * If transfert was "encoded" we need to decode it.
- *
- * For now, we only handle GZIP decompression.
- */
- if (isset($result->headers['content-encoding'])){
- if ($result->headers['content-encoding'] === 'gzip')
- $result->contents = gzdecode($result->contents);
- }
- return $result;
- }
- /**
- * Create the full URI, based on the current $baseUrl, requested relative
- * $url and any given params.
- *
- * @param string $url
- * @param array $additionnalParams
- * @return string
- */
- protected function _buildUrl($url, array $additionnalParams = null)
- {
- if (substr($url, 0, 1) === '/'){
- $baseUrl = $this->_scheme.'://'.$this->_host;
- if ($this->_scheme === 'http'){
- if($this->_port != 80) $baseUrl .= ':'.$this->_port;
- } elseif ($this->_scheme === 'https'){
- if($this->_port != 443) $baseUrl .= ':'.$this->_port;
- } else {
- $baseUrl .= ':'.$this->_port;
- }
- $url = $baseUrl . $this->_path . $url;
- }
- if ($additionnalParams){
- if (strpos($url, '?') !== false)
- $url .= '&';
- else
- $url .= '?';
- $url .= http_build_query($additionnalParams, '',
- ini_get('arg_separator.output'), PHP_QUERY_RFC1738);
- }
- return $url;
- }
- /**
- * Encode uploaded data from POST and PUT queries.
- *
- * @param mixed $data
- * @return string
- */
- protected function _encodeData($data)
- {
- if (is_array($data))
- $data = http_build_query($data, '', '&', PHP_QUERY_RFC1738);
- return $data;
- }
- /**
- * Throw a HEAD query.
- *
- * @param string $url
- * @param array $data
- * @param array $miscHeaders
- * @return kore_api_restResult
- * @throws kore_api_restException
- */
- public function head($url, array $data = null, array $miscHeaders = null)
- {
- $url = $this->_buildUrl($url, $data);
- $opts = $this->_getContextOpts('HEAD', $miscHeaders);
- return $this->_query($url, $opts);
- }
- /**
- * Throw a GET query.
- *
- * @param string $url
- * @param array $data
- * @param array $miscHeaders
- * @return kore_api_restResult
- * @throws kore_api_restException
- */
- public function get($url, array $data = null, array $miscHeaders = null)
- {
- $url = $this->_buildUrl($url, $data);
- $opts = $this->_getContextOpts('GET', $miscHeaders);
- return $this->_query($url, $opts);
- }
- /**
- * Inject uploaded data in the given stream context
- *
- * @param mixed $data
- * @param array $contextOpts
- */
- public function _addContent($data, array &$contextOpts)
- {
- $data = $this->_encodeData($data);
- if ($data)
- $contextOpts['http']['content'] = $data;
- if (!isset($contextOpts['http']['header']))
- $contextOpts['http']['header'] = "Content-type: {$this->_dataContentType}\r\n";
- elseif ((stripos($contextOpts['http']['header'], 'Content-type:') === false))
- $contextOpts['http']['header'] .= "Content-type: {$this->_dataContentType}\r\n";
- }
- /**
- * Throw a POST query.
- *
- * @param string $url
- * @param mixed $data
- * @param array $miscHeaders
- * @return kore_api_restResult
- * @throws kore_api_restException
- */
- public function post($url, $data = null, array $miscHeaders = null)
- {
- $url = $this->_buildUrl($url);
- $opts = $this->_getContextOpts('POST', $miscHeaders);
- $this->_addContent($data, $opts);
- return $this->_query($url, $opts);
- }
- /**
- * Throw a PUT query.
- *
- * @param string $url
- * @param mixed $data
- * @param array $miscHeaders
- * @return kore_api_restResult
- * @throws kore_api_restException
- */
- public function put($url, $data = null, array $miscHeaders = null)
- {
- $url = $this->_buildUrl($url);
- $opts = $this->_getContextOpts('PUT', $miscHeaders);
- $this->_addContent($data, $opts);
- return $this->_query($url, $opts);
- }
- /**
- * Throw a DELETE query.
- *
- * @param string $url
- * @param array $data
- * @param array $miscHeaders
- * @return kore_api_restResult
- * @throws kore_api_restException
- */
- public function delete($url, array $data = null, array $miscHeaders = null)
- {
- $url = $this->_buildUrl($url, $data);
- $opts = $this->_getContextOpts('DELETE', $miscHeaders);
- return $this->_query($url, $opts);
- }
- }
- /**
- * Exceptions throws as a result of HTTP requests.
- *
- * @package API_REST
- */
- class kore_api_restException extends exception
- {
- }
- /**
- * Class which contains result of HTTP requests.
- *
- * @package API_REST
- */
- class kore_api_restResult
- {
- public $code = 599;
- public $codeMessage = 'unable to parse server answer';
- public $headers = array();
- public $contents = '';
- /**
- * Shortcut to easily access to the contents.
- *
- * @return string
- */
- public function __toString()
- {
- return (string) $this->contents;
- }
- }