Failed Conditions
Pull Request — master (#102)
by Šimon
02:27
created

src/Transport/CurlerRequest.php (4 issues)

1
<?php
2
3
namespace ClickHouseDB\Transport;
4
5
use const CURLOPT_CONNECTTIMEOUT_MS;
6
7
class CurlerRequest
8
{
9
    /**
10
     * @var array
11
     */
12
    public $extendinfo = array();
13
14
    /**
15
     * @var string|array
16
     */
17
    private $parameters = '';
18
19
    /**
20
     * @var array
21
     */
22
    private $options;
23
24
    /**
25
     * @var array
26
     */
27
    private $headers; // Parsed reponse header object.
28
29
    /**
30
     * @var string
31
     */
32
    private $url;
33
34
    /**
35
     * @var string
36
     */
37
    private $method;
38
39
    /**
40
     * @var bool
41
     */
42
    private $id;
43
44
    /**
45
     * @var resource|null
46
     */
47
    private $handle;
48
49
    /**
50
     * @var CurlerResponse
51
     */
52
    private $resp = null;
53
54
    /**
55
     * @var bool
56
     */
57
    private $_persistent = false;
58
59
    /**
60
     * @var bool
61
     */
62
    private $_attachFiles = false;
63
64
    /**
65
     * @var string
66
     */
67
    private $callback_class = '';
68
69
    /**
70
     * @var string
71
     */
72
    private $callback_functionName = '';
73
74
    /**
75
     * @var bool
76
     */
77
    private $_httpCompression = false;
78
79
    /**
80
     * @var callable
81
     */
82
    private $callback_function = null;
83
84
    /**
85
     * @var bool|resource
86
     */
87
    private $infile_handle = false;
88
89
    /**
90
     * @var int
91
     */
92
    private $_dns_cache = 120;
93
94
    /**
95
     * @var resource
96
     */
97
    private $resultFileHandle = null;
98
99
    /**
100
     * @param bool $id
101
     */
102 63
    public function __construct($id = false)
103
    {
104 63
        $this->id = $id;
105
106 63
        $this->header('Cache-Control', 'no-cache, no-store, must-revalidate');
107 63
        $this->header('Expires', '0');
108 63
        $this->header('Pragma', 'no-cache');
109
110 63
        $this->options = array(
111 63
            CURLOPT_SSL_VERIFYHOST => 0,
112 63
            CURLOPT_SSL_VERIFYPEER => false,
113 63
            CURLOPT_TIMEOUT => 10,
114 63
            CURLOPT_CONNECTTIMEOUT => 5, // Количество секунд ожидания при попытке соединения
115 63
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
116 63
            CURLOPT_MAXREDIRS => 10,
117 63
            CURLOPT_HEADER => TRUE,
118 63
            CURLOPT_FOLLOWLOCATION => TRUE,
119 63
            CURLOPT_AUTOREFERER => 1, // при редиректе подставлять в «Referer:» значение из «Location:»
120 63
            CURLOPT_BINARYTRANSFER => 1, // передавать в binary-safe
121 63
            CURLOPT_RETURNTRANSFER => TRUE,
122 63
            CURLOPT_USERAGENT => 'smi2/PHPClickHouse/client',
123
        );
124 63
    }
125
126
    /**
127
     *
128
     */
129 63
    public function __destruct()
130
    {
131 63
        $this->close();
132 63
    }
133
134
135 63
    public function close()
136
    {
137 63
        if ($this->handle)
138
        {
139 63
            curl_close($this->handle);
140
        }
141 63
        $this->handle = null;
142 63
    }
143
144
    /**
145
     * @param array $attachFiles
146
     */
147 1
    public function attachFiles($attachFiles)
148
    {
149 1
        $this->header("Content-Type", "multipart/form-data");
150
151 1
        $out = [];
152 1
        foreach ($attachFiles as $post_name => $file_path) {
153 1
            $out[$post_name] = new \CURLFile($file_path);
154
        }
155
156 1
        $this->_attachFiles = true;
157 1
        $this->parameters($out);
158 1
    }
159
160
161
    /**
162
     * @param bool $set
163
     * @return $this
164
     */
165
    public function id($set = false)
166
    {
167
        if ($set) {
168
            $this->id = $set;
169
        }
170
171
        return $this;
172
    }
173
174
    /**
175
     * @param array $params
176
     * @return $this
177
     */
178 63
    public function setRequestExtendedInfo($params)
179
    {
180 63
        $this->extendinfo = $params;
181 63
        return $this;
182
    }
183
184
    /**
185
     * @param string|integer|null $key
186
     * @return mixed
187
     */
188 63
    public function getRequestExtendedInfo($key = null)
189
    {
190 63
        if ($key) {
191 63
            return isset($this->extendinfo[$key]) ? $this->extendinfo[$key] : false;
192
        }
193
194
        return $this->extendinfo;
195
    }
196
197
    /**
198
     * @return bool|resource
199
     */
200 8
    public function getInfileHandle()
201
    {
202 8
        return $this->infile_handle;
203
    }
204
205
    /**
206
     * @param string $file_name
207
     * @return bool|resource
208
     */
209 8
    public function setInfile($file_name)
210
    {
211 8
        $this->header('Expect', '');
212 8
        $this->infile_handle = fopen($file_name, 'r');
213 8
        if (is_resource($this->infile_handle))
214
        {
215
216 8
            if ($this->_httpCompression) {
217 8
                $this->header('Content-Encoding', 'gzip');
218 8
                $this->header('Content-Type', 'application/x-www-form-urlencoded');
219
220 8
                stream_filter_append($this->infile_handle, 'zlib.deflate', STREAM_FILTER_READ, ["window" => 30]);
221
222 8
                $this->options[CURLOPT_SAFE_UPLOAD] = 1;
223
            } else {
224
                $this->options[CURLOPT_INFILESIZE] = filesize($file_name);
225
            }
226
227 8
            $this->options[CURLOPT_INFILE] = $this->infile_handle;
228
        }
229
230 8
        return $this->infile_handle;
231
    }
232
233
    /**
234
     * @param callable $callback
235
     */
236 8
    public function setCallbackFunction($callback)
237
    {
238 8
        $this->callback_function = $callback;
239 8
    }
240
241
    /**
242
     * @param callable $callback
243
     */
244 1
    public function setWriteFunction($callback)
245
    {
246 1
        $this->options[CURLOPT_WRITEFUNCTION]=$callback;
247 1
    }
248
    /**
249
     * @param callable $callback
250
     */
251 3
    public function setReadFunction($callback)
252
    {
253 3
        $this->options[CURLOPT_READFUNCTION] = $callback;
254 3
    }
255
256
    public function setHeaderFunction($callback)
257
    {
258
        $this->options[CURLOPT_HEADERFUNCTION] = $callback;
259
    }
260
261
    /**
262
     * @param string $classCallBack
263
     * @param string $functionName
264
     */
265
    public function setCallback($classCallBack, $functionName)
266
    {
267
        $this->callback_class = $classCallBack;
268
        $this->callback_functionName = $functionName;
269
    }
270
271
    /**
272
     *
273
     */
274 10
    public function onCallback()
275
    {
276 10
        if ($this->callback_function) {
277 8
            $x = $this->callback_function;
278 8
            $x($this);
279
        }
280
281 10
        if ($this->callback_class && $this->callback_functionName) {
282
            $c = $this->callback_functionName;
283
            $this->callback_class->$c($this);
284
        }
285 10
    }
286
287
    /**
288
     * @param bool $result
289
     * @return string
290
     */
291
    public function dump($result = false)
292
    {
293
        $message = "\n------------  Request ------------\n";
294
        $message .= 'URL:' . $this->url . "\n\n";
295
        $message .= 'METHOD:' . $this->method . "\n\n";
296
        $message .= 'PARAMS:' . print_r($this->parameters, true) . "\n";
297
        $message .= 'PARAMS:' . print_r($this->headers, true) . "\n";
298
        $message .= "-----------------------------------\n";
299
300
        if ($result) {
301
            return $message;
302
        }
303
304
        echo $message;
305
        return '';
306
    }
307
308
    /**
309
     * @return bool
310
     */
311 13
    public function getId()
312
    {
313 13
        return $this->id;
314
    }
315
316
    /**
317
     * @param integer $key
318
     * @param mixed $value
319
     * @return $this
320
     */
321 1
    private function option($key, $value)
322
    {
323 1
        $this->options[$key] = $value;
324 1
        return $this;
325
    }
326
327
    /**
328
     * @return $this
329
     */
330 1
    public function persistent()
331
    {
332 1
        $this->_persistent = true;
333 1
        return $this;
334
    }
335
336
    /**
337
     * @return bool
338
     */
339 10
    public function isPersistent()
340
    {
341 10
        return $this->_persistent;
342
    }
343
344
    /**
345
     * @param int $sec
346
     * @return $this
347
     */
348 63
    public function keepAlive($sec = 60)
349
    {
350 63
        $this->options[CURLOPT_FORBID_REUSE] = TRUE;
351 63
        $this->headers['Connection'] = 'Keep-Alive';
352 63
        $this->headers['Keep-Alive'] = $sec;
353
354 63
        return $this;
355
    }
356
357
    /**
358
     * @param bool $flag
359
     * @return $this
360
     */
361 63
    public function verbose($flag = true)
362
    {
363 63
        $this->options[CURLOPT_VERBOSE] = $flag;
364 63
        return $this;
365
    }
366
367
    /**
368
     * @param string $key
369
     * @param string $value
370
     * @return $this
371
     */
372 63
    public function header($key, $value)
373
    {
374 63
        $this->headers[$key] = $value;
375 63
        return $this;
376
    }
377
378
    /**
379
     * @return array
380
     */
381
    public function getHeaders()
382
    {
383
        $head = [];
384
        foreach ($this->headers as $key=>$value) {
385
                    $head[] = sprintf("%s: %s", $key, $value);
386
        }
387
        return $head;
388
    }
389
390
    /**
391
     * @param string $url
392
     * @return $this
393
     */
394 63
    public function url($url)
395
    {
396 63
        $this->url = $url;
397 63
        return $this;
398
    }
399
400
    /**
401
     * @return mixed
402
     */
403
    public function getUrl()
404
    {
405
        return $this->url;
406
    }
407
408
409
    /**
410
     * @param string $id
411
     * @return string
412
     */
413 13
    public function getUniqHash($id)
414
    {
415 13
        return $id . '.' . microtime() . mt_rand(0, 1000000);
416
    }
417
418 63
    public function httpCompression(bool $flag)
0 ignored issues
show
Method \ClickHouseDB\Transport\CurlerRequest::httpCompression() does not have void return type hint.
Loading history...
419
    {
420 63
        if ($flag) {
421 63
            $this->_httpCompression = $flag;
422 63
            $this->options[CURLOPT_ENCODING] = 'gzip';
423
        } else
424
        {
425
            $this->_httpCompression = false;
426
            unset($this->options[CURLOPT_ENCODING]);
427
        }
428 63
    }
429
430
    /**
431
     * @param string $username
432
     * @param string $password
433
     * @return $this
434
     */
435 63
    public function auth($username, $password)
436
    {
437 63
        $this->options[CURLOPT_USERPWD] = sprintf("%s:%s", $username, $password);
438 63
        return $this;
439
    }
440
441
    /**
442
     * @param array|string $data
443
     * @return $this
444
     */
445 1
    public function parameters($data)
446
    {
447 1
        $this->parameters = $data;
448 1
        return $this;
449
    }
450
451
    /**
452
     * The maximum number of seconds (float) allowed to execute cURL functions.
453
     *
454
     * @param float $seconds
0 ignored issues
show
Method \ClickHouseDB\Transport\CurlerRequest::setTimeout() has useless @param annotation for parameter $seconds.
Loading history...
455
     * @return $this
456
     */
457 63
    public function setTimeout(float $seconds = 10) : self
458
    {
459 63
        $this->options[CURLOPT_TIMEOUT_MS] = (int) ($seconds * 1000);
0 ignored issues
show
Constant CURLOPT_TIMEOUT_MS should not be referenced via a fallback global name, but via a use statement.
Loading history...
460
461 63
        return $this;
462
    }
463
464
    /**
465
     * The number of seconds to wait when trying to connect. Use 0 for infinite waiting.
466
     */
467 63
    public function setConnectTimeout(float $seconds = 1) : self
468
    {
469 63
        $this->options[CURLOPT_CONNECTTIMEOUT_MS] = (int) ($seconds * 1000);
470
471 63
        return $this;
472
    }
473
474
    /**
475
     * @param array|mixed $data
476
     * @return $this
477
     * @throws \ClickHouseDB\Exception\TransportException
478
     */
479 63
    public function parameters_json($data)
480
    {
481
482 63
        $this->header("Content-Type", "application/json, text/javascript; charset=utf-8");
483 63
        $this->header("Accept", "application/json, text/javascript, */*; q=0.01");
484
485 63
        if ($data === null) {
486
            $this->parameters = '{}';
487
            return $this;
488
        }
489
490 63
        if (is_string($data)) {
491 63
            $this->parameters = $data;
492 63
            return $this;
493
        }
494
495
        $this->parameters = json_encode($data);
496
497
        if (!$this->parameters && $data) {
498
            throw new \ClickHouseDB\Exception\TransportException('Cant json_encode: ' . strval($data));
499
        }
500
501
        return $this;
502
    }
503
504
    /**
505
     * @return resource
506
     */
507
    public function getResultFileHandle()
508
    {
509
        return $this->resultFileHandle;
510
    }
511
512
    /**
513
     * @return bool
514
     */
515
    public function isResultFile()
516
    {
517
        return ($this->resultFileHandle ? true : false);
518
    }
519
520
    /**
521
     * @param resource $h resource
522
     * @param bool $zlib
523
     * @return $this
524
     */
525 1
    public function setResultFileHandle($h, $zlib = false)
526
    {
527 1
        $this->resultFileHandle = $h;
528 1
        if ($zlib) {
529
            $params = array('level' => 6, 'window' => 15, 'memory' => 9);
530
            stream_filter_append($this->resultFileHandle, 'zlib.deflate', STREAM_FILTER_WRITE, $params);
531
        }
532 1
        return $this;
533
    }
534
535
    /**
536
     * @return CurlerRequest
537
     */
538
    public function PUT()
539
    {
540
        return $this->execute('PUT');
541
    }
542
543
    /**
544
     * @return CurlerRequest
545
     */
546 63
    public function POST()
547
    {
548 63
        return $this->execute('POST');
549
    }
550
551
    /**
552
     * @return CurlerRequest
553
     */
554
    public function OPTIONS()
555
    {
556
        return $this->execute('OPTIONS');
557
    }
558
559
    /**
560
     * @return CurlerRequest
561
     */
562 39
    public function GET()
563
    {
564 39
        return $this->execute('GET');
565
    }
566
567
    /**
568
     * The number of seconds that DNS records are stored in memory. By default this parameter is 120 (2 minutes).
569
     *
570
     * @param integer $set
571
     * @return $this
572
     */
573
    public function setDnsCache($set)
574
    {
575
        $this->_dns_cache = $set;
576
        return $this;
577
    }
578
579
    /**
580
     * The number of seconds that DNS records are stored in memory. By default this parameter is 120 (2 minutes).
581
     *
582
     * @return int
583
     */
584 63
    public function getDnsCache()
585
    {
586 63
        return $this->_dns_cache;
587
    }
588
589
    /**
590
     * @param string $method
591
     * @return $this
592
     */
593 63
    private function execute($method)
594
    {
595 63
        $this->method = $method;
596 63
        return $this;
597
    }
598
599
    /**
600
     * @return CurlerResponse
601
     * @throws \ClickHouseDB\Exception\TransportException
602
     */
603 63
    public function response()
604
    {
605 63
        if (!$this->resp) {
606
            throw new \ClickHouseDB\Exception\TransportException('Can`t fetch response - is empty');
607
        }
608
609 63
        return $this->resp;
610
    }
611
612
    /**
613
     * @return bool
614
     */
615 29
    public function isResponseExists()
616
    {
617 29
        return ($this->resp ? true : false);
618
    }
619
620 63
    public function setResponse(CurlerResponse $response)
621
    {
622 63
        $this->resp = $response;
623 63
    }
624
625
    /**
626
     * @return mixed
627
     */
628 63
    public function handle()
629
    {
630 63
        $this->prepareRequest();
631 63
        return $this->handle;
632
    }
633
634
    /**
635
     * @param callable $callback
636
     * @throws \Exception
637
     */
638 1
    public function setFunctionProgress(callable $callback)
639
    {
640 1
        if (!is_callable($callback)) {
641
            throw new \Exception('setFunctionProgress not is_callable');
642
        }
643
644 1
        $this->option(CURLOPT_NOPROGRESS, false);
645 1
        $this->option(CURLOPT_PROGRESSFUNCTION, $callback); // version 5.5.0
646 1
    }
647
648
649
    /**
650
     * @return bool
651
     */
652 63
    private function prepareRequest()
653
    {
654 63
        if (!$this->handle) {
655 63
            $this->handle = curl_init();
656
        }
657
658 63
        $curl_opt = $this->options;
659 63
        $method = $this->method;
660
661 63
        if ($this->_attachFiles) {
662 1
            $curl_opt[CURLOPT_SAFE_UPLOAD] = true;
663
        }
664
665
666 63
        if (strtoupper($method) == 'GET') {
667 39
            $curl_opt[CURLOPT_HTTPGET] = TRUE;
0 ignored issues
show
TRUE, FALSE and NULL must be lowercase; expected true, but found TRUE.
Loading history...
668 39
            $curl_opt[CURLOPT_CUSTOMREQUEST] = strtoupper($method);
669 39
            $curl_opt[CURLOPT_POSTFIELDS] = false;
670
        } else {
671 63
            if (strtoupper($method) === 'POST') {
672 63
                $curl_opt[CURLOPT_POST] = TRUE;
673
            }
674
675 63
            $curl_opt[CURLOPT_CUSTOMREQUEST] = strtoupper($method);
676
677 63
            if ($this->parameters) {
678 63
                $curl_opt[CURLOPT_POSTFIELDS] = $this->parameters;
679
680 63
                if (!is_array($this->parameters)) {
681 63
                    $this->header('Content-Length', strlen($this->parameters));
682
                }
683
            }
684
        }
685
        // CURLOPT_DNS_CACHE_TIMEOUT - Количество секунд, в течение которых в памяти хранятся DNS-записи.
686 63
        $curl_opt[CURLOPT_DNS_CACHE_TIMEOUT] = $this->getDnsCache();
687 63
        $curl_opt[CURLOPT_URL] = $this->url;
688
689 63
        if (!empty($this->headers) && sizeof($this->headers)) {
690 63
            $curl_opt[CURLOPT_HTTPHEADER] = array();
691
692 63
            foreach ($this->headers as $key => $value) {
693 63
                $curl_opt[CURLOPT_HTTPHEADER][] = sprintf("%s: %s", $key, $value);
694
            }
695
        }
696
697 63
        if (!empty($curl_opt[CURLOPT_INFILE])) {
698
699 8
            $curl_opt[CURLOPT_PUT] = true;
700
        }
701
702 63
        if (!empty($curl_opt[CURLOPT_WRITEFUNCTION]))
703
        {
704 1
            $curl_opt[CURLOPT_HEADER]=false;
705
        }
706
707 63
        if ($this->resultFileHandle) {
708 1
            $curl_opt[CURLOPT_FILE] = $this->resultFileHandle;
709 1
            $curl_opt[CURLOPT_HEADER] = false;
710
        }
711
712 63
        if ($this->options[CURLOPT_VERBOSE]) {
713
            echo "\n-----------BODY REQUEST----------\n" . $curl_opt[CURLOPT_POSTFIELDS] . "\n------END--------\n";
714
        }
715 63
        curl_setopt_array($this->handle, $curl_opt);
716 63
        return true;
717
    }
718
}
719