Curl.php 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. /**
  7. * HTTP CURL Adapter
  8. *
  9. * @author Magento Core Team <core@magentocommerce.com>
  10. */
  11. namespace Magento\Framework\HTTP\Adapter;
  12. /**
  13. * Curl http adapter
  14. */
  15. class Curl implements \Zend_Http_Client_Adapter_Interface
  16. {
  17. /**
  18. * Parameters array
  19. *
  20. * @var array
  21. */
  22. protected $_config = [
  23. 'protocols' => (CURLPROTO_HTTP
  24. | CURLPROTO_HTTPS
  25. | CURLPROTO_FTP
  26. | CURLPROTO_FTPS
  27. ),
  28. 'verifypeer' => true,
  29. 'verifyhost' => 2
  30. ];
  31. /**
  32. * Curl handle
  33. *
  34. * @var resource
  35. */
  36. protected $_resource;
  37. /**
  38. * Allow parameters
  39. *
  40. * @var array
  41. */
  42. protected $_allowedParams = [
  43. 'timeout' => CURLOPT_TIMEOUT,
  44. 'maxredirects' => CURLOPT_MAXREDIRS,
  45. 'proxy' => CURLOPT_PROXY,
  46. 'ssl_cert' => CURLOPT_SSLCERT,
  47. 'userpwd' => CURLOPT_USERPWD,
  48. 'useragent' => CURLOPT_USERAGENT,
  49. 'referer' => CURLOPT_REFERER,
  50. 'protocols' => CURLOPT_PROTOCOLS,
  51. 'verifypeer' => CURLOPT_SSL_VERIFYPEER,
  52. 'verifyhost' => CURLOPT_SSL_VERIFYHOST,
  53. 'sslversion' => CURLOPT_SSLVERSION,
  54. ];
  55. /**
  56. * Array of CURL options
  57. *
  58. * @var array
  59. */
  60. protected $_options = [];
  61. /**
  62. * Apply current configuration array to transport resource
  63. *
  64. * @return \Magento\Framework\HTTP\Adapter\Curl
  65. */
  66. protected function _applyConfig()
  67. {
  68. // apply additional options to cURL
  69. foreach ($this->_options as $option => $value) {
  70. curl_setopt($this->_getResource(), $option, $value);
  71. }
  72. // apply config options
  73. foreach ($this->getDefaultConfig() as $option => $value) {
  74. curl_setopt($this->_getResource(), $option, $value);
  75. }
  76. return $this;
  77. }
  78. /**
  79. * Get default options
  80. *
  81. * @return array
  82. */
  83. private function getDefaultConfig()
  84. {
  85. $config = [];
  86. foreach (array_keys($this->_config) as $param) {
  87. if (array_key_exists($param, $this->_allowedParams)) {
  88. $config[$this->_allowedParams[$param]] = $this->_config[$param];
  89. }
  90. }
  91. return $config;
  92. }
  93. /**
  94. * Set array of additional cURL options
  95. *
  96. * @param array $options
  97. * @return $this
  98. */
  99. public function setOptions(array $options = [])
  100. {
  101. $this->_options = $options;
  102. return $this;
  103. }
  104. /**
  105. * Add additional option to cURL
  106. *
  107. * @param int $option the CURLOPT_* constants
  108. * @param mixed $value
  109. * @return $this
  110. */
  111. public function addOption($option, $value)
  112. {
  113. $this->_options[$option] = $value;
  114. return $this;
  115. }
  116. /**
  117. * Set the configuration array for the adapter
  118. *
  119. * @param array $config
  120. * @return $this
  121. */
  122. public function setConfig($config = [])
  123. {
  124. foreach ($config as $key => $value) {
  125. $this->_config[$key] = $value;
  126. }
  127. return $this;
  128. }
  129. /**
  130. * Connect to the remote server
  131. *
  132. * @param string $host
  133. * @param int $port
  134. * @param boolean $secure
  135. * @return $this
  136. * @SuppressWarnings(PHPMD.UnusedFormalParameter)
  137. */
  138. public function connect($host, $port = 80, $secure = false)
  139. {
  140. return $this->_applyConfig();
  141. }
  142. /**
  143. * Send request to the remote server
  144. *
  145. * @param string $method
  146. * @param string $url
  147. * @param string $http_ver
  148. * @param array $headers
  149. * @param string $body
  150. * @return string Request as text
  151. * @SuppressWarnings(PHPMD.UnusedFormalParameter)
  152. */
  153. public function write($method, $url, $http_ver = '1.1', $headers = [], $body = '')
  154. {
  155. $this->_applyConfig();
  156. // set url to post to
  157. curl_setopt($this->_getResource(), CURLOPT_URL, $url);
  158. curl_setopt($this->_getResource(), CURLOPT_RETURNTRANSFER, true);
  159. if ($method == \Zend_Http_Client::POST) {
  160. curl_setopt($this->_getResource(), CURLOPT_POST, true);
  161. curl_setopt($this->_getResource(), CURLOPT_CUSTOMREQUEST, 'POST');
  162. curl_setopt($this->_getResource(), CURLOPT_POSTFIELDS, $body);
  163. } elseif ($method == \Zend_Http_Client::PUT) {
  164. curl_setopt($this->_getResource(), CURLOPT_CUSTOMREQUEST, 'PUT');
  165. curl_setopt($this->_getResource(), CURLOPT_POSTFIELDS, $body);
  166. } elseif ($method == \Zend_Http_Client::GET) {
  167. curl_setopt($this->_getResource(), CURLOPT_HTTPGET, true);
  168. curl_setopt($this->_getResource(), CURLOPT_CUSTOMREQUEST, 'GET');
  169. }
  170. if (is_array($headers)) {
  171. curl_setopt($this->_getResource(), CURLOPT_HTTPHEADER, $headers);
  172. }
  173. /**
  174. * @internal Curl options setter have to be re-factored
  175. */
  176. $header = isset($this->_config['header']) ? $this->_config['header'] : true;
  177. curl_setopt($this->_getResource(), CURLOPT_HEADER, $header);
  178. return $body;
  179. }
  180. /**
  181. * Read response from server
  182. *
  183. * @return string
  184. */
  185. public function read()
  186. {
  187. $response = curl_exec($this->_getResource());
  188. // Remove 100 and 101 responses headers
  189. while (\Zend_Http_Response::extractCode($response) == 100
  190. || \Zend_Http_Response::extractCode($response) == 101
  191. ) {
  192. $response = preg_split('/^\r?$/m', $response, 2);
  193. $response = trim($response[1]);
  194. }
  195. // CUrl will handle chunked data but leave the header.
  196. $response = preg_replace('/Transfer-Encoding:\s+chunked\r?\n/i', '', $response);
  197. return $response;
  198. }
  199. /**
  200. * Close the connection to the server
  201. *
  202. * @return $this
  203. */
  204. public function close()
  205. {
  206. curl_close($this->_getResource());
  207. $this->_resource = null;
  208. return $this;
  209. }
  210. /**
  211. * Returns a cURL handle on success
  212. *
  213. * @return resource
  214. */
  215. protected function _getResource()
  216. {
  217. if ($this->_resource === null) {
  218. $this->_resource = curl_init();
  219. }
  220. return $this->_resource;
  221. }
  222. /**
  223. * Get last error number
  224. *
  225. * @return int
  226. */
  227. public function getErrno()
  228. {
  229. return curl_errno($this->_getResource());
  230. }
  231. /**
  232. * Get string with last error for the current session
  233. *
  234. * @return string
  235. */
  236. public function getError()
  237. {
  238. return curl_error($this->_getResource());
  239. }
  240. /**
  241. * Get information regarding a specific transfer
  242. *
  243. * @param int $opt CURLINFO option
  244. * @return mixed
  245. */
  246. public function getInfo($opt = 0)
  247. {
  248. return curl_getinfo($this->_getResource(), $opt);
  249. }
  250. /**
  251. * Curl_multi_* requests support
  252. *
  253. * @param array $urls
  254. * @param array $options
  255. * @return array
  256. */
  257. public function multiRequest($urls, $options = [])
  258. {
  259. $handles = [];
  260. $result = [];
  261. $multihandle = curl_multi_init();
  262. // add default parameters
  263. foreach ($this->getDefaultConfig() as $defaultOption => $defaultValue) {
  264. if (!isset($options[$defaultOption])) {
  265. $options[$defaultOption] = $defaultValue;
  266. }
  267. }
  268. foreach ($urls as $key => $url) {
  269. $handles[$key] = curl_init();
  270. curl_setopt($handles[$key], CURLOPT_URL, $url);
  271. curl_setopt($handles[$key], CURLOPT_HEADER, 0);
  272. curl_setopt($handles[$key], CURLOPT_RETURNTRANSFER, 1);
  273. if (!empty($options)) {
  274. curl_setopt_array($handles[$key], $options);
  275. }
  276. curl_multi_add_handle($multihandle, $handles[$key]);
  277. }
  278. $process = null;
  279. do {
  280. curl_multi_exec($multihandle, $process);
  281. usleep(100);
  282. } while ($process > 0);
  283. foreach ($handles as $key => $handle) {
  284. $result[$key] = curl_multi_getcontent($handle);
  285. curl_multi_remove_handle($multihandle, $handle);
  286. }
  287. curl_multi_close($multihandle);
  288. return $result;
  289. }
  290. }