1
|
|
|
<?php namespace Comodojo\Httprequest; |
2
|
|
|
|
3
|
|
|
use \Comodojo\Exception\HttpException; |
4
|
|
|
use \League\Url\Url; |
5
|
|
|
|
6
|
|
|
/** |
7
|
|
|
* HTTP requests library |
8
|
|
|
* |
9
|
|
|
* @package Comodojo Spare Parts |
10
|
|
|
* @author Marco Giovinazzi <[email protected]> |
11
|
|
|
* @license MIT |
12
|
|
|
* |
13
|
|
|
* LICENSE: |
14
|
|
|
* |
15
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
16
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
17
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
18
|
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
19
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
20
|
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
21
|
|
|
* THE SOFTWARE. |
22
|
|
|
*/ |
23
|
|
|
|
24
|
|
|
class Httprequest { |
25
|
|
|
|
26
|
|
|
/** |
27
|
|
|
* Remote host address (complete url) |
28
|
|
|
* |
29
|
|
|
* @var string |
30
|
|
|
*/ |
31
|
|
|
private $address = null; |
32
|
|
|
|
33
|
|
|
/** |
34
|
|
|
* Remote host port |
35
|
|
|
* |
36
|
|
|
* @var integer |
37
|
|
|
*/ |
38
|
|
|
private $port = 80; |
39
|
|
|
|
40
|
|
|
/** |
41
|
|
|
* Conversation method (GET or POST) |
42
|
|
|
* |
43
|
|
|
* @var string |
44
|
|
|
*/ |
45
|
|
|
private $method = 'GET'; |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* Timeout for request, in seconds. |
49
|
|
|
* |
50
|
|
|
* @var integer |
51
|
|
|
*/ |
52
|
|
|
private $timeout = 30; |
53
|
|
|
|
54
|
|
|
/** |
55
|
|
|
* HTTP Version (1.0/1.1) |
56
|
|
|
* |
57
|
|
|
* @var string |
58
|
|
|
*/ |
59
|
|
|
private $httpVersion = "1.0"; |
60
|
|
|
|
61
|
|
|
/** |
62
|
|
|
* Auth method to use. It currently support only: |
63
|
|
|
* - BASIC |
64
|
|
|
* - NTLM (only if CURL is available) |
65
|
|
|
* |
66
|
|
|
* @var string |
67
|
|
|
*/ |
68
|
|
|
private $authenticationMethod = null; |
69
|
|
|
|
70
|
|
|
/** |
71
|
|
|
* Remote host auth username |
72
|
|
|
* |
73
|
|
|
* @var string |
74
|
|
|
*/ |
75
|
|
|
private $user = null; |
76
|
|
|
|
77
|
|
|
/** |
78
|
|
|
* Remote host auth password |
79
|
|
|
* |
80
|
|
|
* @var string |
81
|
|
|
*/ |
82
|
|
|
private $pass = null; |
83
|
|
|
|
84
|
|
|
/** |
85
|
|
|
* Request user agent |
86
|
|
|
* |
87
|
|
|
* @var string |
88
|
|
|
*/ |
89
|
|
|
private $userAgent = 'Comodojo-Httprequest'; |
90
|
|
|
|
91
|
|
|
/** |
92
|
|
|
* Content type |
93
|
|
|
* |
94
|
|
|
* @var string |
95
|
|
|
*/ |
96
|
|
|
private $contentType = 'application/x-www-form-urlencoded'; |
97
|
|
|
|
98
|
|
|
/** |
99
|
|
|
* array of headers to send |
100
|
|
|
* |
101
|
|
|
* @var array |
102
|
|
|
*/ |
103
|
|
|
private $headers = array( |
104
|
|
|
'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', |
105
|
|
|
'Accept-Language' => 'en-us,en;q=0.5', |
106
|
|
|
'Accept-Encoding' => 'gzip,deflate', |
107
|
|
|
'Accept-Charset' => 'UTF-8;q=0.7,*;q=0.7' |
108
|
|
|
); |
109
|
|
|
|
110
|
|
|
/** |
111
|
|
|
* Should we use a proxy? |
112
|
|
|
* |
113
|
|
|
* @var string |
114
|
|
|
*/ |
115
|
|
|
private $proxy = null; |
116
|
|
|
|
117
|
|
|
private $proxy_auth = null; |
118
|
|
|
|
119
|
|
|
/** |
120
|
|
|
* Allowed HTTP methods |
121
|
|
|
* |
122
|
|
|
* @var array |
123
|
|
|
*/ |
124
|
|
|
private $supported_auth_methods = array("BASIC", "DIGEST", "SPNEGO", "NTLM"); |
125
|
|
|
|
126
|
|
|
/** |
127
|
|
|
* Allowed HTTP authentication |
128
|
|
|
* |
129
|
|
|
* @var array |
130
|
|
|
*/ |
131
|
|
|
private $supported_http_methods = array("GET", "POST", "PUT", "DELETE"); |
132
|
|
|
|
133
|
|
|
/** |
134
|
|
|
* Are we using curl? |
135
|
|
|
*/ |
136
|
|
|
private $curl = true; |
137
|
|
|
|
138
|
|
|
/** |
139
|
|
|
* Received headers |
140
|
|
|
* |
141
|
|
|
* @var array |
142
|
|
|
*/ |
143
|
|
|
private $receivedHeaders = array(); |
144
|
|
|
|
145
|
|
|
/** |
146
|
|
|
* Received http status code |
147
|
|
|
* |
148
|
|
|
* @var int |
149
|
|
|
*/ |
150
|
|
|
private $receivedHttpStatus = null; |
151
|
|
|
|
152
|
|
|
/** |
153
|
|
|
* Transfer channel |
154
|
|
|
* |
155
|
|
|
* @var resource |
156
|
|
|
*/ |
157
|
|
|
private $ch = false; |
158
|
|
|
|
159
|
|
|
private $stream_get_data = null; |
160
|
|
|
|
161
|
|
|
/** |
162
|
|
|
* Ignore Errors (stream only) |
163
|
|
|
* |
164
|
|
|
* @var boolean |
165
|
|
|
*/ |
166
|
|
|
private $ignore_errors = false; |
167
|
|
|
|
168
|
|
|
/** |
169
|
|
|
* Class constructor |
170
|
|
|
* |
171
|
|
|
* @param string $address Remote host address |
172
|
|
|
* @param bool $curl Use curl (true) or stream (false) |
173
|
|
|
* |
174
|
|
|
* @throws \Comodojo\Exception\HttpException |
175
|
|
|
*/ |
176
|
84 |
|
final public function __construct($address = false, $curl = true) { |
177
|
|
|
|
178
|
84 |
|
if ( !empty($address) ) { |
179
|
|
|
|
180
|
|
|
try { |
181
|
|
|
|
182
|
|
|
$this->setHost($address); |
183
|
|
|
|
184
|
|
|
} catch (HttpException $he) { |
185
|
|
|
|
186
|
|
|
throw $he; |
187
|
|
|
|
188
|
|
|
} |
189
|
|
|
|
190
|
|
|
} |
191
|
|
|
|
192
|
84 |
|
$this->setCurl($curl); |
193
|
|
|
|
194
|
84 |
|
} |
195
|
|
|
|
196
|
|
|
/** |
197
|
|
|
* Class destructor |
198
|
|
|
* |
199
|
|
|
*/ |
200
|
6 |
|
final public function __destruct() { |
201
|
|
|
|
202
|
6 |
|
if ( $this->ch !== false ) $this->close_transport(); |
203
|
|
|
|
204
|
6 |
|
} |
205
|
|
|
|
206
|
|
|
/** |
207
|
|
|
* Set remote host address |
208
|
|
|
* |
209
|
|
|
* @param string $address Remote host address |
210
|
|
|
* |
211
|
|
|
* @return \Comodojo\Httprequest\Httprequest |
212
|
|
|
* |
213
|
|
|
* @throws \Comodojo\Exception\HttpException |
214
|
|
|
*/ |
215
|
84 |
|
final public function setHost($address) { |
216
|
|
|
|
217
|
84 |
|
$url = filter_var($address, FILTER_VALIDATE_URL); |
218
|
|
|
|
219
|
84 |
|
if ( $url === false ) throw new HttpException("Invalid remote address"); |
220
|
|
|
|
221
|
81 |
|
$this->address = $address; |
222
|
|
|
|
223
|
81 |
|
return $this; |
224
|
|
|
|
225
|
3 |
|
} |
226
|
|
|
|
227
|
|
|
/** |
228
|
|
|
* Force lib to use curl (default if available) or stream |
229
|
|
|
* |
230
|
|
|
* @param bool $mode Use curl (true) or stream (false) |
231
|
|
|
* |
232
|
|
|
* @return \Comodojo\Httprequest\Httprequest |
233
|
|
|
*/ |
234
|
84 |
|
final public function setCurl($mode = true) { |
235
|
|
|
|
236
|
84 |
|
$curl = filter_var($mode, FILTER_VALIDATE_BOOLEAN); |
237
|
|
|
|
238
|
84 |
|
if ( !function_exists("curl_init") OR !$curl ) $this->curl = false; |
239
|
45 |
|
else $this->curl = true; |
240
|
|
|
|
241
|
84 |
|
return $this; |
242
|
|
|
|
243
|
|
|
} |
244
|
|
|
|
245
|
|
|
/** |
246
|
|
|
* Set http authentication |
247
|
|
|
* |
248
|
|
|
* @param string $method Auth method (BASIC or NTLM) |
249
|
|
|
* @param string $user Username to use |
250
|
|
|
* @param string $pass User password |
251
|
|
|
* |
252
|
|
|
* @return \Comodojo\Httprequest\Httprequest |
253
|
|
|
* |
254
|
|
|
* @throws \Comodojo\Exception\HttpException |
255
|
|
|
*/ |
256
|
9 |
|
final public function setAuth($method, $user, $pass = null) { |
257
|
|
|
|
258
|
9 |
|
$method = strtoupper($method); |
259
|
|
|
|
260
|
9 |
|
if ( !in_array($method, $this->supported_auth_methods) ) { |
261
|
|
|
|
262
|
|
|
throw new HttpException("Unsupported authentication method"); |
263
|
|
|
|
264
|
|
|
} |
265
|
|
|
|
266
|
9 |
|
$this->authenticationMethod = $method; |
267
|
|
|
|
268
|
9 |
|
if ( empty($user) ) { |
269
|
|
|
|
270
|
|
|
throw new HttpException("User name cannot be null"); |
271
|
|
|
|
272
|
|
|
} |
273
|
|
|
|
274
|
9 |
|
$this->user = $user; |
275
|
9 |
|
$this->pass = $pass; |
276
|
|
|
|
277
|
9 |
|
return $this; |
278
|
|
|
|
279
|
|
|
} |
280
|
|
|
|
281
|
|
|
/** |
282
|
|
|
* Set user agent for request |
283
|
|
|
* |
284
|
|
|
* @param string $ua User Agent |
285
|
|
|
* |
286
|
|
|
* @return \Comodojo\Httprequest\Httprequest |
287
|
|
|
* |
288
|
|
|
* @throws \Comodojo\Exception\HttpException |
289
|
|
|
*/ |
290
|
9 |
|
final public function setUserAgent($ua) { |
291
|
|
|
|
292
|
9 |
|
if ( empty($ua) ) throw new HttpException("Useragent cannot be null"); |
293
|
|
|
|
294
|
9 |
|
$this->userAgent = $ua; |
295
|
|
|
|
296
|
9 |
|
return $this; |
297
|
|
|
|
298
|
|
|
} |
299
|
|
|
|
300
|
|
|
/** |
301
|
|
|
* Set connection timeout |
302
|
|
|
* |
303
|
|
|
* @param int $sec Timeout to wait for (in second) |
304
|
|
|
* |
305
|
|
|
* @return \Comodojo\Httprequest\Httprequest |
306
|
|
|
*/ |
307
|
9 |
|
final public function setTimeout($sec) { |
308
|
|
|
|
309
|
9 |
|
$time = filter_var($sec, FILTER_VALIDATE_INT); |
310
|
|
|
|
311
|
9 |
|
$this->timeout = $time; |
312
|
|
|
|
313
|
9 |
|
return $this; |
314
|
|
|
|
315
|
|
|
} |
316
|
|
|
|
317
|
|
|
/** |
318
|
|
|
* Set http version (1.0/1.1) |
319
|
|
|
* |
320
|
|
|
* @param string $ver 1.0 or 1.1 |
321
|
|
|
* |
322
|
|
|
* @return \Comodojo\Httprequest\Httprequest |
323
|
|
|
*/ |
324
|
3 |
|
final public function setHttpVersion($ver) { |
325
|
|
|
|
326
|
3 |
|
if ( !in_array($ver, array("1.0", "1.1")) ) { |
327
|
|
|
|
328
|
|
|
$this->httpVersion = "NONE"; |
329
|
|
|
|
330
|
|
|
} else { |
331
|
|
|
|
332
|
3 |
|
$this->httpVersion = $ver; |
333
|
|
|
|
334
|
|
|
} |
335
|
|
|
|
336
|
3 |
|
return $this; |
337
|
|
|
|
338
|
|
|
} |
339
|
|
|
|
340
|
|
|
/** |
341
|
|
|
* Set http content type |
342
|
|
|
* |
343
|
|
|
* @param string $type |
344
|
|
|
* |
345
|
|
|
* @return \Comodojo\Httprequest\Httprequest |
346
|
|
|
* |
347
|
|
|
* @throws \Comodojo\Exception\HttpException |
348
|
|
|
*/ |
349
|
9 |
|
final public function setContentType($type) { |
350
|
|
|
|
351
|
9 |
|
if ( empty($type) ) throw new HttpException("Conte Type cannot be null"); |
352
|
|
|
|
353
|
9 |
|
$this->contentType = $type; |
354
|
|
|
|
355
|
9 |
|
return $this; |
356
|
|
|
|
357
|
|
|
} |
358
|
|
|
|
359
|
|
|
/** |
360
|
|
|
* Set TCP port to connect to |
361
|
|
|
* |
362
|
|
|
* @param integer $port TCP port (default 80) |
363
|
|
|
* |
364
|
|
|
* @return \Comodojo\Httprequest\Httprequest |
365
|
|
|
*/ |
366
|
3 |
|
final public function setPort($port) { |
367
|
|
|
|
368
|
3 |
|
$this->port = filter_var($port, FILTER_VALIDATE_INT, array( |
369
|
|
|
"options" => array( |
370
|
3 |
|
"min_range" => 1, |
371
|
3 |
|
"max_range" => 65535, |
372
|
3 |
|
"default" => 80 ) |
373
|
3 |
|
) |
374
|
3 |
|
); |
375
|
|
|
|
376
|
3 |
|
return $this; |
377
|
|
|
|
378
|
|
|
} |
379
|
|
|
|
380
|
|
|
/** |
381
|
|
|
* Set HTTP method to use |
382
|
|
|
* |
383
|
|
|
* @param string $method HTTP METHOD |
384
|
|
|
* |
385
|
|
|
* @return \Comodojo\Httprequest\Httprequest |
386
|
|
|
* |
387
|
|
|
* @throws \Comodojo\Exception\HttpException |
388
|
|
|
*/ |
389
|
27 |
|
final public function setHttpMethod($method) { |
390
|
|
|
|
391
|
27 |
|
$method = strtoupper($method); |
392
|
|
|
|
393
|
27 |
|
if ( !in_array($method, $this->supported_http_methods) ) { |
394
|
|
|
|
395
|
|
|
throw new HttpException("Unsupported HTTP method"); |
396
|
|
|
|
397
|
|
|
} |
398
|
|
|
|
399
|
27 |
|
$this->method = $method; |
400
|
|
|
|
401
|
27 |
|
return $this; |
402
|
|
|
|
403
|
|
|
} |
404
|
|
|
|
405
|
|
|
/** |
406
|
|
|
* Set whether or not to ignore errors |
407
|
|
|
* |
408
|
|
|
* @param boolean $ignore Should stream ignore errors |
409
|
|
|
* |
410
|
|
|
* @return \Comodojo\Httprequest\Httprequest |
411
|
|
|
*/ |
412
|
|
|
final public function setIgnoreErrors($ignore = true) { |
413
|
|
|
|
414
|
|
|
$this->ignore_errors = (bool)$ignore; |
415
|
|
|
|
416
|
|
|
return $this; |
417
|
|
|
|
418
|
|
|
} |
419
|
|
|
|
420
|
|
|
/** |
421
|
|
|
* Set HTTP method to use |
422
|
|
|
* |
423
|
|
|
* @param string $address Proxy URL or IP address |
424
|
|
|
* @param string $user (optional) User name for proy auth |
425
|
|
|
* @param string $pass (optional) User password for proxy auth |
426
|
|
|
* |
427
|
|
|
* @return \Comodojo\Httprequest\Httprequest |
428
|
|
|
* |
429
|
|
|
* @throws \Comodojo\Exception\HttpException |
430
|
|
|
*/ |
431
|
3 |
|
final public function setProxy($address, $user = null, $pass = null) { |
432
|
|
|
|
433
|
3 |
|
$proxy = filter_var($address, FILTER_VALIDATE_URL); |
434
|
|
|
|
435
|
3 |
|
if ( $proxy == false ) throw new HttpException("Invalid proxy address or URL"); |
436
|
|
|
|
437
|
3 |
|
$this->proxy = $proxy; |
438
|
|
|
|
439
|
3 |
|
if ( !is_null($user) AND !is_null($pass) ) { |
440
|
|
|
|
441
|
3 |
|
$this->proxy_auth = $user.':'.$pass; |
442
|
|
|
|
443
|
3 |
|
} else if ( !is_null($user) ) { |
444
|
|
|
|
445
|
|
|
$this->proxy_auth = $user; |
446
|
|
|
|
447
|
|
|
} else $this->proxy_auth = NULL; |
448
|
|
|
|
449
|
3 |
|
return $this; |
450
|
|
|
|
451
|
|
|
} |
452
|
|
|
|
453
|
|
|
/** |
454
|
|
|
* Set header component |
455
|
|
|
* |
456
|
|
|
* @param string $header Header name |
457
|
|
|
* @param string $value Header content (optional) |
458
|
|
|
* |
459
|
|
|
* @return \Comodojo\Httprequest\Httprequest |
460
|
|
|
*/ |
461
|
27 |
|
final public function setHeader($header, $value = NULL) { |
462
|
|
|
|
463
|
27 |
|
$this->headers[$header] = $value; |
464
|
|
|
|
465
|
27 |
|
return $this; |
466
|
|
|
|
467
|
|
|
} |
468
|
|
|
|
469
|
|
|
/** |
470
|
|
|
* Unset header component |
471
|
|
|
* |
472
|
|
|
* @param string $header Header name |
473
|
|
|
* |
474
|
|
|
* @return \Comodojo\Httprequest\Httprequest |
475
|
|
|
*/ |
476
|
|
|
final public function unsetHeader($header) { |
477
|
|
|
|
478
|
|
|
if ( array_key_exists($header, $this->headers) ) unset($this->headers[$header]); |
479
|
|
|
|
480
|
|
|
return $this; |
481
|
|
|
|
482
|
|
|
} |
483
|
|
|
|
484
|
|
|
/** |
485
|
|
|
* Get the whole headers array |
486
|
|
|
* |
487
|
|
|
* @return array |
488
|
|
|
*/ |
489
|
78 |
|
final public function getHeaders() { |
490
|
|
|
|
491
|
78 |
|
return $this->headers; |
492
|
|
|
|
493
|
|
|
} |
494
|
|
|
|
495
|
|
|
/** |
496
|
|
|
* Get received headers |
497
|
|
|
* |
498
|
|
|
* @return array |
499
|
|
|
*/ |
500
|
24 |
|
final public function getReceivedHeaders() { |
501
|
|
|
|
502
|
24 |
|
return $this->receivedHeaders; |
503
|
|
|
|
504
|
|
|
} |
505
|
|
|
|
506
|
|
|
/** |
507
|
|
|
* Get received headers |
508
|
|
|
* |
509
|
|
|
* @return integer |
510
|
|
|
*/ |
511
|
60 |
|
final public function getHttpStatusCode() { |
512
|
|
|
|
513
|
60 |
|
return $this->receivedHttpStatus; |
514
|
|
|
|
515
|
|
|
} |
516
|
|
|
|
517
|
|
|
/** |
518
|
|
|
* Get transport channel (curl channel or stream context) |
519
|
|
|
* |
520
|
|
|
* @return mixed |
521
|
|
|
*/ |
522
|
6 |
|
final public function getChannel() { |
523
|
|
|
|
524
|
6 |
|
return $this->ch; |
525
|
|
|
|
526
|
|
|
} |
527
|
|
|
|
528
|
|
|
/** |
529
|
|
|
* Init transport and send data to the remote host. |
530
|
|
|
* |
531
|
|
|
* @return string |
532
|
|
|
* |
533
|
|
|
* @throws \Comodojo\Exception\HttpException |
534
|
|
|
*/ |
535
|
30 |
View Code Duplication |
public function send($data = null) { |
|
|
|
|
536
|
|
|
|
537
|
|
|
try { |
538
|
|
|
|
539
|
30 |
|
if ( $this->curl ) { |
540
|
|
|
|
541
|
15 |
|
$this->init_curl($data); |
542
|
|
|
|
543
|
15 |
|
$received = $this->send_curl(); |
544
|
|
|
|
545
|
15 |
|
} else { |
546
|
|
|
|
547
|
15 |
|
$this->init_stream($data); |
548
|
|
|
|
549
|
15 |
|
$received = $this->send_stream(); |
550
|
|
|
|
551
|
|
|
} |
552
|
|
|
|
553
|
|
|
|
554
|
30 |
|
} catch (HttpException $ioe) { |
555
|
|
|
|
556
|
|
|
throw $ioe; |
557
|
|
|
|
558
|
|
|
} |
559
|
|
|
|
560
|
30 |
|
return $received; |
561
|
|
|
|
562
|
|
|
} |
563
|
|
|
|
564
|
|
|
/** |
565
|
|
|
* Init transport and get remote content |
566
|
|
|
* |
567
|
|
|
* @return string |
568
|
|
|
* |
569
|
|
|
* @throws \Comodojo\Exception\HttpException |
570
|
|
|
*/ |
571
|
48 |
View Code Duplication |
public function get() { |
|
|
|
|
572
|
|
|
|
573
|
|
|
try { |
574
|
|
|
|
575
|
48 |
|
if ( $this->curl ) { |
576
|
|
|
|
577
|
24 |
|
$this->init_curl(null); |
578
|
|
|
|
579
|
24 |
|
$received = $this->send_curl(); |
580
|
|
|
|
581
|
21 |
|
} else { |
582
|
|
|
|
583
|
24 |
|
$this->init_stream(null); |
584
|
|
|
|
585
|
24 |
|
$received = $this->send_stream(); |
586
|
|
|
|
587
|
|
|
} |
588
|
|
|
|
589
|
48 |
|
} catch (HttpException $ioe) { |
590
|
|
|
|
591
|
6 |
|
throw $ioe; |
592
|
|
|
|
593
|
|
|
} |
594
|
|
|
|
595
|
42 |
|
return $received; |
596
|
|
|
|
597
|
|
|
} |
598
|
|
|
|
599
|
|
|
/** |
600
|
|
|
* Reset the data channel for new request |
601
|
|
|
* |
602
|
|
|
*/ |
603
|
|
|
final public function reset() { |
604
|
|
|
|
605
|
|
|
$this->address = null; |
606
|
|
|
|
607
|
|
|
$this->port = 80; |
608
|
|
|
|
609
|
|
|
$this->method = 'GET'; |
610
|
|
|
|
611
|
|
|
$this->timeout = 30; |
612
|
|
|
|
613
|
|
|
$this->httpVersion = "1.0"; |
614
|
|
|
|
615
|
|
|
$this->authenticationMethod = null; |
616
|
|
|
|
617
|
|
|
$this->user = null; |
618
|
|
|
|
619
|
|
|
$this->pass = null; |
620
|
|
|
|
621
|
|
|
$this->userAgent = 'Comodojo-Httprequest'; |
622
|
|
|
|
623
|
|
|
$this->contentType = 'application/x-www-form-urlencoded'; |
624
|
|
|
|
625
|
|
|
$this->headers = array( |
626
|
|
|
'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', |
627
|
|
|
'Accept-Language' => 'en-us,en;q=0.5', |
628
|
|
|
'Accept-Encoding' => 'deflate', |
629
|
|
|
'Accept-Charset' => 'UTF-8;q=0.7,*;q=0.7' |
630
|
|
|
); |
631
|
|
|
|
632
|
|
|
$this->proxy = null; |
633
|
|
|
|
634
|
|
|
$this->proxy_auth = null; |
635
|
|
|
|
636
|
|
|
$this->receivedHeaders = array(); |
637
|
|
|
|
638
|
|
|
$this->receivedHttpStatus = null; |
639
|
|
|
|
640
|
|
|
$this->stream_get_data = null; |
641
|
|
|
|
642
|
|
|
if ( $this->ch !== false ) $this->close_transport(); |
643
|
|
|
|
644
|
|
|
} |
645
|
|
|
|
646
|
|
|
/** |
647
|
|
|
* Parse a single header |
648
|
|
|
* |
649
|
|
|
* @param string $header |
650
|
|
|
* @param string $value |
651
|
|
|
* |
652
|
|
|
* @return string |
653
|
|
|
*/ |
654
|
|
|
private function parseHeader($header, $value) { |
|
|
|
|
655
|
|
|
|
656
|
|
|
if ( is_null($value) ) return $header; |
657
|
|
|
|
658
|
|
|
else return $header.': '.$value; |
659
|
|
|
|
660
|
|
|
} |
661
|
|
|
|
662
|
|
|
/** |
663
|
|
|
* Init the CURL channel |
664
|
|
|
* |
665
|
|
|
* @param string $data |
666
|
|
|
* |
667
|
|
|
* @throws \Comodojo\Exception\HttpException |
668
|
|
|
*/ |
669
|
39 |
|
private function init_curl($data) { |
670
|
|
|
|
671
|
39 |
|
$this->ch = curl_init(); |
672
|
|
|
|
673
|
39 |
|
if ( $this->ch === false ) throw new HttpException("Cannot init data channel"); |
674
|
|
|
|
675
|
39 |
|
switch ( $this->httpVersion ) { |
676
|
|
|
|
677
|
39 |
|
case '1.0': |
678
|
39 |
|
curl_setopt($this->ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); |
679
|
39 |
|
break; |
680
|
|
|
|
681
|
|
|
case '1.1': |
682
|
|
|
curl_setopt($this->ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); |
683
|
|
|
break; |
684
|
|
|
|
685
|
|
|
default: |
686
|
|
|
curl_setopt($this->ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_NONE); |
687
|
|
|
break; |
688
|
|
|
|
689
|
39 |
|
} |
690
|
|
|
|
691
|
39 |
|
switch ( $this->authenticationMethod ) { |
692
|
|
|
|
693
|
39 |
View Code Duplication |
case 'BASIC': |
|
|
|
|
694
|
3 |
|
curl_setopt($this->ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); |
695
|
3 |
|
curl_setopt($this->ch, CURLOPT_USERPWD, $this->user.":".$this->pass); |
696
|
3 |
|
break; |
697
|
|
|
|
698
|
36 |
View Code Duplication |
case 'DIGEST': |
|
|
|
|
699
|
|
|
curl_setopt($this->ch, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST); |
700
|
|
|
curl_setopt($this->ch, CURLOPT_USERPWD, $this->user.":".$this->pass); |
701
|
|
|
break; |
702
|
|
|
|
703
|
36 |
View Code Duplication |
case 'SPNEGO': |
|
|
|
|
704
|
|
|
curl_setopt($this->ch, CURLOPT_HTTPAUTH, CURLAUTH_GSSNEGOTIATE); |
705
|
|
|
curl_setopt($this->ch, CURLOPT_USERPWD, $this->user.":".$this->pass); |
706
|
|
|
break; |
707
|
|
|
|
708
|
36 |
View Code Duplication |
case 'NTLM': |
|
|
|
|
709
|
|
|
curl_setopt($this->ch, CURLOPT_HTTPAUTH, CURLAUTH_NTLM); |
710
|
|
|
curl_setopt($this->ch, CURLOPT_USERPWD, $this->user.":".$this->pass); |
711
|
|
|
break; |
712
|
|
|
|
713
|
39 |
|
} |
714
|
|
|
|
715
|
39 |
|
if ( !is_null($this->proxy) ) { |
716
|
|
|
|
717
|
|
|
curl_setopt($this->ch, CURLOPT_PROXY, $this->proxy); |
718
|
|
|
|
719
|
|
|
if ( !is_null($this->proxy_auth) ) curl_setopt($this->ch, CURLOPT_PROXYUSERPWD, $this->proxy_auth); |
720
|
|
|
|
721
|
|
|
} |
722
|
|
|
|
723
|
39 |
|
switch ( $this->method ) { |
724
|
|
|
|
725
|
39 |
|
case 'GET': |
726
|
|
|
|
727
|
27 |
|
if ( empty($data) ) curl_setopt($this->ch, CURLOPT_URL, $this->address); |
728
|
|
|
|
729
|
3 |
|
else curl_setopt($this->ch, CURLOPT_URL, $this->address."?".((is_array($data) OR is_object($data)) ? http_build_query($data) : $data)); |
730
|
|
|
|
731
|
27 |
|
break; |
732
|
|
|
|
733
|
12 |
View Code Duplication |
case 'PUT': |
|
|
|
|
734
|
|
|
|
735
|
3 |
|
curl_setopt($this->ch, CURLOPT_CUSTOMREQUEST, "PUT"); |
736
|
|
|
|
737
|
3 |
|
if ( !empty($data) ) { |
738
|
|
|
|
739
|
3 |
|
curl_setopt($this->ch, CURLOPT_POSTFIELDS, (is_array($data) OR is_object($data)) ? http_build_query($data) : $data); |
740
|
|
|
|
741
|
3 |
|
$this->setHeader('Content-Type', $this->contentType); |
742
|
|
|
|
743
|
3 |
|
} |
744
|
|
|
|
745
|
3 |
|
curl_setopt($this->ch, CURLOPT_URL, $this->address); |
746
|
|
|
|
747
|
3 |
|
break; |
748
|
|
|
|
749
|
9 |
View Code Duplication |
case 'POST': |
|
|
|
|
750
|
|
|
|
751
|
6 |
|
curl_setopt($this->ch, CURLOPT_POST, true); |
752
|
|
|
|
753
|
6 |
|
if ( !empty($data) ) { |
754
|
|
|
|
755
|
6 |
|
curl_setopt($this->ch, CURLOPT_POSTFIELDS, (is_array($data) OR is_object($data)) ? http_build_query($data) : $data); |
756
|
|
|
|
757
|
6 |
|
$this->setHeader('Content-Type', $this->contentType); |
758
|
|
|
|
759
|
6 |
|
} |
760
|
|
|
|
761
|
6 |
|
curl_setopt($this->ch, CURLOPT_URL, $this->address); |
762
|
|
|
|
763
|
6 |
|
break; |
764
|
|
|
|
765
|
3 |
View Code Duplication |
case 'DELETE': |
|
|
|
|
766
|
|
|
|
767
|
3 |
|
curl_setopt($this->ch, CURLOPT_CUSTOMREQUEST, "DELETE"); |
768
|
|
|
|
769
|
3 |
|
if ( !empty($data) ) { |
770
|
|
|
|
771
|
3 |
|
curl_setopt($this->ch, CURLOPT_POSTFIELDS, (is_array($data) OR is_object($data)) ? http_build_query($data) : $data); |
772
|
|
|
|
773
|
3 |
|
$this->setHeader('Content-Type', $this->contentType); |
774
|
|
|
|
775
|
3 |
|
} |
776
|
|
|
|
777
|
3 |
|
curl_setopt($this->ch, CURLOPT_URL, $this->address); |
778
|
|
|
|
779
|
3 |
|
break; |
780
|
|
|
|
781
|
39 |
|
} |
782
|
|
|
|
783
|
39 |
|
if ( sizeof($this->headers) != 0 ) { |
784
|
|
|
|
785
|
39 |
|
$headers = array(); |
786
|
|
|
|
787
|
39 |
|
foreach ( $this->getHeaders() as $header => $value ) { |
788
|
|
|
|
789
|
39 |
|
if ( is_null($value) ) array_push($headers, $header); |
790
|
|
|
|
791
|
39 |
|
else array_push($headers, $header.': '.$value); |
792
|
|
|
|
793
|
39 |
|
} |
794
|
|
|
|
795
|
39 |
|
} else $headers = array(); |
796
|
|
|
|
797
|
39 |
|
curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, 1); |
798
|
39 |
|
curl_setopt($this->ch, CURLOPT_FOLLOWLOCATION, 1); |
799
|
39 |
|
curl_setopt($this->ch, CURLOPT_TIMEOUT, $this->timeout); |
800
|
39 |
|
curl_setopt($this->ch, CURLOPT_PORT, $this->port); |
801
|
39 |
|
curl_setopt($this->ch, CURLOPT_USERAGENT, $this->userAgent); |
802
|
39 |
|
curl_setopt($this->ch, CURLOPT_HTTPHEADER, $headers); |
803
|
39 |
|
curl_setopt($this->ch, CURLOPT_HEADER, 1); |
804
|
39 |
|
curl_setopt($this->ch, CURLOPT_ENCODING, ""); |
805
|
|
|
|
806
|
|
|
//curl_setopt($this->ch, CURLOPT_VERBOSE, true); |
807
|
|
|
|
808
|
39 |
|
} |
809
|
|
|
|
810
|
|
|
/** |
811
|
|
|
* Init the STREAM channel |
812
|
|
|
* |
813
|
|
|
* @param string $data |
814
|
|
|
* |
815
|
|
|
* @throws \Comodojo\Exception\HttpException |
816
|
|
|
*/ |
817
|
39 |
|
private function init_stream($data) { |
818
|
|
|
|
819
|
39 |
|
if ( in_array($this->authenticationMethod, array("DIGEST", "SPNEGO", "NTLM")) ) throw new HttpException("Selected auth method not available in stream mode"); |
820
|
|
|
|
821
|
|
|
$stream_options = array( |
822
|
|
|
'http' => array( |
823
|
39 |
|
'method' => $this->method, |
824
|
39 |
|
'protocol_version' => $this->httpVersion == "NONE" ? "1.0" : $this->httpVersion, |
825
|
39 |
|
'user_agent' => $this->userAgent, |
826
|
39 |
|
'timeout' => $this->timeout, |
827
|
|
|
'header' => array( |
828
|
|
|
'Connection: close' |
829
|
39 |
|
) |
830
|
39 |
|
) |
831
|
39 |
|
); |
832
|
|
|
|
833
|
39 |
|
if ( !is_null($this->proxy) ) { |
834
|
|
|
|
835
|
|
|
$stream_options['http']['proxy'] = $this->proxy; |
836
|
|
|
|
837
|
|
|
if ( !is_null($this->proxy_auth) ) array_push($stream_options['http']['header'], 'Proxy-Authorization: Basic '.base64_encode($this->proxy_auth)); |
838
|
|
|
|
839
|
|
|
} |
840
|
|
|
|
841
|
39 |
|
if ( $this->authenticationMethod == "BASIC" ) array_push($stream_options['http']['header'], 'Authorization: Basic '.base64_encode($this->user.":".$this->pass)); |
842
|
|
|
|
843
|
39 |
|
if ( $this->ignore_errors ) { |
844
|
|
|
$stream_options['http']['ignore_errors'] = true; |
845
|
|
|
} |
846
|
|
|
|
847
|
39 |
|
foreach ( $this->getHeaders() as $header => $value ) { |
848
|
|
|
|
849
|
39 |
|
if ( is_null($value) ) array_push($stream_options['http']['header'], $header); |
850
|
|
|
|
851
|
39 |
|
else array_push($stream_options['http']['header'], $header.': '.$value); |
852
|
|
|
|
853
|
39 |
|
} |
854
|
|
|
|
855
|
39 |
|
if ( !empty($data) ) { |
856
|
|
|
|
857
|
15 |
|
$data_query = (is_array($data) OR is_object($data)) ? http_build_query($data) : $data; |
858
|
|
|
|
859
|
15 |
|
if ( $this->method == "GET" ) { |
860
|
|
|
|
861
|
3 |
|
$this->stream_get_data = $data_query; |
862
|
|
|
|
863
|
3 |
|
} else { |
864
|
|
|
|
865
|
12 |
|
array_push($stream_options['http']['header'], 'Content-Type: '.$this->contentType); |
866
|
|
|
|
867
|
12 |
|
array_push($stream_options['http']['header'], 'Content-Length: '.strlen($data_query)); |
868
|
|
|
|
869
|
12 |
|
$stream_options['http']['content'] = $data_query; |
870
|
|
|
|
871
|
|
|
} |
872
|
|
|
|
873
|
15 |
|
} |
874
|
|
|
|
875
|
39 |
|
$this->ch = stream_context_create($stream_options); |
876
|
|
|
|
877
|
39 |
|
if ( !$this->ch ) { |
878
|
|
|
|
879
|
|
|
throw new HttpException("Cannot init data channel"); |
880
|
|
|
|
881
|
|
|
} |
882
|
|
|
|
883
|
39 |
|
} |
884
|
|
|
|
885
|
|
|
/** |
886
|
|
|
* Send data via CURL |
887
|
|
|
* |
888
|
|
|
* @return string |
889
|
|
|
* |
890
|
|
|
* @throws \Comodojo\Exception\HttpException |
891
|
|
|
*/ |
892
|
39 |
|
private function send_curl() { |
893
|
|
|
|
894
|
39 |
|
$request = curl_exec($this->ch); |
895
|
|
|
|
896
|
39 |
|
if ( $request === false ) { |
897
|
|
|
|
898
|
3 |
|
throw new HttpException(curl_error($this->ch), curl_errno($this->ch)); |
899
|
|
|
|
900
|
|
|
} |
901
|
|
|
|
902
|
36 |
|
$this->receivedHttpStatus = curl_getinfo($this->ch, CURLINFO_HTTP_CODE); |
903
|
|
|
|
904
|
36 |
|
$header_size = curl_getinfo($this->ch, CURLINFO_HEADER_SIZE); |
905
|
|
|
|
906
|
36 |
|
$headers = substr($request, 0, $header_size); |
907
|
|
|
|
908
|
36 |
|
$body = substr($request, $header_size); |
909
|
|
|
|
910
|
36 |
|
$this->receivedHeaders = self::tokenizeHeaders($headers); |
911
|
|
|
|
912
|
36 |
|
return $body; |
913
|
|
|
|
914
|
|
|
} |
915
|
|
|
|
916
|
|
|
/** |
917
|
|
|
* Send data via STREAM |
918
|
|
|
* |
919
|
|
|
* @return string |
920
|
|
|
* |
921
|
|
|
* @throws \Comodojo\Exception\HttpException |
922
|
|
|
*/ |
923
|
39 |
|
private function send_stream() { |
924
|
|
|
|
925
|
39 |
|
$url = Url::createFromUrl($this->address); |
926
|
|
|
|
927
|
39 |
|
if ( $this->port != 80 ) $url->setPort($this->port); |
928
|
|
|
|
929
|
39 |
|
if ( !is_null($this->stream_get_data) ) $url->setQuery($this->stream_get_data); |
930
|
|
|
|
931
|
39 |
|
$host = $url; |
932
|
|
|
|
933
|
39 |
|
set_error_handler( |
934
|
|
|
|
935
|
3 |
|
function($severity, $message, $file, $line) { |
|
|
|
|
936
|
|
|
|
937
|
3 |
|
throw new HttpException($message); |
938
|
|
|
|
939
|
|
|
} |
940
|
|
|
|
941
|
39 |
|
); |
942
|
|
|
|
943
|
|
|
try { |
944
|
|
|
|
945
|
39 |
|
$received = file_get_contents($host, false, $this->ch); |
946
|
|
|
|
947
|
39 |
|
} catch (HttpException $he) { |
948
|
|
|
|
949
|
3 |
|
throw $he; |
950
|
|
|
|
951
|
|
|
} |
952
|
|
|
|
953
|
36 |
|
restore_error_handler(); |
954
|
|
|
|
955
|
36 |
|
if ( $received === false ) { |
956
|
|
|
|
957
|
|
|
throw new HttpException("Cannot read stream socket"); |
958
|
|
|
|
959
|
|
|
} |
960
|
|
|
|
961
|
36 |
|
$this->receivedHeaders = self::tokenizeHeaders(implode("\r\n", $http_response_header)); |
962
|
|
|
|
963
|
36 |
|
$content_encoding = array_key_exists('Content-Encoding', $this->receivedHeaders); |
964
|
|
|
|
965
|
36 |
|
list($version, $this->receivedHttpStatus, $msg) = explode(' ', $this->receivedHeaders[0], 3); |
|
|
|
|
966
|
|
|
|
967
|
36 |
|
if ( $content_encoding === true AND strpos($this->receivedHeaders['Content-Encoding'], 'gzip') !== false ) { |
968
|
|
|
|
969
|
3 |
|
return gzinflate(substr($received, 10, -8)); |
970
|
|
|
|
971
|
33 |
|
} else return $received; |
972
|
|
|
|
973
|
|
|
} |
974
|
|
|
|
975
|
|
|
/** |
976
|
|
|
* Tokenize received headers |
977
|
|
|
* |
978
|
|
|
* @param string $headers |
979
|
|
|
* |
980
|
|
|
* @return array |
981
|
|
|
*/ |
982
|
72 |
|
private static function tokenizeHeaders($headers) { |
983
|
|
|
|
984
|
72 |
|
$return = array(); |
985
|
|
|
|
986
|
72 |
|
$headers_array = explode("\r\n", $headers); |
987
|
|
|
|
988
|
72 |
|
foreach ( $headers_array as $header ) { |
989
|
|
|
|
990
|
72 |
|
if ( empty($header) ) continue; |
991
|
|
|
|
992
|
72 |
|
$header_components = explode(":", $header); |
993
|
|
|
|
994
|
72 |
|
if ( !isset($header_components[1]) OR @empty($header_components[1]) ) array_push($return, $header_components[0]); |
995
|
|
|
|
996
|
72 |
|
else $return[$header_components[0]] = $header_components[1]; |
997
|
|
|
|
998
|
72 |
|
} |
999
|
|
|
|
1000
|
72 |
|
return $return; |
1001
|
|
|
|
1002
|
|
|
} |
1003
|
|
|
|
1004
|
|
|
/** |
1005
|
|
|
* Close transport layer |
1006
|
|
|
*/ |
1007
|
|
|
private function close_transport() { |
1008
|
|
|
|
1009
|
|
|
if ( $this->curl ) { |
1010
|
|
|
|
1011
|
|
|
curl_close($this->ch); |
1012
|
|
|
|
1013
|
|
|
} |
1014
|
|
|
|
1015
|
|
|
} |
1016
|
|
|
|
1017
|
|
|
} |
1018
|
|
|
|
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.