/classes/request/curl.php

https://github.com/michael-lefebvre/core · PHP · 251 lines · 135 code · 37 blank · 79 comment · 14 complexity · ea8446a83fe093e904c90e10b03becc9 MD5 · raw file

  1. <?php
  2. namespace Fuel\Core;
  3. class Request_Curl extends \Request_Driver
  4. {
  5. /**
  6. * @var string to preserve the original resource url when using get
  7. */
  8. protected $preserve_resource;
  9. /**
  10. * Extends parent constructor to detect availability of cURL
  11. *
  12. * @param string $resource
  13. * @param array $options
  14. * @throws \RuntimeException
  15. */
  16. public function __construct($resource, array $options)
  17. {
  18. // check if we have libcurl available
  19. if ( ! function_exists('curl_init'))
  20. {
  21. throw new \RuntimeException('Your PHP installation doesn\'t have cURL enabled. Rebuild PHP with --with-curl');
  22. }
  23. // If authentication is enabled use it
  24. if ( ! empty($options['auth']) and ! empty($options['user']) and ! empty($options['pass']))
  25. {
  26. $this->http_login($options['user'], $options['pass'], $options['auth']);
  27. }
  28. // we want to handle failure ourselves
  29. $this->set_option('failonerror', false);
  30. parent::__construct($resource, $options);
  31. }
  32. /**
  33. * Change the HTTP method
  34. *
  35. * @param string $method
  36. * @return Request_Curl
  37. */
  38. public function set_method($method)
  39. {
  40. $this->options[CURLOPT_CUSTOMREQUEST] = strtoupper($method);
  41. return $this;
  42. }
  43. /**
  44. * Fetch the connection, create if necessary
  45. *
  46. * @return \resource
  47. */
  48. protected function connection()
  49. {
  50. // If no a protocol in URL, assume its a local link
  51. ! preg_match('!^\w+://! i', $this->resource) and $this->resource = Uri::create($this->resource);
  52. return curl_init($this->resource);
  53. }
  54. /**
  55. * Authenticate to an http server
  56. *
  57. * @param string $username
  58. * @param string $password
  59. * @param string $type
  60. * @return Request_Curl
  61. */
  62. public function http_login($username = '', $password = '', $type = 'any')
  63. {
  64. $this->set_option(CURLOPT_HTTPAUTH, constant('CURLAUTH_' . strtoupper($type)));
  65. $this->set_option(CURLOPT_USERPWD, $username . ':' . $password);
  66. return $this;
  67. }
  68. /**
  69. * Overwrites driver method to set options driver specifically
  70. *
  71. * @param int|string $code
  72. * @param mixed $value
  73. * @return Request_Curl
  74. */
  75. public function set_options(array $options)
  76. {
  77. foreach ($options as $key => $val)
  78. {
  79. if (is_string($key) && ! is_numeric($key))
  80. {
  81. $key = constant('CURLOPT_' . strtoupper($key));
  82. }
  83. $this->options[$key] = $val;
  84. }
  85. return $this;
  86. }
  87. public function execute(array $additional_params = array())
  88. {
  89. // Reset response
  90. $this->response = null;
  91. $this->response_info = array();
  92. // Set two default options, and merge any extra ones in
  93. if ( ! isset($this->options[CURLOPT_TIMEOUT]))
  94. {
  95. $this->options[CURLOPT_TIMEOUT] = 30;
  96. }
  97. if ( ! isset($this->options[CURLOPT_RETURNTRANSFER]))
  98. {
  99. $this->options[CURLOPT_RETURNTRANSFER] = true;
  100. }
  101. if ( ! isset($this->options[CURLOPT_FAILONERROR]))
  102. {
  103. $this->options[CURLOPT_FAILONERROR] = true;
  104. }
  105. // Only set follow location if not running securely
  106. if ( ! ini_get('safe_mode') && ! ini_get('open_basedir'))
  107. {
  108. // Ok, follow location is not set already so lets set it to true
  109. if ( ! isset($this->options[CURLOPT_FOLLOWLOCATION]))
  110. {
  111. $this->options[CURLOPT_FOLLOWLOCATION] = true;
  112. }
  113. }
  114. if ( ! empty($this->headers))
  115. {
  116. $this->set_option(CURLOPT_HTTPHEADER, $this->get_headers());
  117. }
  118. $additional_params and $this->params = \Arr::merge($this->params, $additional_params);
  119. if ( ! empty($this->options[CURLOPT_CUSTOMREQUEST]))
  120. {
  121. $this->{'method_'.strtolower($this->options[CURLOPT_CUSTOMREQUEST])}();
  122. }
  123. else
  124. {
  125. $this->method_get();
  126. }
  127. $connection = $this->connection();
  128. curl_setopt_array($connection, $this->options);
  129. // Execute the request & and hide all output
  130. $body = curl_exec($connection);
  131. $this->response_info = curl_getinfo($connection);
  132. $mime = isset($this->headers['Accept']) ? $this->headers['Accept'] : $this->response_info('content_type', 'text/plain');
  133. $this->set_response($body, $this->response_info('http_code', 200), $mime);
  134. // Request failed
  135. if ($body === false or $this->response->status >= 400)
  136. {
  137. $this->set_defaults();
  138. throw new \RequestException(curl_error($connection), curl_errno($connection));
  139. }
  140. else
  141. {
  142. // Request successful
  143. curl_close($connection);
  144. $this->set_defaults();
  145. return $this;
  146. }
  147. }
  148. /**
  149. * Extends parent to reset headers as well
  150. *
  151. * @return Request_Curl
  152. */
  153. protected function set_defaults()
  154. {
  155. parent::set_defaults();
  156. $this->headers = array();
  157. if ( ! empty($this->preserve_resource))
  158. {
  159. $this->resource = $this->preserve_resource;
  160. $this->preserve_resource = null;
  161. }
  162. return $this;
  163. }
  164. /**
  165. * GET request
  166. *
  167. * @param array $params
  168. * @param array $options
  169. * @return void
  170. */
  171. protected function method_get()
  172. {
  173. $this->preserve_resource = $this->resource;
  174. $this->resource = \Uri::create($this->resource, array(), $this->params);
  175. }
  176. /**
  177. * POST request
  178. *
  179. * @param array $params
  180. * @return void
  181. */
  182. protected function method_post()
  183. {
  184. $params = http_build_query($this->params, null, '&');
  185. $this->set_option(CURLOPT_POST, true);
  186. $this->set_option(CURLOPT_POSTFIELDS, $params);
  187. }
  188. /**
  189. * PUT request
  190. *
  191. * @param array $params
  192. * @return void
  193. */
  194. protected function method_put()
  195. {
  196. $params = http_build_query($this->params, null, '&');
  197. $this->set_option(CURLOPT_POSTFIELDS, $params);
  198. // Override method, I think this makes $_POST DELETE data but... we'll see eh?
  199. $this->set_header('X-HTTP-Method-Override', 'PUT');
  200. }
  201. /**
  202. * DELETE request
  203. *
  204. * @param array $params
  205. * @return void
  206. */
  207. protected function method_delete()
  208. {
  209. $params = http_build_query($this->params, null, '&');
  210. $this->set_option(CURLOPT_POSTFIELDS, $params);
  211. // Override method, I think this makes $_POST DELETE data but... we'll see eh?
  212. $this->set_header('X-HTTP-Method-Override', 'DELETE');
  213. }
  214. }