|
1
|
|
|
<?php |
|
2
|
|
|
namespace Fwlib\Net; |
|
3
|
|
|
|
|
4
|
|
|
use Fwlib\Util\UtilContainer; |
|
5
|
|
|
|
|
6
|
|
|
/** |
|
7
|
|
|
* Helper class for easy curl usage |
|
8
|
|
|
* |
|
9
|
|
|
* @copyright Copyright 2007-2015 Fwolf |
|
10
|
|
|
* @license http://www.gnu.org/licenses/lgpl.html LGPL-3.0+ |
|
11
|
|
|
*/ |
|
12
|
|
|
class Curl |
|
13
|
|
|
{ |
|
14
|
|
|
/** |
|
15
|
|
|
* File to save cookie |
|
16
|
|
|
* |
|
17
|
|
|
* @var string |
|
18
|
|
|
*/ |
|
19
|
|
|
protected $cookieFile = ''; |
|
20
|
|
|
|
|
21
|
|
|
/** |
|
22
|
|
|
* Debug mode, will log more information, like get/post url |
|
23
|
|
|
* |
|
24
|
|
|
* @var boolean |
|
25
|
|
|
*/ |
|
26
|
|
|
protected $debug = false; |
|
27
|
|
|
|
|
28
|
|
|
/** |
|
29
|
|
|
* cURL handle |
|
30
|
|
|
* |
|
31
|
|
|
* @var resource |
|
32
|
|
|
*/ |
|
33
|
|
|
protected $handle; |
|
34
|
|
|
|
|
35
|
|
|
/** |
|
36
|
|
|
* Result read from web server |
|
37
|
|
|
* |
|
38
|
|
|
* @var string |
|
39
|
|
|
*/ |
|
40
|
|
|
protected $html = ''; |
|
41
|
|
|
|
|
42
|
|
|
/** |
|
43
|
|
|
* File to save log |
|
44
|
|
|
* |
|
45
|
|
|
* Empty for direct print out(default), or set to a valid file to save, or |
|
46
|
|
|
* set to /dev/null to do nothing. |
|
47
|
|
|
* |
|
48
|
|
|
* @var string |
|
49
|
|
|
*/ |
|
50
|
|
|
protected $logFile = null; |
|
51
|
|
|
|
|
52
|
|
|
|
|
53
|
|
|
/** |
|
54
|
|
|
* Destructor |
|
55
|
|
|
*/ |
|
56
|
|
|
public function __destruct() |
|
57
|
|
|
{ |
|
58
|
|
|
curl_close($this->getHandle()); |
|
59
|
|
|
} |
|
60
|
|
|
|
|
61
|
|
|
|
|
62
|
|
|
/** |
|
63
|
|
|
* Http get method |
|
64
|
|
|
* |
|
65
|
|
|
* @param string $url Host address |
|
66
|
|
|
* @param string|array $param Get parameter |
|
67
|
|
|
* @return string |
|
68
|
|
|
*/ |
|
69
|
|
|
public function get($url, $param = null) |
|
70
|
|
|
{ |
|
71
|
|
|
$handle = $this->getHandle(); |
|
72
|
|
|
|
|
73
|
|
|
curl_setopt($handle, CURLOPT_HTTPGET, true); |
|
74
|
|
|
|
|
75
|
|
|
// Remove tailing '?" from url |
|
76
|
|
View Code Duplication |
if ('?' == substr($url, -1, 1)) { |
|
|
|
|
|
|
77
|
|
|
$url = substr($url, 0, strlen($url) - 1); |
|
78
|
|
|
} |
|
79
|
|
|
|
|
80
|
|
|
// Char used between url & param |
|
81
|
|
|
$linker = (false === strpos($url, '?')) ? '?' : '&'; |
|
82
|
|
|
|
|
83
|
|
|
// Parse param, join array and fix linker char with url |
|
84
|
|
|
if (!empty($param)) { |
|
85
|
|
View Code Duplication |
if (is_array($param)) { |
|
|
|
|
|
|
86
|
|
|
$queryString = ''; |
|
87
|
|
|
foreach ($param as $k => $v) { |
|
88
|
|
|
$queryString .= '&' . urlencode($k) . '=' . urlencode($v); |
|
89
|
|
|
} |
|
90
|
|
|
$param = $queryString; |
|
91
|
|
|
} |
|
92
|
|
|
|
|
93
|
|
|
$param{0} = $linker; |
|
94
|
|
|
} |
|
95
|
|
|
|
|
96
|
|
|
curl_setopt($handle, CURLOPT_URL, $url . $param); |
|
97
|
|
|
$this->html = curl_exec($handle); |
|
98
|
|
|
|
|
99
|
|
|
if ($this->debug) { |
|
100
|
|
|
$this->log('Get: ' . $url . $param); |
|
101
|
|
|
} |
|
102
|
|
|
|
|
103
|
|
|
if (0 != curl_errno($handle)) { |
|
104
|
|
|
$this->log(curl_error($handle)); |
|
105
|
|
|
} |
|
106
|
|
|
|
|
107
|
|
|
return $this->html; |
|
108
|
|
|
} |
|
109
|
|
|
|
|
110
|
|
|
|
|
111
|
|
|
/** |
|
112
|
|
|
* Get and initialize curl handle |
|
113
|
|
|
* |
|
114
|
|
|
* @return resource |
|
115
|
|
|
*/ |
|
116
|
|
|
public function getHandle() |
|
117
|
|
|
{ |
|
118
|
|
|
if (is_null($this->handle)) { |
|
119
|
|
|
$this->handle = curl_init(); |
|
120
|
|
|
$this->setDefaultOptions($this->handle); |
|
121
|
|
|
} |
|
122
|
|
|
|
|
123
|
|
|
return $this->handle; |
|
124
|
|
|
} |
|
125
|
|
|
|
|
126
|
|
|
|
|
127
|
|
|
/** |
|
128
|
|
|
* Get server return code of last curl_exec |
|
129
|
|
|
* |
|
130
|
|
|
* 200-ok, 404-missing file, etc |
|
131
|
|
|
* |
|
132
|
|
|
* @return int |
|
133
|
|
|
*/ |
|
134
|
|
|
public function getLastCode() |
|
135
|
|
|
{ |
|
136
|
|
|
$handle = $this->getHandle(); |
|
137
|
|
|
|
|
138
|
|
|
$code = curl_getinfo($handle, CURLINFO_HTTP_CODE); |
|
139
|
|
|
|
|
140
|
|
|
return intval($code); |
|
141
|
|
|
} |
|
142
|
|
|
|
|
143
|
|
|
|
|
144
|
|
|
/** |
|
145
|
|
|
* Get server return content type of last curl_exec |
|
146
|
|
|
* |
|
147
|
|
|
* text/html, image/png, etc |
|
148
|
|
|
* |
|
149
|
|
|
* @return string |
|
150
|
|
|
*/ |
|
151
|
|
|
public function getLastContentType() |
|
152
|
|
|
{ |
|
153
|
|
|
$handle = $this->getHandle(); |
|
154
|
|
|
|
|
155
|
|
|
$type = curl_getinfo($handle, CURLINFO_CONTENT_TYPE); |
|
156
|
|
|
|
|
157
|
|
|
return $type; |
|
158
|
|
|
} |
|
159
|
|
|
|
|
160
|
|
|
|
|
161
|
|
|
/** |
|
162
|
|
|
* Log curl action |
|
163
|
|
|
* |
|
164
|
|
|
* @param string $msg |
|
165
|
|
|
*/ |
|
166
|
|
|
protected function log($msg) |
|
167
|
|
|
{ |
|
168
|
|
|
// Prepend msg with time, append with newline |
|
169
|
|
|
$msg = date('[Y-m-d H:i:s] ') . $msg . PHP_EOL; |
|
170
|
|
|
|
|
171
|
|
|
if (empty($this->logFile)) { |
|
172
|
|
|
// Print |
|
173
|
|
|
UtilContainer::getInstance()->getEnv()->ecl($msg); |
|
174
|
|
|
|
|
175
|
|
|
} elseif (is_writable($this->logFile)) { |
|
176
|
|
|
// Write to log file |
|
177
|
|
|
file_put_contents($this->logFile, $msg, FILE_APPEND); |
|
178
|
|
|
} |
|
179
|
|
|
|
|
180
|
|
|
// Invalid $this->logFile will do nothing. |
|
181
|
|
|
} |
|
182
|
|
|
|
|
183
|
|
|
|
|
184
|
|
|
/** |
|
185
|
|
|
* Match content to variables using preg |
|
186
|
|
|
* |
|
187
|
|
|
* Return value maybe string(for single result) or array(for multiple |
|
188
|
|
|
* result), use carefully and remind which value you use it for. |
|
189
|
|
|
* |
|
190
|
|
|
* Regex should surround wih '/', and mark match target with '()'. |
|
191
|
|
|
* |
|
192
|
|
|
* @param string $preg |
|
193
|
|
|
* @param string $html If omitted, use $this->html |
|
194
|
|
|
* @return string|array |
|
195
|
|
|
*/ |
|
196
|
|
|
public function match($preg, $html = '') |
|
197
|
|
|
{ |
|
198
|
|
|
// Param check |
|
199
|
|
|
if (empty($preg)) { |
|
200
|
|
|
return null; |
|
201
|
|
|
} |
|
202
|
|
|
if (empty($html)) { |
|
203
|
|
|
$html = $this->html; |
|
204
|
|
|
} |
|
205
|
|
|
|
|
206
|
|
|
|
|
207
|
|
|
$matchCount = preg_match_all($preg, $html, $matches, PREG_SET_ORDER); |
|
208
|
|
|
if (0 == $matchCount || false === $matchCount) { |
|
209
|
|
|
// Got none match or Got error |
|
210
|
|
|
$matches = null; |
|
211
|
|
|
|
|
212
|
|
|
} elseif (1 == $matchCount) { |
|
213
|
|
|
// Got 1 match, return as string or array(2 value in 1 match) |
|
214
|
|
|
$matches = $matches[0]; |
|
215
|
|
|
array_shift($matches); |
|
216
|
|
|
if (1 == count($matches)) { |
|
217
|
|
|
$matches = $matches[0]; |
|
218
|
|
|
} |
|
219
|
|
|
|
|
220
|
|
|
} else { |
|
221
|
|
|
// Got more than 1 match return array contains string or sub-array |
|
222
|
|
View Code Duplication |
foreach ($matches as &$row) { |
|
|
|
|
|
|
223
|
|
|
array_shift($row); |
|
224
|
|
|
if (1 == count($row)) { |
|
225
|
|
|
$row = $row[0]; |
|
226
|
|
|
} |
|
227
|
|
|
} |
|
228
|
|
|
} |
|
229
|
|
|
|
|
230
|
|
|
return $matches; |
|
231
|
|
|
} |
|
232
|
|
|
|
|
233
|
|
|
|
|
234
|
|
|
/** |
|
235
|
|
|
* Http post method |
|
236
|
|
|
* |
|
237
|
|
|
* @param string $url Host address |
|
238
|
|
|
* @param string|array $params Post parameter, prefer array |
|
239
|
|
|
* @return string |
|
240
|
|
|
*/ |
|
241
|
|
|
public function post($url, $params = []) |
|
242
|
|
|
{ |
|
243
|
|
|
$handle = $this->getHandle(); |
|
244
|
|
|
|
|
245
|
|
|
curl_setopt($handle, CURLOPT_POST, true); |
|
246
|
|
|
|
|
247
|
|
|
curl_setopt($handle, CURLOPT_POSTFIELDS, $params); |
|
248
|
|
|
curl_setopt($handle, CURLOPT_URL, $url); |
|
249
|
|
|
$this->html = curl_exec($handle); |
|
250
|
|
|
|
|
251
|
|
|
if (is_array($params)) { |
|
252
|
|
|
$params = implode('&', array_keys($params)); |
|
253
|
|
|
} |
|
254
|
|
|
$linker = (false === strpos($url, '?')) ? '?' : '&'; |
|
255
|
|
|
$params = rtrim($linker . ltrim($params, '&'), '?&'); |
|
256
|
|
|
|
|
257
|
|
|
if ($this->debug) { |
|
258
|
|
|
$this->log('Post: ' . $url . $params); |
|
259
|
|
|
} |
|
260
|
|
|
|
|
261
|
|
|
if (0 != curl_errno($handle)) { |
|
262
|
|
|
$this->log(curl_error($handle), 4); |
|
|
|
|
|
|
263
|
|
|
} |
|
264
|
|
|
|
|
265
|
|
|
return $this->html; |
|
266
|
|
|
} |
|
267
|
|
|
|
|
268
|
|
|
|
|
269
|
|
|
/** |
|
270
|
|
|
* Renew handle |
|
271
|
|
|
* |
|
272
|
|
|
* This is useful when cookie file is used, and want to reload cookies, |
|
273
|
|
|
* eg: after login, reload cookie then they will be used in next operation. |
|
274
|
|
|
* |
|
275
|
|
|
* @return static |
|
276
|
|
|
*/ |
|
277
|
|
|
public function renewHandle() |
|
278
|
|
|
{ |
|
279
|
|
|
if (!is_null($this->handle)) { |
|
280
|
|
|
curl_close($this->handle); |
|
281
|
|
|
$this->handle = null; |
|
282
|
|
|
|
|
283
|
|
|
$this->getHandle(); |
|
284
|
|
|
|
|
285
|
|
|
// Re-assign options |
|
286
|
|
|
if (!is_null($this->cookieFile)) { |
|
287
|
|
|
$this->setCookieFile($this->cookieFile); |
|
288
|
|
|
} |
|
289
|
|
|
|
|
290
|
|
|
// More option to set ? |
|
291
|
|
|
} |
|
292
|
|
|
|
|
293
|
|
|
return $this; |
|
294
|
|
|
} |
|
295
|
|
|
|
|
296
|
|
|
|
|
297
|
|
|
/** |
|
298
|
|
|
* Set cookie option |
|
299
|
|
|
* |
|
300
|
|
|
* If filename is not given, use default, |
|
301
|
|
|
* If file is given, use & set it as default. |
|
302
|
|
|
* |
|
303
|
|
|
* @param string $cookieFile |
|
304
|
|
|
*/ |
|
305
|
|
|
public function setCookieFile($cookieFile = '') |
|
306
|
|
|
{ |
|
307
|
|
|
$handle = $this->getHandle(); |
|
308
|
|
|
|
|
309
|
|
|
$this->cookieFile = $cookieFile; |
|
310
|
|
|
|
|
311
|
|
|
if (!empty($cookieFile) && (is_writable($cookieFile))) { |
|
312
|
|
|
curl_setopt($handle, CURLOPT_COOKIEFILE, $cookieFile); |
|
313
|
|
|
curl_setopt($handle, CURLOPT_COOKIEJAR, $cookieFile); |
|
314
|
|
|
} |
|
315
|
|
|
} |
|
316
|
|
|
|
|
317
|
|
|
|
|
318
|
|
|
/** |
|
319
|
|
|
* Setter of $debug |
|
320
|
|
|
* |
|
321
|
|
|
* @param boolean $debug |
|
322
|
|
|
* @return static |
|
323
|
|
|
*/ |
|
324
|
|
|
public function setDebug($debug) |
|
325
|
|
|
{ |
|
326
|
|
|
$this->debug = $debug; |
|
327
|
|
|
|
|
328
|
|
|
return $this; |
|
329
|
|
|
} |
|
330
|
|
|
|
|
331
|
|
|
|
|
332
|
|
|
/** |
|
333
|
|
|
* Set default options |
|
334
|
|
|
* |
|
335
|
|
|
* @param resource $handle |
|
336
|
|
|
* @return static |
|
337
|
|
|
*/ |
|
338
|
|
|
protected function setDefaultOptions($handle) |
|
339
|
|
|
{ |
|
340
|
|
|
curl_setopt($handle, CURLOPT_AUTOREFERER, true); |
|
341
|
|
|
// If got http error, report. |
|
342
|
|
|
curl_setopt($handle, CURLOPT_FAILONERROR, true); |
|
343
|
|
|
|
|
344
|
|
|
// CURLOPT_FOLLOWLOCATION cannot set when open_basedir is set. |
|
345
|
|
|
// Also safe_mode, which are DEPRECATED in 5.3.0 and REMOVED in 5.4.0. |
|
346
|
|
|
if ('' == ini_get('open_basedir')) { |
|
347
|
|
|
curl_setopt($handle, CURLOPT_FOLLOWLOCATION, true); |
|
348
|
|
|
} |
|
349
|
|
|
|
|
350
|
|
|
// Return result instead of display it. |
|
351
|
|
|
curl_setopt($handle, CURLOPT_RETURNTRANSFER, true); |
|
352
|
|
|
curl_setopt($handle, CURLOPT_CONNECTTIMEOUT, 300); |
|
353
|
|
|
curl_setopt($handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); |
|
354
|
|
|
curl_setopt($handle, CURLOPT_MAXREDIRS, 10); |
|
355
|
|
|
curl_setopt($handle, CURLOPT_TIMEOUT, 300); |
|
356
|
|
|
|
|
357
|
|
|
// Accept all supported encoding(identity, deflate, gzip) |
|
358
|
|
|
// See CURLOPT_ACCEPT_ENCODING in libcurl |
|
359
|
|
|
// Set this to get uncompressed html content |
|
360
|
|
|
curl_setopt($handle, CURLOPT_ENCODING, ''); |
|
361
|
|
|
|
|
362
|
|
|
// Cipher list depends on curl lib use OpenSSL or NSS module |
|
363
|
|
|
// @see https://github.com/PayU/openpayu_php/issues/38 |
|
364
|
|
|
// Wrong cipher will got error: Unknown cipher in list: ... |
|
365
|
|
|
$cipher = ('NSS' == substr(curl_version()['ssl_version'], 0, 3)) |
|
366
|
|
|
? 'rsa_aes_128_sha' |
|
367
|
|
|
: 'TLSv1'; |
|
368
|
|
|
curl_setopt($handle, CURLOPT_SSL_CIPHER_LIST, $cipher); |
|
369
|
|
|
|
|
370
|
|
|
return $this; |
|
371
|
|
|
} |
|
372
|
|
|
|
|
373
|
|
|
|
|
374
|
|
|
/** |
|
375
|
|
|
* Setter of $logFile |
|
376
|
|
|
* |
|
377
|
|
|
* @param string $logFile |
|
378
|
|
|
* @return static |
|
379
|
|
|
*/ |
|
380
|
|
|
public function setLogFile($logFile) |
|
381
|
|
|
{ |
|
382
|
|
|
$this->logFile = $logFile; |
|
383
|
|
|
|
|
384
|
|
|
return $this; |
|
385
|
|
|
} |
|
386
|
|
|
|
|
387
|
|
|
|
|
388
|
|
|
/** |
|
389
|
|
|
* Set proxy option |
|
390
|
|
|
* |
|
391
|
|
|
* @param int $type 0-no proxy, 1-http, 2-socks5 |
|
392
|
|
|
* @param string $host |
|
393
|
|
|
* @param int $port |
|
394
|
|
|
* @param string $auth [username]:[password] |
|
395
|
|
|
*/ |
|
396
|
|
|
public function setProxy($type, $host, $port, $auth = '') |
|
397
|
|
|
{ |
|
398
|
|
|
$handle = $this->getHandle(); |
|
399
|
|
|
|
|
400
|
|
|
if (0 == $type) { |
|
401
|
|
|
// Some server refuse http proxy tunnel, it's useless settings. |
|
402
|
|
|
//curl_setopt($handle, CURLOPT_HTTPPROXYTUNNEL, false); |
|
403
|
|
|
curl_setopt($handle, CURLOPT_PROXY, null); |
|
404
|
|
|
|
|
405
|
|
|
} else { |
|
406
|
|
|
//curl_setopt($handle, CURLOPT_HTTPPROXYTUNNEL, true); |
|
407
|
|
|
|
|
408
|
|
|
curl_setopt($handle, CURLOPT_PROXY, $host); |
|
409
|
|
|
|
|
410
|
|
|
curl_setopt( |
|
411
|
|
|
$handle, |
|
412
|
|
|
CURLOPT_PROXYTYPE, |
|
413
|
|
|
(1 == $type) ? CURLPROXY_HTTP : CURLPROXY_SOCKS5 |
|
414
|
|
|
); |
|
415
|
|
|
|
|
416
|
|
|
curl_setopt($handle, CURLOPT_PROXYPORT, $port); |
|
417
|
|
|
if (!empty($auth)) { |
|
418
|
|
|
curl_setopt($handle, CURLOPT_PROXYUSERPWD, $auth); |
|
419
|
|
|
} |
|
420
|
|
|
} |
|
421
|
|
|
} |
|
422
|
|
|
|
|
423
|
|
|
|
|
424
|
|
|
/** |
|
425
|
|
|
* Set http referrer url |
|
426
|
|
|
* |
|
427
|
|
|
* @param string $url |
|
428
|
|
|
*/ |
|
429
|
|
|
public function setReferrer($url = null) |
|
430
|
|
|
{ |
|
431
|
|
|
$handle = $this->getHandle(); |
|
432
|
|
|
|
|
433
|
|
|
if (!empty($url)) { |
|
434
|
|
|
curl_setopt($handle, CURLOPT_REFERER, $url); |
|
435
|
|
|
} |
|
436
|
|
|
} |
|
437
|
|
|
|
|
438
|
|
|
|
|
439
|
|
|
/** |
|
440
|
|
|
* Enable or disable ssl verify function |
|
441
|
|
|
* |
|
442
|
|
|
* Ssl verify is enabled by curl in default. |
|
443
|
|
|
* |
|
444
|
|
|
* @param boolean $enable |
|
445
|
|
|
*/ |
|
446
|
|
|
public function setSslVerify($enable = true) |
|
447
|
|
|
{ |
|
448
|
|
|
$handle = $this->getHandle(); |
|
449
|
|
|
|
|
450
|
|
|
curl_setopt($handle, CURLOPT_SSL_VERIFYPEER, $enable); |
|
451
|
|
|
curl_setopt($handle, CURLOPT_SSL_VERIFYHOST, $enable); |
|
452
|
|
|
} |
|
453
|
|
|
|
|
454
|
|
|
|
|
455
|
|
|
/** |
|
456
|
|
|
* Set browser agent option |
|
457
|
|
|
* |
|
458
|
|
|
* @param string $userAgent |
|
459
|
|
|
*/ |
|
460
|
|
|
public function setUserAgent($userAgent = 'curl') |
|
461
|
|
|
{ |
|
462
|
|
|
$handle = $this->getHandle(); |
|
463
|
|
|
|
|
464
|
|
|
curl_setopt($handle, CURLOPT_USERAGENT, $userAgent); |
|
465
|
|
|
} |
|
466
|
|
|
} |
|
467
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.