Failed Conditions
Push — master ( 20fa9e...5a0a45 )
by Igor
03:28 queued 10s
created

src/Transport/CurlerRequest.php (12 issues)

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

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
699 37
            $curl_opt[CURLOPT_CUSTOMREQUEST] = strtoupper($method);
700 37
            $curl_opt[CURLOPT_POSTFIELDS] = false;
701
        } else {
702 39
            if (strtoupper($method) === 'POST') {
703 39
                $curl_opt[CURLOPT_POST] = true;
704
            }
705
706 39
            $curl_opt[CURLOPT_CUSTOMREQUEST] = strtoupper($method);
707
708 39
            if ($this->parameters) {
709 39
                $curl_opt[CURLOPT_POSTFIELDS] = $this->parameters;
710
711 39
                if (!is_array($this->parameters)) {
712 39
                    $this->header('Content-Length', strlen($this->parameters));
713
                }
714
            }
715
        }
716
        // CURLOPT_DNS_CACHE_TIMEOUT - Количество секунд, в течение которых в памяти хранятся DNS-записи.
717 48
        $curl_opt[CURLOPT_DNS_CACHE_TIMEOUT] = $this->getDnsCache();
718 48
        $curl_opt[CURLOPT_URL] = $this->url;
719
720 48
        if (!empty($this->headers) && sizeof($this->headers)) {
721 48
            $curl_opt[CURLOPT_HTTPHEADER] = array();
722
723 48
            foreach ($this->headers as $key => $value) {
724 48
                $curl_opt[CURLOPT_HTTPHEADER][] = sprintf("%s: %s", $key, $value);
725
            }
726
        }
727
728 48
        if (!empty($curl_opt[CURLOPT_INFILE])) {
729
730 8
            $curl_opt[CURLOPT_PUT] = true;
731
        }
732
733 48
        if (!empty($curl_opt[CURLOPT_WRITEFUNCTION])) {
734 1
            $curl_opt[CURLOPT_HEADER] = false;
735
        }
736
737 48
        if ($this->resultFileHandle) {
738 1
            $curl_opt[CURLOPT_FILE] = $this->resultFileHandle;
739 1
            $curl_opt[CURLOPT_HEADER] = false;
740
        }
741
742 48
        if ($this->options[CURLOPT_VERBOSE]) {
743
            echo "\n-----------BODY REQUEST----------\n" . $curl_opt[CURLOPT_POSTFIELDS] . "\n------END--------\n";
744
        }
745 48
        curl_setopt_array($this->handle, $curl_opt);
746 48
        return true;
747
    }
748
}
749