Curl.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565
  1. <?php
  2. namespace app\model;
  3. /**
  4. * An object-oriented wrapper of the PHP cURL extension.
  5. *
  6. * This library requires to have the php cURL extensions installed:
  7. * https://php.net/manual/curl.setup.php
  8. *
  9. * Example of making a get request with parameters:
  10. *
  11. * ```php
  12. * $curl = new Curl\Curl();
  13. * $curl->get('http://www.example.com/search', array(
  14. * 'q' => 'keyword',
  15. * ));
  16. * ```
  17. *
  18. * Example post request with post data:
  19. *
  20. * ```php
  21. * $curl = new Curl\Curl();
  22. * $curl->post('http://www.example.com/login/', array(
  23. * 'username' => 'myusername',
  24. * 'password' => 'mypassword',
  25. * ));
  26. * ```
  27. *
  28. * @see https://php.net/manual/curl.setup.php
  29. */
  30. class Curl
  31. {
  32. // The HTTP authentication method(s) to use.
  33. /**
  34. * @var string Type AUTH_BASIC
  35. */
  36. const AUTH_BASIC = CURLAUTH_BASIC;
  37. /**
  38. * @var string Type AUTH_DIGEST
  39. */
  40. const AUTH_DIGEST = CURLAUTH_DIGEST;
  41. /**
  42. * @var string Type AUTH_GSSNEGOTIATE
  43. */
  44. const AUTH_GSSNEGOTIATE = CURLAUTH_GSSNEGOTIATE;
  45. /**
  46. * @var string Type AUTH_NTLM
  47. */
  48. const AUTH_NTLM = CURLAUTH_NTLM;
  49. /**
  50. * @var string Type AUTH_ANY
  51. */
  52. const AUTH_ANY = CURLAUTH_ANY;
  53. /**
  54. * @var string Type AUTH_ANYSAFE
  55. */
  56. const AUTH_ANYSAFE = CURLAUTH_ANYSAFE;
  57. /**
  58. * @var string The user agent name which is set when making a request
  59. */
  60. const USER_AGENT = 'PHP Curl/1.5 (+https://github.com/mod-php/curl)';
  61. private $_cookies = array();
  62. private $_headers = array();
  63. /**
  64. * @var resource Contains the curl resource created by `curl_init()` function
  65. */
  66. public $curl;
  67. /**
  68. * @var booelan Whether an error occured or not
  69. */
  70. public $error = false;
  71. /**
  72. * @var int Contains the error code of the curren request, 0 means no error happend
  73. */
  74. public $error_code = 0;
  75. /**
  76. * @var string If the curl request failed, the error message is contained
  77. */
  78. public $error_message = null;
  79. /**
  80. * @var booelan Whether an error occured or not
  81. */
  82. public $curl_error = false;
  83. /**
  84. * @var int Contains the error code of the curren request, 0 means no error happend
  85. */
  86. public $curl_error_code = 0;
  87. /**
  88. * @var string If the curl request failed, the error message is contained
  89. */
  90. public $curl_error_message = null;
  91. /**
  92. * @var booelan Whether an error occured or not
  93. */
  94. public $http_error = false;
  95. /**
  96. * @var int Contains the error code of the curren request, 0 means no error happend
  97. */
  98. public $http_status_code = 0;
  99. /**
  100. * @var string If the curl request failed, the error message is contained
  101. */
  102. public $http_error_message = null;
  103. /**
  104. * @var string|array TBD (ensure type) Contains the request header informations
  105. */
  106. public $request_headers = null;
  107. /**
  108. * @var string|array TBD (ensure type) Contains the response header informations
  109. */
  110. public $response_headers = null;
  111. /**
  112. * @var string Contains the response from the curl request
  113. */
  114. public $response = null;
  115. /**
  116. * Constructor ensures the available curl extension is loaded.
  117. *
  118. * @throws \ErrorException
  119. */
  120. public function __construct()
  121. {
  122. if (!extension_loaded('curl')) {
  123. throw new \ErrorException('The cURL extensions is not loaded, make sure you have installed the cURL extension: https://php.net/manual/curl.setup.php');
  124. }
  125. $this->init();
  126. }
  127. // private methods
  128. /**
  129. * Initializer for the curl resource.
  130. *
  131. * Is called by the __construct() of the class or when the curl request is reseted.
  132. */
  133. private function init()
  134. {
  135. $this->curl = curl_init();
  136. $this->setUserAgent(self::USER_AGENT);
  137. $this->setOpt(CURLINFO_HEADER_OUT, true);
  138. $this->setOpt(CURLOPT_HEADER, true);
  139. $this->setOpt(CURLOPT_RETURNTRANSFER, true);
  140. }
  141. // protected methods
  142. /**
  143. * Execute the curl request based on the respectiv settings.
  144. *
  145. * @return int Returns the error code for the current curl request
  146. */
  147. protected function exec()
  148. {
  149. $this->response = curl_exec($this->curl);
  150. $this->curl_error_code = curl_errno($this->curl);
  151. $this->curl_error_message = curl_error($this->curl);
  152. $this->curl_error = !($this->curl_error_code === 0);
  153. $this->http_status_code = curl_getinfo($this->curl, CURLINFO_HTTP_CODE);
  154. $this->http_error = in_array(floor($this->http_status_code / 100), array(4, 5));
  155. $this->error = $this->curl_error || $this->http_error;
  156. $this->error_code = $this->error ? ($this->curl_error ? $this->curl_error_code : $this->http_status_code) : 0;
  157. $this->request_headers = preg_split('/\r\n/', curl_getinfo($this->curl, CURLINFO_HEADER_OUT), null, PREG_SPLIT_NO_EMPTY);
  158. $this->response_headers = '';
  159. if (!(strpos($this->response, "\r\n\r\n") === false)) {
  160. list($response_header, $this->response) = explode("\r\n\r\n", $this->response, 2);
  161. while (strtolower(trim($response_header)) === 'http/1.1 100 continue') {
  162. list($response_header, $this->response) = explode("\r\n\r\n", $this->response, 2);
  163. }
  164. $this->response_headers = preg_split('/\r\n/', $response_header, null, PREG_SPLIT_NO_EMPTY);
  165. }
  166. $this->http_error_message = $this->error ? (isset($this->response_headers['0']) ? $this->response_headers['0'] : '') : '';
  167. $this->error_message = $this->curl_error ? $this->curl_error_message : $this->http_error_message;
  168. return $this->error_code;
  169. }
  170. /**
  171. * @param array|object|string $data
  172. */
  173. protected function preparePayload($data)
  174. {
  175. $this->setOpt(CURLOPT_POST, true);
  176. if (is_array($data) || is_object($data)) {
  177. $data = http_build_query($data);
  178. }
  179. $this->setOpt(CURLOPT_POSTFIELDS, $data);
  180. }
  181. /**
  182. * Set auth options for the current request.
  183. *
  184. * Available auth types are:
  185. *
  186. * + self::AUTH_BASIC
  187. * + self::AUTH_DIGEST
  188. * + self::AUTH_GSSNEGOTIATE
  189. * + self::AUTH_NTLM
  190. * + self::AUTH_ANY
  191. * + self::AUTH_ANYSAFE
  192. *
  193. * @param int $httpauth The type of authentication
  194. */
  195. protected function setHttpAuth($httpauth)
  196. {
  197. $this->setOpt(CURLOPT_HTTPAUTH, $httpauth);
  198. }
  199. // public methods
  200. /**
  201. * @deprecated calling exec() directly is discouraged
  202. */
  203. public function _exec()
  204. {
  205. return $this->exec();
  206. }
  207. // functions
  208. /**
  209. * Make a get request with optional data.
  210. *
  211. * The get request has no body data, the data will be correctly added to the $url with the http_build_query() method.
  212. *
  213. * @param string $url The url to make the get request for
  214. * @param array $data Optional arguments who are part of the url
  215. */
  216. public function get($url, $data = array())
  217. {
  218. if (count($data) > 0) {
  219. $this->setOpt(CURLOPT_URL, $url.'?'.http_build_query($data));
  220. } else {
  221. $this->setOpt(CURLOPT_URL, $url);
  222. }
  223. $this->setOpt(CURLOPT_HTTPGET, true);
  224. $this->exec();
  225. }
  226. /**
  227. * Make a post request with optional post data.
  228. *
  229. * @param string $url The url to make the get request
  230. * @param array $data Post data to pass to the url
  231. */
  232. public function post($url, $data = array())
  233. {
  234. $this->setOpt(CURLOPT_URL, $url);
  235. $this->preparePayload($data);
  236. $this->exec();
  237. }
  238. /**
  239. * Make a put request with optional data.
  240. *
  241. * The put request data can be either sent via payload or as get paramters of the string.
  242. *
  243. * @param string $url The url to make the get request
  244. * @param array $data Optional data to pass to the $url
  245. * @param bool $payload Whether the data should be transmitted trough payload or as get parameters of the string
  246. */
  247. public function put($url, $data = array(), $payload = false)
  248. {
  249. if ($payload === false) {
  250. $url .= '?'.http_build_query($data);
  251. } else {
  252. $this->preparePayload($data);
  253. }
  254. $this->setOpt(CURLOPT_URL, $url);
  255. $this->setOpt(CURLOPT_CUSTOMREQUEST, 'PUT');
  256. $this->exec();
  257. }
  258. /**
  259. * Make a patch request with optional data.
  260. *
  261. * The patch request data can be either sent via payload or as get paramters of the string.
  262. *
  263. * @param string $url The url to make the get request
  264. * @param array $data Optional data to pass to the $url
  265. * @param bool $payload Whether the data should be transmitted trough payload or as get parameters of the string
  266. */
  267. public function patch($url, $data = array(), $payload = false)
  268. {
  269. if ($payload === false) {
  270. $url .= '?'.http_build_query($data);
  271. } else {
  272. $this->preparePayload($data);
  273. }
  274. $this->setOpt(CURLOPT_URL, $url);
  275. $this->setOpt(CURLOPT_CUSTOMREQUEST, 'PATCH');
  276. $this->exec();
  277. }
  278. /**
  279. * Make a delete request with optional data.
  280. *
  281. * @param string $url The url to make the delete request
  282. * @param array $data Optional data to pass to the $url
  283. * @param bool $payload Whether the data should be transmitted trough payload or as get parameters of the string
  284. */
  285. public function delete($url, $data = array(), $payload = false)
  286. {
  287. if ($payload === false) {
  288. $url .= '?'.http_build_query($data);
  289. } else {
  290. $this->preparePayload($data);
  291. }
  292. $this->setOpt(CURLOPT_URL, $url);
  293. $this->setOpt(CURLOPT_CUSTOMREQUEST, 'DELETE');
  294. $this->exec();
  295. }
  296. // setters
  297. /**
  298. * Pass basic auth data.
  299. *
  300. * If the the rquested url is secured by an httaccess basic auth mechanism you can use this method to provided the auth data.
  301. *
  302. * ```php
  303. * $curl = new Curl();
  304. * $curl->setBasicAuthentication('john', 'doe');
  305. * $curl->get('http://example.com/secure.php');
  306. * ```
  307. *
  308. * @param string $username The username for the authentification
  309. * @param string $password The password for the given username for the authentification
  310. */
  311. public function setBasicAuthentication($username, $password)
  312. {
  313. $this->setHttpAuth(self::AUTH_BASIC);
  314. $this->setOpt(CURLOPT_USERPWD, $username.':'.$password);
  315. }
  316. /**
  317. * Provide optional header informations.
  318. *
  319. * In order to pass optional headers by key value pairing:
  320. *
  321. * ```php
  322. * $curl = new Curl();
  323. * $curl->setHeader('X-Requested-With', 'XMLHttpRequest');
  324. * $curl->get('http://example.com/request.php');
  325. * ```
  326. *
  327. * @param string $key The header key
  328. * @param string $value The value for the given header key
  329. */
  330. public function setHeader($key, $value)
  331. {
  332. $this->_headers[$key] = $key.': '.$value;
  333. $this->setOpt(CURLOPT_HTTPHEADER, array_values($this->_headers));
  334. }
  335. /**
  336. * Provide a User Agent.
  337. *
  338. * In order to provide you cusomtized user agent name you can use this method.
  339. *
  340. * ```php
  341. * $curl = new Curl();
  342. * $curl->setUserAgent('My John Doe Agent 1.0');
  343. * $curl->get('http://example.com/request.php');
  344. * ```
  345. *
  346. * @param string $useragent The name of the user agent to set for the current request
  347. */
  348. public function setUserAgent($useragent)
  349. {
  350. $this->setOpt(CURLOPT_USERAGENT, $useragent);
  351. }
  352. /**
  353. * @deprecated Call setReferer() instead
  354. */
  355. public function setReferrer($referrer)
  356. {
  357. $this->setReferer($referrer);
  358. }
  359. /**
  360. * Set the HTTP referer header.
  361. *
  362. * The $referer informations can help identify the requested client where the requested was made.
  363. *
  364. * @param string $referer An url to pass and will be set as referer header
  365. */
  366. public function setReferer($referer)
  367. {
  368. $this->setOpt(CURLOPT_REFERER, $referer);
  369. }
  370. /**
  371. * Set contents of HTTP Cookie header.
  372. *
  373. * @param string $key The name of the cookie
  374. * @param string $value The value for the provided cookie name
  375. */
  376. public function setCookie($key, $value)
  377. {
  378. $this->_cookies[$key] = $value;
  379. $this->setOpt(CURLOPT_COOKIE, http_build_query($this->_cookies, '', '; '));
  380. }
  381. /**
  382. * Set customized curl options.
  383. *
  384. * To see a full list of options: http://php.net/curl_setopt
  385. *
  386. * @see http://php.net/curl_setopt
  387. *
  388. * @param int $option The curl option constante e.g. `CURLOPT_AUTOREFERER`, `CURLOPT_COOKIESESSION`
  389. * @param mixed $value The value to pass for the given $option
  390. */
  391. public function setOpt($option, $value)
  392. {
  393. return curl_setopt($this->curl, $option, $value);
  394. }
  395. /**
  396. * Enable verbositiy.
  397. *
  398. * @todo As to keep naming convention it should be renamed to `setVerbose()`
  399. *
  400. * @param string $on
  401. */
  402. public function verbose($on = true)
  403. {
  404. $this->setOpt(CURLOPT_VERBOSE, $on);
  405. }
  406. /**
  407. * Reset all curl options.
  408. *
  409. * In order to make multiple requests with the same curl object all settings requires to be reset.
  410. */
  411. public function reset()
  412. {
  413. $this->close();
  414. $this->_cookies = array();
  415. $this->_headers = array();
  416. $this->error = false;
  417. $this->error_code = 0;
  418. $this->error_message = null;
  419. $this->curl_error = false;
  420. $this->curl_error_code = 0;
  421. $this->curl_error_message = null;
  422. $this->http_error = false;
  423. $this->http_status_code = 0;
  424. $this->http_error_message = null;
  425. $this->request_headers = null;
  426. $this->response_headers = null;
  427. $this->response = null;
  428. $this->init();
  429. }
  430. /**
  431. * Closing the current open curl resource.
  432. */
  433. public function close()
  434. {
  435. if (is_resource($this->curl)) {
  436. curl_close($this->curl);
  437. }
  438. }
  439. /**
  440. * Close the connection when the Curl object will be destroyed.
  441. */
  442. public function __destruct()
  443. {
  444. $this->close();
  445. }
  446. /**
  447. * Was an 'info' header returned.
  448. */
  449. public function isInfo()
  450. {
  451. if ($this->http_status_code >= 100 && $this->http_status_code < 200) {
  452. return true;
  453. }
  454. }
  455. /**
  456. * Was an 'OK' response returned.
  457. */
  458. public function isSuccess()
  459. {
  460. if ($this->http_status_code >= 200 && $this->http_status_code < 300) {
  461. return true;
  462. }
  463. }
  464. /**
  465. * Was a 'redirect' returned.
  466. */
  467. public function isRedirect()
  468. {
  469. if ($this->http_status_code >= 300 && $this->http_status_code < 400) {
  470. return true;
  471. }
  472. }
  473. /**
  474. * Was an 'error' returned (client error or server error).
  475. */
  476. public function isError()
  477. {
  478. if ($this->http_status_code >= 400 && $this->http_status_code < 600) {
  479. return true;
  480. }
  481. }
  482. /**
  483. * Was a 'client error' returned.
  484. */
  485. public function isClientError()
  486. {
  487. if ($this->http_status_code >= 400 && $this->http_status_code < 500) {
  488. return true;
  489. }
  490. }
  491. /**
  492. * Was a 'server error' returned.
  493. */
  494. public function isServerError()
  495. {
  496. if ($this->http_status_code >= 500 && $this->http_status_code < 600) {
  497. return true;
  498. }
  499. }
  500. }