PageRenderTime 56ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/src/NBOS/http/Curl.php

https://gitlab.com/nboscode_starter/nbos_dev_php_starter
PHP | 401 lines | 295 code | 64 blank | 42 comment | 42 complexity | d7ca042808f7ad60e8dbdd7005431af9 MD5 | raw file
  1. <?php
  2. namespace NBOS\http;
  3. class Curl {
  4. protected $response = ''; // Contains the cURL response for debug
  5. protected $response_header = '';
  6. protected $session; // Contains the cURL handler for a session
  7. protected $url; // URL of the session
  8. protected $options = array(); // Populates curl_setopt_array
  9. protected $headers = array(); // Populates extra HTTP headers
  10. protected $http_method = 'get';
  11. public $format = null;
  12. public $mime_type = null;
  13. public $error_code; // Error code returned as an int
  14. public $error_string; // Error message returned as a string
  15. public $info = null; // Returned after request (elapsed time, etc)
  16. private $log = null;
  17. public $last_info = null;
  18. public $last_response_header = null;
  19. function __construct($url = '')
  20. {
  21. $url AND $this->create($url);
  22. if(defined('CURL_DEBUG') && CURL_DEBUG === true && class_exists('\Monolog\Logger')){
  23. $this->log = new \Monolog\Logger('client_request');
  24. $log_file_path = dirname(dirname(__FILE__)).'/logs/'.date("Y-m-d").'api_requests.log';
  25. if(!file_exists(dirname(dirname(__FILE__)).'/logs/')){
  26. mkdir(dirname(dirname(__FILE__)).'/logs/');
  27. }
  28. if(!file_exists($log_file_path)){
  29. $fp = fopen($log_file_path, 'a');
  30. fclose($fp);
  31. }
  32. $this->log->pushHandler(new \Monolog\Handler\StreamHandler($log_file_path, \Monolog\Logger::INFO));
  33. }
  34. }
  35. public function __call($method, $arguments)
  36. {
  37. if (in_array($method, array('simple_get', 'simple_post', 'simple_put', 'simple_delete', 'simple_patch')))
  38. {
  39. // Take off the "simple_" and past get/post/put/delete/patch to _simple_call
  40. $verb = str_replace('simple_', '', $method);
  41. array_unshift($arguments, $verb);
  42. return call_user_func_array(array($this, '_simple_call'), $arguments);
  43. }
  44. }
  45. /* =================================================================================
  46. * SIMPLE METHODS
  47. * Using these methods you can make a quick and easy cURL call with one line.
  48. * ================================================================================= */
  49. public function _simple_call($method, $url, $params = array(), $options = array())
  50. {
  51. // Get acts differently, as it doesnt accept parameters in the same way
  52. if ($method === 'get')
  53. {
  54. // If a URL is provided, create new session
  55. $this->create($url.($params ? '?'.http_build_query($params, NULL, '&') : ''));
  56. }
  57. else
  58. {
  59. // If a URL is provided, create new session
  60. $this->create($url);
  61. $this->{$method}($params);
  62. }
  63. // Add in the specific options provided
  64. $this->options($options);
  65. return $this->execute();
  66. }
  67. public function simple_ftp_get($url, $file_path, $username = '', $password = '')
  68. {
  69. // If there is no ftp:// or any protocol entered, add ftp://
  70. if ( ! preg_match('!^(ftp|sftp)://! i', $url))
  71. {
  72. $url = 'ftp://' . $url;
  73. }
  74. // Use an FTP login
  75. if ($username != '')
  76. {
  77. $auth_string = $username;
  78. if ($password != '')
  79. {
  80. $auth_string .= ':' . $password;
  81. }
  82. // Add the user auth string after the protocol
  83. $url = str_replace('://', '://' . $auth_string . '@', $url);
  84. }
  85. // Add the filepath
  86. $url .= $file_path;
  87. $this->option(CURLOPT_BINARYTRANSFER, TRUE);
  88. $this->option(CURLOPT_VERBOSE, TRUE);
  89. return $this->execute();
  90. }
  91. /* =================================================================================
  92. * ADVANCED METHODS
  93. * Use these methods to build up more complex queries
  94. * ================================================================================= */
  95. public function post($params = array(), $options = array())
  96. {
  97. // If its an array (instead of a query string) then format it correctly
  98. if (is_array($params))
  99. {
  100. if($this->format == "json"){
  101. $params = json_encode($params);
  102. }else{
  103. if(!empty($_FILES)){
  104. foreach($_FILES as $fileField => $fileVal){
  105. $params[$fileField] = curl_file_create($fileVal['tmp_name'], $fileVal['type'], $fileVal['name']);
  106. }
  107. }else{
  108. $params = http_build_query($params, NULL, '&');
  109. }
  110. }
  111. }
  112. // Add in the specific options provided
  113. $this->options($options);
  114. $this->http_method('post');
  115. $this->option(CURLOPT_POST, TRUE);
  116. $this->option(CURLOPT_POSTFIELDS, $params);
  117. }
  118. public function put($params = array(), $options = array())
  119. {
  120. // If its an array (instead of a query string) then format it correctly
  121. if (is_array($params))
  122. {
  123. if($this->format == "json"){
  124. $params = json_encode($params);
  125. }else{
  126. //$params = http_build_query($params, NULL, '&');
  127. }
  128. }
  129. // Add in the specific options provided
  130. $this->options($options);
  131. $this->http_method('put');
  132. $this->option(CURLOPT_POSTFIELDS, $params);
  133. // Override method, I think this overrides $_POST with PUT data but... we'll see eh?
  134. $this->option(CURLOPT_HTTPHEADER, array('X-HTTP-Method-Override: PUT'));
  135. }
  136. public function patch($params = array(), $options = array())
  137. {
  138. // If its an array (instead of a query string) then format it correctly
  139. if (is_array($params))
  140. {
  141. $params = http_build_query($params, NULL, '&');
  142. }
  143. // Add in the specific options provided
  144. $this->options($options);
  145. $this->http_method('patch');
  146. $this->option(CURLOPT_POSTFIELDS, $params);
  147. // Override method, I think this overrides $_POST with PATCH data but... we'll see eh?
  148. $this->option(CURLOPT_HTTPHEADER, array('X-HTTP-Method-Override: PATCH'));
  149. }
  150. public function delete($params, $options = array())
  151. {
  152. // If its an array (instead of a query string) then format it correctly
  153. if(is_array($params) && $this->format == "json"){
  154. $params = json_encode($params);
  155. }else if (is_array($params)){
  156. $params = http_build_query($params, NULL, '&');
  157. }
  158. // Add in the specific options provided
  159. $this->options($options);
  160. $this->http_method('delete');
  161. $this->option(CURLOPT_POSTFIELDS, $params);
  162. }
  163. public function set_cookies($params = array())
  164. {
  165. if (is_array($params))
  166. {
  167. $params = http_build_query($params, NULL, '&');
  168. }
  169. $this->option(CURLOPT_COOKIE, $params);
  170. return $this;
  171. }
  172. public function http_header($header, $content = NULL)
  173. {
  174. $this->headers[] = $content ? $header . ': ' . $content : $header;
  175. return $this;
  176. }
  177. public function http_method($method)
  178. {
  179. $this->http_method = $method;
  180. $this->options[CURLOPT_CUSTOMREQUEST] = strtoupper($method);
  181. return $this;
  182. }
  183. public function http_login($username = '', $password = '', $type = 'any')
  184. {
  185. $this->option(CURLOPT_HTTPAUTH, constant('CURLAUTH_' . strtoupper($type)));
  186. $this->option(CURLOPT_USERPWD, $username . ':' . $password);
  187. return $this;
  188. }
  189. public function proxy($url = '', $port = 80)
  190. {
  191. $this->option(CURLOPT_HTTPPROXYTUNNEL, TRUE);
  192. $this->option(CURLOPT_PROXY, $url . ':' . $port);
  193. return $this;
  194. }
  195. public function proxy_login($username = '', $password = '')
  196. {
  197. $this->option(CURLOPT_PROXYUSERPWD, $username . ':' . $password);
  198. return $this;
  199. }
  200. public function ssl($verify_peer = TRUE, $verify_host = 2, $path_to_cert = NULL)
  201. {
  202. if ($verify_peer)
  203. {
  204. $this->option(CURLOPT_SSL_VERIFYPEER, TRUE);
  205. $this->option(CURLOPT_SSL_VERIFYHOST, $verify_host);
  206. if (isset($path_to_cert)) {
  207. $path_to_cert = realpath($path_to_cert);
  208. $this->option(CURLOPT_CAINFO, $path_to_cert);
  209. }
  210. }
  211. else
  212. {
  213. $this->option(CURLOPT_SSL_VERIFYPEER, FALSE);
  214. }
  215. return $this;
  216. }
  217. public function options($options = array())
  218. {
  219. // Merge options in with the rest - done as array_merge() does not overwrite numeric keys
  220. foreach ($options as $option_code => $option_value)
  221. {
  222. $this->option($option_code, $option_value);
  223. }
  224. // Set all options provided
  225. curl_setopt_array($this->session, $this->options);
  226. return $this;
  227. }
  228. public function option($code, $value, $prefix = 'opt')
  229. {
  230. if (is_string($code) && !is_numeric($code))
  231. {
  232. $code = constant('CURL' . strtoupper($prefix) . '_' . strtoupper($code));
  233. }
  234. $this->options[$code] = $value;
  235. return $this;
  236. }
  237. // Start a session from a URL
  238. public function create($url)
  239. {
  240. $this->url = $url;
  241. $this->session = curl_init($this->url);
  242. return $this;
  243. }
  244. // End a session and return the results
  245. public function execute()
  246. {
  247. // Set two default options, and merge any extra ones in
  248. if ( ! isset($this->options[CURLOPT_TIMEOUT]))
  249. {
  250. $this->options[CURLOPT_TIMEOUT] = 30;
  251. }
  252. if ( ! isset($this->options[CURLOPT_RETURNTRANSFER]))
  253. {
  254. $this->options[CURLOPT_RETURNTRANSFER] = TRUE;
  255. }
  256. if ( ! isset($this->options[CURLOPT_FAILONERROR]))
  257. {
  258. $this->options[CURLOPT_FAILONERROR] = TRUE;
  259. }
  260. // Only set follow location if not running securely
  261. if ( ! ini_get('safe_mode') && ! ini_get('open_basedir'))
  262. {
  263. // Ok, follow location is not set already so lets set it to true
  264. if ( ! isset($this->options[CURLOPT_FOLLOWLOCATION]))
  265. {
  266. $this->options[CURLOPT_FOLLOWLOCATION] = TRUE;
  267. }
  268. }
  269. if ( ! empty($this->headers))
  270. {
  271. $this->option(CURLOPT_HTTPHEADER, $this->headers);
  272. }
  273. $this->options();
  274. curl_setopt($this->session, CURLINFO_HEADER_OUT, true);
  275. curl_setopt($this->session, CURLOPT_HEADER, 1);
  276. // Execute the request & and hide all output
  277. $this->response = curl_exec($this->session);
  278. if($this->response !== false){
  279. $this->info = curl_getinfo($this->session);
  280. // Split header and body response
  281. //$header_size = curl_getinfo($this->session, CURLINFO_HEADER_SIZE);
  282. //$this->response_header = substr($this->response, 0, $header_size);
  283. //$this->response = substr($this->response, $header_size);
  284. list($this->response_header, $this->response) = explode("\r\n\r\n", $this->response);
  285. if(defined('CURL_DEBUG') && $this->log !== null){
  286. $this->log->addInfo($this->url, [
  287. "Request" => $this->info,
  288. "Response" => $this->response
  289. ]);
  290. }
  291. }else{
  292. if(defined('CURL_DEBUG') && $this->log !== null){
  293. $this->log->addError("Server not responding!", ["URL" => $this->url], ["message" => "test"]);
  294. }
  295. }
  296. // Request failed
  297. if ($this->response === FALSE)
  298. {
  299. $errno = curl_errno($this->session);
  300. $error = curl_error($this->session);
  301. curl_close($this->session);
  302. $this->set_defaults();
  303. $this->error_code = $errno;
  304. $this->error_string = $error;
  305. return FALSE;
  306. }
  307. // Request successful
  308. else
  309. {
  310. curl_close($this->session);
  311. $this->last_response = $this->response;
  312. $this->last_response_header = $this->response_header;
  313. $this->last_info = $this->info;
  314. $this->set_defaults();
  315. return $this->last_response;
  316. }
  317. }
  318. public function is_enabled()
  319. {
  320. return function_exists('curl_init');
  321. }
  322. public function debug_request()
  323. {
  324. return array(
  325. 'url' => $this->url
  326. );
  327. }
  328. public function set_defaults()
  329. {
  330. $this->response = '';
  331. $this->headers = array();
  332. $this->options = array();
  333. $this->error_code = NULL;
  334. $this->error_string = '';
  335. $this->session = NULL;
  336. }
  337. }