<?php /******************************************************************************* * Copyright (c) 2013, 2014, 2015, 2016 Eclipse Foundation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Zak James (zak.james@gmail.com) - Initial implementation * Denis Roy (Eclipse Foundation) * Christopher Guindon (Eclipse Foundation) - Refactoring for usability and USS *******************************************************************************/ require_once(realpath(dirname(__FILE__) . '/../../../system/eclipseenv.class.php')); /** * RestClient class * * @author chrisguindon */ class RestClient extends EclipseEnv { /** * Base url for api requests. * @var string */ protected $base_url = ""; /** * List of headers for subsequent request. * @var array */ protected $header = array(); /** * List of cookies for subsequent request. * @var array */ protected $cookie = array(); /** * Proxy value for curl requests * * @var string */ protected $proxy = ''; /** * Result of the last request made * * @var unknown */ protected $result = NULL; /** * Oauth2 access_token * * @var string */ protected $access_token = ""; function __construct(App $App = NULL) { parent::__construct($App); // Default headers $default_headers = array( 'Content-Type' => 'application/json', 'Accept' =>'application/json', 'User-Agent' => 'eclipse/foundation' ); $this->setHeader($default_headers); } /** * Execute a GET request. * * @param string $url * * @return Response $data */ public function get($url) { return $this->curl_exec($url); } /** * Execute a POST request. * * @param string $url * @param string $data * * @return Response $data */ public function post($url, $data = NULL) { $options[CURLOPT_POST] = TRUE; $options[CURLOPT_POSTFIELDS] = $data; return $this->curl_exec($url, $options); } /** * Execute a PUT request. * * @param string $url * @param string $data * * @return Response $data */ public function put($url, $data = NULL) { $options[CURLOPT_CUSTOMREQUEST] = 'PUT'; $options[CURLOPT_POSTFIELDS] = $data; return $this->curl_exec($url, $options); } /** * Execute a DELETE request. * * @param string $url * @param string $data * * @return Response $data */ public function delete($url) { $options[CURLOPT_CUSTOMREQUEST] = 'DELETE'; return $this->curl_exec($url, $options); } /** * Execute a PATCH request. * * @param string $url * @param string $data * * @return Response $data */ public function patch($url, $data) { $options[CURLOPT_CUSTOMREQUEST] = 'PATCH'; $options[CURLOPT_POSTFIELDS] = $data; return $this->curl_exec($url, $options); } /** * Get $base_url * * @return string $base_url */ public function getBaseUrl() { return $this->base_url; } /** * Set $base_url * @param string $url * * @return string $base_url */ public function setBaseUrl($url) { if (filter_var($url, FILTER_VALIDATE_URL)) { $this->base_url = $url; } return $this->base_url; } /** * Shortcut for the decoded value of the request body * * The server must return data in JSON. */ public function getRequestBody($json = TRUE) { $return = new stdClass(); if (isset($this->result->body) && !empty($this->result->body)) { $return = $this->result->body; if ($json) { $return = json_decode(stripslashes($this->result->body)); } } return $return; } /** * Get $cookie * Convert $cookie array into a string * * @return string $cookie */ public function getCookie() { return implode('; ', $this->cookie); } /** * Set $cookie * @param array $cookies * * @return bool */ public function setCookie($cookies = array()) { if (!is_array($cookies)) { return FALSE; } foreach ($cookies as $key => $value) { $this->cookie[$key] = $value; } return TRUE; } /** * Get $header * Remove array key from $header * * @return array $header */ public function getHeader() { return array_values($this->header); } /** * Set $header * @param array $headers * * @return bool */ public function setHeader($headers = array()) { if (!is_array($headers)) { return FALSE; } foreach ($headers as $key => $value) { $this->header[$key] = $key . ': '. $value; } return TRUE; } /** * Get access_token * * @return string */ public function getAccessToken() { return $this->access_token; } /** * Get access_token * * @param string $token */ public function setAccessToken($token = "") { $this->access_token = $token; $_SESSION['access_token']['uss'] = $token; } /** * Unset $header * @param string $header * * @return bool */ public function unsetHeader($header = "") { if (isset($this->header[$header])) { unset($this->header[$header]); return TRUE; } return FALSE; } /** * Execute a CURL request * * @param string $path * @param array $options * * @return Response $return */ protected function curl_exec($path = '', $options = array()) { $this->result = new stdClass(); $ch = curl_init(); curl_setopt($ch, CURLOPT_HEADER, TRUE); curl_setopt($ch, CURLOPT_FRESH_CONNECT, TRUE); curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); curl_setopt($ch, CURLINFO_HEADER_OUT, TRUE); curl_setopt($ch, CURLOPT_FORBID_REUSE, TRUE); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); curl_setopt($ch, CURLOPT_TIMEOUT, 30); //proxy configuration //curl_setopt($ch, CURLOPT_PROXY, $this->_get_proxy()); //curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, 1); if ($this->getEnvShortName() === 'local') { curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($ch, CURLOPT_PROXY, ''); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); } $options[CURLOPT_URL] = $this->base_url . '/' . $path; // Use access token if set if ($token = $this->getAccessToken()) { $this->setHeader(array('Authorization' => 'Bearer ' . $token)); } $headers = $this->getHeader(); $cookies = $this->getCookie(); if (!empty($cookies)) { $headers[] = 'Cookie: ' . $cookies; } $options[CURLOPT_HTTPHEADER] = $headers; curl_setopt_array($ch, $options); $result = curl_exec($ch); if (!$result) { $this->result->error = curl_error($ch); $this->result->code = 9990; $this->result->request_error = $result; curl_close($ch); return $this->result; } $this->result->options = $options; $this->result->request = curl_getinfo($ch); $this->result->body = substr($result, $this->result->request['header_size']); curl_close($ch); $this->result->headers = array(); $header_text = substr($result, 0, strpos($result, "\r\n\r\n")); foreach (explode("\r\n", $header_text) as $i => $line) { if ($i === 0) { $this->result->headers['http_code'] = $line; } else { list ($key, $value) = explode(': ', $line); $this->result->headers[$key] = $value; } } $response_array = explode(' ', trim($this->result->headers['http_code']), 3); $this->result->status_message = ''; $this->result->protocol = $response_array[0]; $this->result->code = $this->result->request['http_code']; if (isset($response_array[2])) { $this->result->status_message = $response_array[2]; } return $this->result; } /** * Get 'Link' header * * @param string $link * * @return bool/array $links */ protected function _getHeaderLink($link = '') { if (strlen($link) == 0) { return FALSE; } $parts = explode(',', $link); $links = array(); foreach($parts as $p) { $section = explode(';', htmlspecialchars_decode($p)); if (count($section) != 2) { return FALSE; } $url = $this->_removeBaseUrlFromUrl(trim(preg_replace("/<(.*)>/", '$1', $section[0]))); $key = trim(preg_replace("/rel=\"(.*)\"/", '$1', $section[1])); $links[$key] = $url; } return $links; } /** * Get next page from pagination * * @param Response $data * * @return Response $return */ public function _getNextPage($data) { if ($data && isset($data->headers['Link']) && !isset($data->error) && !empty($data->body)) { $pages = $this->_getHeaderLink($data->headers['Link']); if (($pages['self'] !== $pages['last']) && !empty($pages['next'])){ if ($data = $this->get($pages['next'])) { return $data; } } } return FALSE; } /** * Remove $base_url from $url * @param string $url * * @return string $url */ protected function _removeBaseUrlFromUrl($url = '') { return str_replace($this->getBaseUrl() . '/', '', $url); } /** * Get proxy value * * @return string */ private function _get_proxy() { if (empty($this->proxy)) { $this->_set_proxy(); } return $this->proxy; } /** * Set eclipse proxy for staging/production */ private function _set_proxy(){ if ($this->_get_prefix_domain() === 'www.eclipse.org') { $this->proxy = 'proxy.eclipse.org:9899'; } } }