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

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