1
|
|
|
<?php /** MicroCurl */ |
2
|
|
|
|
3
|
|
|
namespace Micro\Web; |
4
|
|
|
|
5
|
|
|
use Micro\Base\Exception; |
6
|
|
|
|
7
|
|
|
/** |
8
|
|
|
* Class cURL |
9
|
|
|
* |
10
|
|
|
* @author Hassan Amouhzi <http://anezi.net> |
11
|
|
|
* @link https://github.com/php-mod/curl |
12
|
|
|
* @copyright Copyright © 2013 php-mod |
13
|
|
|
* @license https://github.com/php-mod/curl/blob/master/LICENSE |
14
|
|
|
* @package Micro |
15
|
|
|
* @subpackage Web |
16
|
|
|
* @version 1.1.5 |
17
|
|
|
* @since 1.0 |
18
|
|
|
*/ |
19
|
|
|
class Curl |
20
|
|
|
{ |
21
|
|
|
/** @var integer AUTH_BASIC authentication basic */ |
22
|
|
|
const AUTH_BASIC = CURLAUTH_BASIC; |
23
|
|
|
/** @var integer AUTH_DIGEST authentication digest */ |
24
|
|
|
const AUTH_DIGEST = CURLAUTH_DIGEST; |
25
|
|
|
/** @var integer AUTH_GSSNEGOTIATE authentication gss negotiate */ |
26
|
|
|
const AUTH_GSSNEGOTIATE = CURLAUTH_GSSNEGOTIATE; |
27
|
|
|
/** @var integer AUTH_NTLM authentication NT LM */ |
28
|
|
|
const AUTH_NTLM = CURLAUTH_NTLM; |
29
|
|
|
/** @var integer AUTH_ANY authentication any */ |
30
|
|
|
const AUTH_ANY = CURLAUTH_ANY; |
31
|
|
|
/** @var integer AUTH_ANYSAFE authentication any safe */ |
32
|
|
|
const AUTH_ANYSAFE = CURLAUTH_ANYSAFE; |
33
|
|
|
|
34
|
|
|
/** @var string USER_AGENT user agent identity */ |
35
|
|
|
const USER_AGENT = 'My User Agent'; |
36
|
|
|
/** @var resource $curl cURL resource */ |
37
|
|
|
public $curl; |
38
|
|
|
/** @var bool $error is error */ |
39
|
|
|
public $error = false; |
40
|
|
|
/** @var int $error_code error code */ |
41
|
|
|
public $error_code = 0; |
42
|
|
|
/** @var null|string $error_message error message */ |
43
|
|
|
public $error_message; |
44
|
|
|
/** @var bool $curl_error is cURL error */ |
45
|
|
|
public $curl_error = false; |
46
|
|
|
/** @var int $curl_error_code cURL error code */ |
47
|
|
|
public $curl_error_code = 0; |
48
|
|
|
/** @var null|string $curl_error_message cURL error message */ |
49
|
|
|
public $curl_error_message; |
50
|
|
|
/** @var bool $http_error is HTTP error */ |
51
|
|
|
public $http_error = false; |
52
|
|
|
/** @var int $http_status_code HTTP status code */ |
53
|
|
|
public $http_status_code = 0; |
54
|
|
|
/** @var null $http_error_message HTTP error message */ |
55
|
|
|
public $http_error_message; |
56
|
|
|
/** @var null $request_headers request headers */ |
57
|
|
|
public $request_headers; |
58
|
|
|
/** @var null $response_headers response headers */ |
59
|
|
|
public $response_headers; |
60
|
|
|
/** @var null $response response */ |
61
|
|
|
public $response; |
62
|
|
|
/** @var array $_cookies cookies for request */ |
63
|
|
|
private $_cookies = []; |
64
|
|
|
/** @var array $_headers headers for request */ |
65
|
|
|
private $_headers = []; |
66
|
|
|
|
67
|
|
|
/** |
68
|
|
|
* Construct |
69
|
|
|
* |
70
|
|
|
* @access public |
71
|
|
|
* @result void |
72
|
|
|
* @throws Exception |
73
|
|
|
*/ |
74
|
|
|
public function __construct() |
75
|
|
|
{ |
76
|
|
|
|
77
|
|
|
if (!extension_loaded('curl')) { |
78
|
|
|
throw new Exception('cURL library is not loaded'); |
79
|
|
|
} |
80
|
|
|
|
81
|
|
|
$this->curl = curl_init(); |
82
|
|
|
$this->setUserAgent(self::USER_AGENT); |
83
|
|
|
$this->setopt(CURLINFO_HEADER_OUT, true); |
84
|
|
|
$this->setopt(CURLOPT_HEADER, true); |
85
|
|
|
$this->setopt(CURLOPT_RETURNTRANSFER, true); |
86
|
|
|
} |
87
|
|
|
|
88
|
|
|
/** |
89
|
|
|
* Set user agent |
90
|
|
|
* |
91
|
|
|
* @access public |
92
|
|
|
* |
93
|
|
|
* @param string $user_agent user agent name |
94
|
|
|
* |
95
|
|
|
* @return void |
96
|
|
|
*/ |
97
|
|
|
public function setUserAgent($user_agent) |
98
|
|
|
{ |
99
|
|
|
$this->setopt(CURLOPT_USERAGENT, $user_agent); |
100
|
|
|
} |
101
|
|
|
|
102
|
|
|
/** |
103
|
|
|
* Set option |
104
|
|
|
* |
105
|
|
|
* @access public |
106
|
|
|
* |
107
|
|
|
* @param mixed $option |
108
|
|
|
* @param mixed $value |
109
|
|
|
* |
110
|
|
|
* @return bool |
111
|
|
|
*/ |
112
|
|
|
public function setopt($option, $value) |
113
|
|
|
{ |
114
|
|
|
return curl_setopt($this->curl, $option, $value); |
115
|
|
|
} |
116
|
|
|
|
117
|
|
|
/** |
118
|
|
|
* Get URL |
119
|
|
|
* |
120
|
|
|
* @access public |
121
|
|
|
* |
122
|
|
|
* @param string $url URL |
123
|
|
|
* @param array $data data |
124
|
|
|
* |
125
|
|
|
* @return void |
126
|
|
|
*/ |
127
|
|
|
public function get($url, array $data = []) |
128
|
|
|
{ |
129
|
|
|
if (count($data) > 0) { |
130
|
|
|
$this->setopt(CURLOPT_URL, $url . '?' . http_build_query($data)); |
131
|
|
|
} else { |
132
|
|
|
$this->setopt(CURLOPT_URL, $url); |
133
|
|
|
} |
134
|
|
|
$this->setopt(CURLOPT_HTTPGET, true); |
135
|
|
|
$this->_exec(); |
136
|
|
|
} |
137
|
|
|
|
138
|
|
|
/** |
139
|
|
|
* Execute |
140
|
|
|
* |
141
|
|
|
* @access public |
142
|
|
|
* @return int|mixed |
143
|
|
|
*/ |
144
|
|
|
public function _exec() |
145
|
|
|
{ |
146
|
|
|
$this->response = curl_exec($this->curl); |
147
|
|
|
$this->curl_error_code = curl_errno($this->curl); |
148
|
|
|
$this->curl_error_message = curl_error($this->curl); |
149
|
|
|
$this->curl_error = !($this->curl_error_code === 0); |
150
|
|
|
$this->http_status_code = curl_getinfo($this->curl, CURLINFO_HTTP_CODE); |
151
|
|
|
$this->http_error = in_array(floor($this->http_status_code / 100), array(4, 5), true); |
152
|
|
|
$this->error = $this->curl_error || $this->http_error; |
153
|
|
|
if ($this->error) { |
154
|
|
|
$this->error_code = $this->curl_error ? $this->curl_error_code : $this->http_status_code; |
|
|
|
|
155
|
|
|
} |
156
|
|
|
|
157
|
|
|
$this->request_headers = preg_split('/\r\n/', curl_getinfo($this->curl, CURLINFO_HEADER_OUT), null, |
|
|
|
|
158
|
|
|
PREG_SPLIT_NO_EMPTY); |
159
|
|
|
$this->response_headers = ''; |
|
|
|
|
160
|
|
|
if (!(strpos($this->response, "\r\n\r\n") === false)) { |
161
|
|
|
list($response_header, $this->response) = explode("\r\n\r\n", $this->response, 2); |
162
|
|
|
if ($response_header === 'HTTP/1.1 100 Continue') { |
163
|
|
|
list($response_header, $this->response) = explode("\r\n\r\n", $this->response, 2); |
164
|
|
|
} |
165
|
|
|
$this->response_headers = preg_split('/\r\n/', $response_header, null, PREG_SPLIT_NO_EMPTY); |
|
|
|
|
166
|
|
|
} |
167
|
|
|
|
168
|
|
|
$this->http_error_message = ''; |
|
|
|
|
169
|
|
|
if ($this->error) { |
170
|
|
|
$this->http_error_message = !empty($this->response_headers[0]) ? $this->response_headers[0] : ''; |
171
|
|
|
} |
172
|
|
|
|
173
|
|
|
$this->error_message = $this->curl_error ? $this->curl_error_message : $this->http_error_message; |
174
|
|
|
|
175
|
|
|
return $this->error_code; |
176
|
|
|
} |
177
|
|
|
|
178
|
|
|
/** |
179
|
|
|
* Post URL |
180
|
|
|
* |
181
|
|
|
* @access public |
182
|
|
|
* |
183
|
|
|
* @param string $url URL |
184
|
|
|
* @param array|mixed $data data |
185
|
|
|
* |
186
|
|
|
* @return void |
187
|
|
|
*/ |
188
|
|
|
public function post($url, array $data = []) |
189
|
|
|
{ |
190
|
|
|
$this->setopt(CURLOPT_URL, $url); |
191
|
|
|
$this->setopt(CURLOPT_POST, true); |
192
|
|
|
$data = http_build_query($data); |
193
|
|
|
$this->setopt(CURLOPT_POSTFIELDS, $data); |
194
|
|
|
$this->_exec(); |
195
|
|
|
} |
196
|
|
|
|
197
|
|
|
/** |
198
|
|
|
* Put URL |
199
|
|
|
* |
200
|
|
|
* @access public |
201
|
|
|
* |
202
|
|
|
* @param string $url URL |
203
|
|
|
* @param array $data data |
204
|
|
|
* |
205
|
|
|
* @return void |
206
|
|
|
*/ |
207
|
|
|
public function put($url, array $data = []) |
208
|
|
|
{ |
209
|
|
|
$this->setopt(CURLOPT_URL, $url . '?' . http_build_query($data)); |
210
|
|
|
$this->setopt(CURLOPT_CUSTOMREQUEST, 'PUT'); |
211
|
|
|
$this->_exec(); |
212
|
|
|
} |
213
|
|
|
|
214
|
|
|
/** |
215
|
|
|
* Patch URL |
216
|
|
|
* |
217
|
|
|
* @access public |
218
|
|
|
* |
219
|
|
|
* @param string $url URL |
220
|
|
|
* @param array $data data |
221
|
|
|
* |
222
|
|
|
* @return void |
223
|
|
|
*/ |
224
|
|
|
public function patch($url, array $data = []) |
225
|
|
|
{ |
226
|
|
|
$this->setopt(CURLOPT_URL, $url); |
227
|
|
|
$this->setopt(CURLOPT_CUSTOMREQUEST, 'PATCH'); |
228
|
|
|
$this->setopt(CURLOPT_POSTFIELDS, $data); |
229
|
|
|
$this->_exec(); |
230
|
|
|
} |
231
|
|
|
|
232
|
|
|
/** |
233
|
|
|
* Delete URL |
234
|
|
|
* |
235
|
|
|
* @access public |
236
|
|
|
* |
237
|
|
|
* @param string $url URL |
238
|
|
|
* @param array $data data |
239
|
|
|
* |
240
|
|
|
* @return void |
241
|
|
|
*/ |
242
|
|
|
public function delete($url, array $data = []) |
243
|
|
|
{ |
244
|
|
|
$this->setopt(CURLOPT_URL, $url . '?' . http_build_query($data)); |
245
|
|
|
$this->setopt(CURLOPT_CUSTOMREQUEST, 'DELETE'); |
246
|
|
|
$this->_exec(); |
247
|
|
|
} |
248
|
|
|
|
249
|
|
|
/** |
250
|
|
|
* Set basic authentication |
251
|
|
|
* |
252
|
|
|
* @access public |
253
|
|
|
* |
254
|
|
|
* @param string $username username |
255
|
|
|
* @param string $password password |
256
|
|
|
* |
257
|
|
|
* @return void |
258
|
|
|
*/ |
259
|
|
|
public function setBasicAuthentication($username, $password) |
260
|
|
|
{ |
261
|
|
|
$this->setHttpAuth(self::AUTH_BASIC); |
262
|
|
|
$this->setopt(CURLOPT_USERPWD, $username . ':' . $password); |
263
|
|
|
} |
264
|
|
|
|
265
|
|
|
/** |
266
|
|
|
* Set HTTP auth |
267
|
|
|
* |
268
|
|
|
* @access public |
269
|
|
|
* |
270
|
|
|
* @param mixed $httpauth http auth type |
271
|
|
|
* |
272
|
|
|
* @return void |
273
|
|
|
*/ |
274
|
|
|
protected function setHttpAuth($httpauth) |
275
|
|
|
{ |
276
|
|
|
$this->setopt(CURLOPT_HTTPAUTH, $httpauth); |
277
|
|
|
} |
278
|
|
|
|
279
|
|
|
/** |
280
|
|
|
* Set header |
281
|
|
|
* |
282
|
|
|
* @access public |
283
|
|
|
* |
284
|
|
|
* @param string $key key |
285
|
|
|
* @param string $value value |
286
|
|
|
* |
287
|
|
|
* @return void |
288
|
|
|
*/ |
289
|
|
|
public function setHeader($key, $value) |
290
|
|
|
{ |
291
|
|
|
$this->_headers[$key] = $key . ': ' . $value; |
292
|
|
|
$this->setopt(CURLOPT_HTTPHEADER, array_values($this->_headers)); |
293
|
|
|
} |
294
|
|
|
|
295
|
|
|
/** |
296
|
|
|
* Set referrer |
297
|
|
|
* |
298
|
|
|
* @access public |
299
|
|
|
* |
300
|
|
|
* @param string $referrer URL referrer |
301
|
|
|
* |
302
|
|
|
* @return void |
303
|
|
|
*/ |
304
|
|
|
public function setReferrer($referrer) |
305
|
|
|
{ |
306
|
|
|
$this->setopt(CURLOPT_REFERER, $referrer); |
307
|
|
|
} |
308
|
|
|
|
309
|
|
|
/** |
310
|
|
|
* Set cookie |
311
|
|
|
* |
312
|
|
|
* @access public |
313
|
|
|
* |
314
|
|
|
* @param string $key key |
315
|
|
|
* @param string $value value |
316
|
|
|
* |
317
|
|
|
* @return void |
318
|
|
|
*/ |
319
|
|
|
public function setCookie($key, $value) |
320
|
|
|
{ |
321
|
|
|
$this->_cookies[$key] = $value; |
322
|
|
|
$this->setopt(CURLOPT_COOKIE, http_build_query($this->_cookies, '', '; ')); |
323
|
|
|
} |
324
|
|
|
|
325
|
|
|
/** |
326
|
|
|
* Verbose |
327
|
|
|
* |
328
|
|
|
* @access public |
329
|
|
|
* |
330
|
|
|
* @param bool $on on |
331
|
|
|
* |
332
|
|
|
* @return void |
333
|
|
|
*/ |
334
|
|
|
public function verbose($on = true) |
335
|
|
|
{ |
336
|
|
|
$this->setopt(CURLOPT_VERBOSE, $on); |
337
|
|
|
} |
338
|
|
|
|
339
|
|
|
/** |
340
|
|
|
* Destructor |
341
|
|
|
* |
342
|
|
|
* @access public |
343
|
|
|
* @result void |
344
|
|
|
*/ |
345
|
|
|
public function __destruct() |
346
|
|
|
{ |
347
|
|
|
$this->close(); |
348
|
|
|
} |
349
|
|
|
|
350
|
|
|
/** |
351
|
|
|
* Close |
352
|
|
|
* |
353
|
|
|
* @access public |
354
|
|
|
* @return void |
355
|
|
|
*/ |
356
|
|
|
public function close() |
357
|
|
|
{ |
358
|
|
|
if (is_resource($this->curl)) { |
359
|
|
|
curl_close($this->curl); |
360
|
|
|
} |
361
|
|
|
} |
362
|
|
|
} |
363
|
|
|
|
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountId
that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theid
property of an instance of theAccount
class. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.