Advertisement
Guest User

Untitled

a guest
Apr 23rd, 2018
87
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.00 KB | None | 0 0
  1. <?php
  2. defined('BASEPATH') OR exit('No direct script access allowed');
  3. class RestclientException extends Exception {}
  4.  
  5. class Restclient {
  6.  
  7. public $options;
  8. public $handle; // cURL resource handle.
  9.  
  10. // Populated after execution:
  11. public $response; // Response body.
  12. public $headers; // Parsed reponse header object.
  13. public $info; // Response info object.
  14. public $error; // Response error string.
  15. public $response_status_lines; // indexed array of raw HTTP response status lines.
  16.  
  17. // Populated as-needed.
  18. public $decoded_response; // Decoded response body.
  19.  
  20. public function __construct($options=[]){
  21. $default_options = [
  22. 'headers' => [],
  23. 'parameters' => [],
  24. 'curl_options' => [],
  25. 'build_indexed_queries' => FALSE,
  26. 'user_agent' => "PHP Restclient/0.1.7",
  27. 'base_url' => NULL,
  28. 'format' => NULL,
  29. 'format_regex' => "/(\w+)\/(\w+)(;[.+])?/",
  30. 'decoders' => [
  31. 'json' => 'json_decode',
  32. 'php' => 'unserialize'
  33. ],
  34. 'username' => NULL,
  35. 'password' => NULL
  36. ];
  37.  
  38. $this->options = array_merge($default_options, $options);
  39. if(array_key_exists('decoders', $options))
  40. $this->options['decoders'] = array_merge(
  41. $default_options['decoders'], $options['decoders']);
  42. }
  43.  
  44. public function set_option($key, $value){
  45. $this->options[$key] = $value;
  46. }
  47.  
  48. public function register_decoder($format, $method){
  49. // Decoder callbacks must adhere to the following pattern:
  50. // array my_decoder(string $data)
  51. $this->options['decoders'][$format] = $method;
  52. }
  53.  
  54. // Iterable methods:
  55. public function rewind(){
  56. $this->decode_response();
  57. return reset($this->decoded_response);
  58. }
  59.  
  60. public function current(){
  61. return current($this->decoded_response);
  62. }
  63.  
  64. public function key(){
  65. return key($this->decoded_response);
  66. }
  67.  
  68. public function next(){
  69. return next($this->decoded_response);
  70. }
  71.  
  72. public function valid(){
  73. return is_array($this->decoded_response)
  74. && (key($this->decoded_response) !== NULL);
  75. }
  76.  
  77. // ArrayAccess methods:
  78. public function offsetExists($key){
  79. $this->decode_response();
  80. return is_array($this->decoded_response)?
  81. isset($this->decoded_response[$key]) : isset($this->decoded_response->{$key});
  82. }
  83.  
  84. public function offsetGet($key){
  85. $this->decode_response();
  86. if(!$this->offsetExists($key))
  87. return NULL;
  88.  
  89. return is_array($this->decoded_response)?
  90. $this->decoded_response[$key] : $this->decoded_response->{$key};
  91. }
  92.  
  93. public function offsetSet($key, $value){
  94. throw new RestclientException("Decoded response data is immutable.");
  95. }
  96.  
  97. public function offsetUnset($key){
  98. throw new RestclientException("Decoded response data is immutable.");
  99. }
  100.  
  101. // Request methods:
  102. public function get($url, $parameters=[], $headers=[]){
  103. return $this->execute($url, 'GET', $parameters, $headers);
  104. }
  105.  
  106. public function post($url, $parameters=[], $headers=[]){
  107. return $this->execute($url, 'POST', $parameters, $headers);
  108. }
  109.  
  110. public function put($url, $parameters=[], $headers=[]){
  111. return $this->execute($url, 'PUT', $parameters, $headers);
  112. }
  113.  
  114. public function patch($url, $parameters=[], $headers=[]){
  115. return $this->execute($url, 'PATCH', $parameters, $headers);
  116. }
  117.  
  118. public function delete($url, $parameters=[], $headers=[]){
  119. return $this->execute($url, 'DELETE', $parameters, $headers);
  120. }
  121.  
  122. public function head($url, $parameters=[], $headers=[]){
  123. return $this->execute($url, 'HEAD', $parameters, $headers);
  124. }
  125.  
  126. public function execute($url, $method='GET', $parameters=[], $headers=[]){
  127. $client = clone $this;
  128. $client->url = $url;
  129. $client->handle = curl_init();
  130. $curlopt = [
  131. CURLOPT_HEADER => TRUE,
  132. CURLOPT_RETURNTRANSFER => TRUE,
  133. CURLOPT_USERAGENT => $client->options['user_agent']
  134. ];
  135.  
  136. if($client->options['username'] && $client->options['password'])
  137. $curlopt[CURLOPT_USERPWD] = sprintf("%s:%s",
  138. $client->options['username'], $client->options['password']);
  139.  
  140. if(count($client->options['headers']) || count($headers)){
  141. $curlopt[CURLOPT_HTTPHEADER] = [];
  142. $headers = array_merge($client->options['headers'], $headers);
  143. foreach($headers as $key => $values){
  144. foreach(is_array($values)? $values : [$values] as $value){
  145. $curlopt[CURLOPT_HTTPHEADER][] = sprintf("%s:%s", $key, $value);
  146. }
  147. }
  148. }
  149.  
  150. if($client->options['format'])
  151. $client->url .= '.'.$client->options['format'];
  152.  
  153. // Allow passing parameters as a pre-encoded string (or something that
  154. // allows casting to a string). Parameters passed as strings will not be
  155. // merged with parameters specified in the default options.
  156. if(is_array($parameters)){
  157. $parameters = array_merge($client->options['parameters'], $parameters);
  158. $parameters_string = http_build_query($parameters);
  159.  
  160. // http_build_query automatically adds an array index to repeated
  161. // parameters which is not desirable on most systems. This hack
  162. // reverts "key[0]=foo&key[1]=bar" to "key[]=foo&key[]=bar"
  163. if(!$client->options['build_indexed_queries'])
  164. $parameters_string = preg_replace(
  165. "/%5B[0-9]+%5D=/simU", "%5B%5D=", $parameters_string);
  166. }
  167. else
  168. $parameters_string = (string) $parameters;
  169.  
  170. if(strtoupper($method) == 'POST'){
  171. $curlopt[CURLOPT_POST] = TRUE;
  172. $curlopt[CURLOPT_POSTFIELDS] = $parameters_string;
  173. }
  174. elseif(strtoupper($method) != 'GET'){
  175. $curlopt[CURLOPT_CUSTOMREQUEST] = strtoupper($method);
  176. $curlopt[CURLOPT_POSTFIELDS] = $parameters_string;
  177. }
  178. elseif($parameters_string){
  179. $client->url .= strpos($client->url, '?')? '&' : '?';
  180. $client->url .= $parameters_string;
  181. }
  182.  
  183. if($client->options['base_url']){
  184. if($client->url[0] != '/' && substr($client->options['base_url'], -1) != '/')
  185. $client->url = '/' . $client->url;
  186. $client->url = $client->options['base_url'] . $client->url;
  187. }
  188. $curlopt[CURLOPT_URL] = $client->url;
  189.  
  190. if($client->options['curl_options']){
  191. // array_merge would reset our numeric keys.
  192. foreach($client->options['curl_options'] as $key => $value){
  193. $curlopt[$key] = $value;
  194. }
  195. }
  196. curl_setopt_array($client->handle, $curlopt);
  197.  
  198. $client->parse_response(curl_exec($client->handle));
  199. $client->info = (object) curl_getinfo($client->handle);
  200. $client->error = curl_error($client->handle);
  201.  
  202. curl_close($client->handle);
  203. return $client;
  204. }
  205.  
  206. public function parse_response($response){
  207. $headers = [];
  208. $this->response_status_lines = [];
  209. $line = strtok($response, "\n");
  210. do {
  211. if(strlen(trim($line)) == 0){
  212. // Since we tokenize on \n, use the remaining \r to detect empty lines.
  213. if(count($headers) > 0) break; // Must be the newline after headers, move on to response body
  214. }
  215. elseif(strpos($line, 'HTTP') === 0){
  216. // One or more HTTP status lines
  217. $this->response_status_lines[] = trim($line);
  218. }
  219. else {
  220. // Has to be a header
  221. list($key, $value) = explode(':', $line, 2);
  222. $key = trim(strtolower(str_replace('-', '_', $key)));
  223. $value = trim($value);
  224.  
  225. if(empty($headers[$key]))
  226. $headers[$key] = $value;
  227. elseif(is_array($headers[$key]))
  228. $headers[$key][] = $value;
  229. else
  230. $headers[$key] = [$headers[$key], $value];
  231. }
  232. } while($line = strtok("\n"));
  233.  
  234. $this->headers = (object) $headers;
  235. $this->response = strtok("");
  236. }
  237.  
  238. public function get_response_format(){
  239. if(!$this->response)
  240. throw new RestclientException(
  241. "A response must exist before it can be decoded.");
  242.  
  243. // User-defined format.
  244. if(!empty($this->options['format']))
  245. return $this->options['format'];
  246.  
  247. // Extract format from response content-type header.
  248. if(!empty($this->headers->content_type))
  249. if(preg_match($this->options['format_regex'], $this->headers->content_type, $matches))
  250. return $matches[2];
  251.  
  252. throw new RestclientException(
  253. "Response format could not be determined.");
  254. }
  255.  
  256. public function decode_response(){
  257. if(empty($this->decoded_response)){
  258. $format = $this->get_response_format();
  259. if(!array_key_exists($format, $this->options['decoders']))
  260. throw new RestclientException("'${format}' is not a supported ".
  261. "format, register a decoder to handle this response.");
  262.  
  263. $this->decoded_response = call_user_func(
  264. $this->options['decoders'][$format], $this->response);
  265. }
  266.  
  267. return $this->decoded_response;
  268. }
  269. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement