Passed
Push — master ( 7b4f81...84e0ca )
by Igor
03:22
created

CurlerRequest   F

Complexity

Total Complexity 85

Size/Duplication

Total Lines 726
Duplicated Lines 0 %

Test Coverage

Coverage 74.27%

Importance

Changes 0
Metric Value
wmc 85
dl 0
loc 726
ccs 179
cts 241
cp 0.7427
rs 1.874
c 0
b 0
f 0

50 Methods

Rating   Name   Duplication   Size   Complexity  
A close() 0 7 2
A id() 0 7 2
A __destruct() 0 3 1
A __construct() 0 21 1
A getInfileHandle() 0 3 1
A attachFiles() 0 11 2
A setRequestExtendedInfo() 0 4 1
A getRequestExtendedInfo() 0 7 3
A setInfile() 0 22 3
A setCallbackFunction() 0 3 1
A keepAlive() 0 7 1
A httpCompression() 0 9 2
A getUniqHash() 0 3 1
A isResultFile() 0 3 2
A parameters_json() 0 23 5
A setReadFunction() 0 3 1
A isPersistent() 0 3 1
A dump() 0 15 2
F prepareRequest() 0 65 14
A GET() 0 3 1
A url() 0 4 1
A getId() 0 3 1
A getResultFileHandle() 0 3 1
A setResponse() 0 3 1
A execute() 0 4 1
A OPTIONS() 0 3 1
A timeOut() 0 3 1
A auth() 0 4 1
A timeOutMs() 0 4 1
A persistent() 0 4 1
A setWriteFunction() 0 3 1
A getUrl() 0 3 1
A setFunctionProgress() 0 8 2
A isResponseExists() 0 3 2
A header() 0 4 1
A onCallback() 0 10 4
A getHeaders() 0 7 2
A parameters() 0 4 1
A connectTimeOut() 0 4 1
A option() 0 4 1
A handle() 0 4 1
A POST() 0 3 1
A setCallback() 0 4 1
A response() 0 7 2
A verbose() 0 4 1
A getDnsCache() 0 3 1
A setDnsCache() 0 4 1
A setHeaderFunction() 0 3 1
A PUT() 0 3 1
A setResultFileHandle() 0 8 2

How to fix   Complexity   

Complex Class

Complex classes like CurlerRequest often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use CurlerRequest, and based on these observations, apply Extract Interface, too.

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