1 | <?php |
||||
0 ignored issues
–
show
introduced
by
![]() |
|||||
2 | |||||
3 | namespace ClickHouseDB\Transport; |
||||
4 | |||||
5 | use ClickHouseDB\Exception\TransportException; |
||||
6 | use ClickHouseDB\Query\Degeneration; |
||||
7 | use ClickHouseDB\Query\Query; |
||||
8 | use ClickHouseDB\Query\WhereInFile; |
||||
9 | use ClickHouseDB\Query\WriteToFile; |
||||
10 | use ClickHouseDB\Settings; |
||||
11 | use ClickHouseDB\Statement; |
||||
12 | use const PHP_EOL; |
||||
0 ignored issues
–
show
|
|||||
13 | |||||
14 | class Http |
||||
15 | { |
||||
16 | const AUTH_METHOD_HEADER = 1; |
||||
0 ignored issues
–
show
|
|||||
17 | const AUTH_METHOD_QUERY_STRING = 2; |
||||
0 ignored issues
–
show
|
|||||
18 | const AUTH_METHOD_BASIC_AUTH = 3; |
||||
0 ignored issues
–
show
|
|||||
19 | |||||
20 | const AUTH_METHODS_LIST = [ |
||||
0 ignored issues
–
show
|
|||||
21 | self::AUTH_METHOD_HEADER, |
||||
22 | self::AUTH_METHOD_QUERY_STRING, |
||||
23 | self::AUTH_METHOD_BASIC_AUTH, |
||||
24 | ]; |
||||
25 | |||||
26 | /** |
||||
0 ignored issues
–
show
|
|||||
27 | * @var string |
||||
28 | */ |
||||
29 | private $_username = null; |
||||
30 | |||||
31 | /** |
||||
0 ignored issues
–
show
|
|||||
32 | * @var string |
||||
33 | */ |
||||
34 | private $_password = null; |
||||
35 | |||||
36 | /** |
||||
37 | * The username and password can be indicated in one of three ways: |
||||
38 | * - Using HTTP Basic Authentication. |
||||
39 | * - In the ‘user’ and ‘password’ URL parameters. |
||||
40 | * - Using ‘X-ClickHouse-User’ and ‘X-ClickHouse-Key’ headers (by default) |
||||
41 | * |
||||
42 | * @see https://clickhouse.tech/docs/en/interfaces/http/ |
||||
0 ignored issues
–
show
|
|||||
43 | * @var int |
||||
44 | */ |
||||
45 | private $_authMethod = self::AUTH_METHOD_HEADER; |
||||
46 | |||||
47 | /** |
||||
0 ignored issues
–
show
|
|||||
48 | * @var string |
||||
49 | */ |
||||
50 | private $_host = ''; |
||||
51 | |||||
52 | /** |
||||
0 ignored issues
–
show
|
|||||
53 | * @var int |
||||
54 | */ |
||||
55 | private $_port = 0; |
||||
56 | |||||
57 | /** |
||||
0 ignored issues
–
show
|
|||||
58 | * @var bool|int |
||||
59 | */ |
||||
60 | private $_verbose = false; |
||||
61 | |||||
62 | /** |
||||
0 ignored issues
–
show
|
|||||
63 | * @var CurlerRolling |
||||
64 | */ |
||||
65 | private $_curler = null; |
||||
66 | |||||
67 | /** |
||||
0 ignored issues
–
show
|
|||||
68 | * @var Settings |
||||
69 | */ |
||||
70 | private $_settings = null; |
||||
71 | |||||
72 | /** |
||||
0 ignored issues
–
show
|
|||||
73 | * @var array |
||||
0 ignored issues
–
show
|
|||||
74 | */ |
||||
75 | private $_query_degenerations = []; |
||||
0 ignored issues
–
show
|
|||||
76 | |||||
77 | /** |
||||
78 | * Count seconds (int) |
||||
79 | * |
||||
80 | * @var float |
||||
81 | */ |
||||
82 | private $_connectTimeOut = 5.0; |
||||
83 | |||||
84 | /** |
||||
0 ignored issues
–
show
|
|||||
85 | * @var callable |
||||
86 | */ |
||||
87 | private $xClickHouseProgress = null; |
||||
88 | |||||
89 | /** |
||||
0 ignored issues
–
show
|
|||||
90 | * @var null|string |
||||
0 ignored issues
–
show
|
|||||
91 | */ |
||||
92 | private $sslCA = null; |
||||
93 | |||||
94 | /** |
||||
0 ignored issues
–
show
|
|||||
95 | * @var null|resource |
||||
0 ignored issues
–
show
|
|||||
96 | */ |
||||
97 | private $stdErrOut = null; |
||||
98 | /** |
||||
99 | * Http constructor. |
||||
0 ignored issues
–
show
|
|||||
100 | * @param string $host |
||||
0 ignored issues
–
show
|
|||||
101 | * @param int $port |
||||
0 ignored issues
–
show
|
|||||
102 | 68 | * @param string $username |
|||
103 | * @param string $password |
||||
104 | 68 | * @param int $authMethod |
|||
0 ignored issues
–
show
|
|||||
105 | */ |
||||
106 | 68 | public function __construct($host, $port, $username, $password, $authMethod = null) |
|||
0 ignored issues
–
show
|
|||||
107 | 68 | { |
|||
108 | 68 | $this->setHost($host, $port); |
|||
109 | |||||
110 | $this->_username = $username; |
||||
111 | $this->_password = $password; |
||||
112 | 68 | if ($authMethod) { |
|||
0 ignored issues
–
show
The expression
$authMethod of type integer|null is loosely compared to true ; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.
In PHP, under loose comparison (like For 0 == false // true
0 == null // true
123 == false // false
123 == null // false
// It is often better to use strict comparison
0 === false // false
0 === null // false
![]() |
|||||
113 | $this->_authMethod = $authMethod; |
||||
114 | 68 | } |
|||
115 | 68 | ||||
116 | $this->_settings = new Settings(); |
||||
117 | |||||
118 | 68 | $this->setCurler(); |
|||
119 | } |
||||
0 ignored issues
–
show
|
|||||
120 | 68 | ||||
121 | 68 | ||||
122 | public function setCurler() : void |
||||
0 ignored issues
–
show
|
|||||
123 | { |
||||
124 | $this->_curler = new CurlerRolling(); |
||||
125 | } |
||||
126 | |||||
127 | /** |
||||
128 | * @param CurlerRolling $curler |
||||
0 ignored issues
–
show
|
|||||
129 | */ |
||||
130 | public function setDirtyCurler(CurlerRolling $curler) : void |
||||
0 ignored issues
–
show
|
|||||
131 | { |
||||
132 | if ($curler instanceof CurlerRolling) { |
||||
0 ignored issues
–
show
|
|||||
133 | $this->_curler = $curler; |
||||
134 | } |
||||
135 | } |
||||
136 | |||||
137 | /** |
||||
138 | * @return CurlerRolling |
||||
0 ignored issues
–
show
|
|||||
139 | */ |
||||
140 | public function getCurler(): ?CurlerRolling |
||||
0 ignored issues
–
show
|
|||||
141 | { |
||||
142 | return $this->_curler; |
||||
143 | } |
||||
144 | |||||
145 | 68 | /** |
|||
146 | * @param string $host |
||||
0 ignored issues
–
show
|
|||||
147 | 68 | * @param int $port |
|||
0 ignored issues
–
show
|
|||||
148 | 68 | */ |
|||
149 | public function setHost(string $host, int $port = -1) : void |
||||
0 ignored issues
–
show
|
|||||
150 | { |
||||
151 | 68 | if ($port > 0) { |
|||
152 | 68 | $this->_port = $port; |
|||
153 | } |
||||
154 | |||||
155 | $this->_host = $host; |
||||
156 | } |
||||
157 | |||||
158 | /** |
||||
159 | * Sets client SSL certificate for Yandex Cloud |
||||
160 | * |
||||
161 | * @param string $caPath |
||||
0 ignored issues
–
show
|
|||||
162 | */ |
||||
163 | public function setSslCa(string $caPath) : void |
||||
0 ignored issues
–
show
|
|||||
164 | { |
||||
165 | $this->sslCA = $caPath; |
||||
166 | } |
||||
167 | 55 | ||||
168 | /** |
||||
169 | 55 | * @return string |
|||
0 ignored issues
–
show
|
|||||
170 | 55 | */ |
|||
171 | 1 | public function getUri(): string |
|||
0 ignored issues
–
show
|
|||||
172 | { |
||||
173 | 55 | $proto = 'http'; |
|||
174 | 55 | if ($this->settings()->isHttps()) { |
|||
0 ignored issues
–
show
|
|||||
175 | 1 | $proto = 'https'; |
|||
176 | } |
||||
177 | 55 | $uri = $proto . '://' . $this->_host; |
|||
178 | 55 | if (stripos($this->_host, '/') !== false || stripos($this->_host, ':') !== false) { |
|||
0 ignored issues
–
show
|
|||||
179 | return $uri; |
||||
180 | 1 | } |
|||
181 | if (intval($this->_port) > 0) { |
||||
0 ignored issues
–
show
|
|||||
182 | return $uri . ':' . $this->_port; |
||||
183 | } |
||||
184 | return $uri; |
||||
0 ignored issues
–
show
|
|||||
185 | } |
||||
186 | 68 | ||||
187 | /** |
||||
188 | 68 | * @return Settings |
|||
0 ignored issues
–
show
|
|||||
189 | */ |
||||
190 | public function settings(): Settings |
||||
0 ignored issues
–
show
|
|||||
191 | { |
||||
192 | return $this->_settings; |
||||
193 | } |
||||
194 | |||||
195 | /** |
||||
196 | * @param bool $flag |
||||
0 ignored issues
–
show
|
|||||
197 | * @return bool |
||||
0 ignored issues
–
show
|
|||||
198 | */ |
||||
199 | public function verbose(bool $flag): bool |
||||
0 ignored issues
–
show
|
|||||
200 | { |
||||
201 | $this->_verbose = $flag; |
||||
202 | return $flag; |
||||
0 ignored issues
–
show
|
|||||
203 | } |
||||
204 | |||||
205 | 45 | /** |
|||
206 | * @param array $params |
||||
0 ignored issues
–
show
|
|||||
207 | 45 | * @return string |
|||
0 ignored issues
–
show
|
|||||
208 | */ |
||||
209 | 45 | private function getUrl($params = []): string |
|||
0 ignored issues
–
show
|
|||||
210 | 45 | { |
|||
211 | $settings = $this->settings()->getSettings(); |
||||
212 | |||||
213 | if (is_array($params) && sizeof($params)) { |
||||
0 ignored issues
–
show
|
|||||
214 | 45 | $settings = array_merge($settings, $params); |
|||
0 ignored issues
–
show
|
|||||
215 | } |
||||
216 | |||||
0 ignored issues
–
show
|
|||||
217 | |||||
218 | if ($this->settings()->isReadOnlyUser()) { |
||||
219 | unset($settings['extremes']); |
||||
220 | unset($settings['readonly']); |
||||
221 | unset($settings['enable_http_compression']); |
||||
222 | 45 | unset($settings['max_execution_time']); |
|||
223 | |||||
0 ignored issues
–
show
|
|||||
224 | } |
||||
225 | 45 | ||||
226 | unset($settings['https']); |
||||
227 | |||||
0 ignored issues
–
show
|
|||||
228 | |||||
229 | return $this->getUri() . '?' . http_build_query($settings); |
||||
0 ignored issues
–
show
|
|||||
230 | } |
||||
231 | |||||
232 | 45 | /** |
|||
233 | * @param array $extendinfo |
||||
0 ignored issues
–
show
|
|||||
234 | 45 | * @return CurlerRequest |
|||
0 ignored issues
–
show
|
|||||
235 | */ |
||||
236 | 45 | private function newRequest($extendinfo): CurlerRequest |
|||
0 ignored issues
–
show
|
|||||
237 | 45 | { |
|||
238 | $new = new CurlerRequest(); |
||||
239 | |||||
240 | switch ($this->_authMethod) { |
||||
241 | case self::AUTH_METHOD_QUERY_STRING: |
||||
242 | /* @todo: Move this implementation to CurlerRequest class. Possible options: the authentication method |
||||
243 | * should be applied in method `CurlerRequest:prepareRequest()`. |
||||
244 | 45 | */ |
|||
245 | $this->settings()->set('user', $this->_username); |
||||
246 | $this->settings()->set('password', $this->_password); |
||||
247 | break; |
||||
248 | case self::AUTH_METHOD_BASIC_AUTH: |
||||
249 | 45 | $new->authByBasicAuth($this->_username, $this->_password); |
|||
250 | 45 | break; |
|||
251 | default: |
||||
252 | // Auth with headers by default |
||||
253 | 45 | $new->authByHeaders($this->_username, $this->_password); |
|||
254 | break; |
||||
255 | 45 | } |
|||
256 | 45 | ||||
257 | $new->POST()->setRequestExtendedInfo($extendinfo); |
||||
258 | 45 | ||||
259 | 1 | $new->httpCompression($this->settings()->isEnableHttpCompression()); |
|||
0 ignored issues
–
show
It seems like
$this->settings()->isEnableHttpCompression() can also be of type null ; however, parameter $flag of ClickHouseDB\Transport\C...uest::httpCompression() does only seem to accept boolean , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
260 | |||||
261 | 45 | if ($this->settings()->getSessionId()) { |
|||
0 ignored issues
–
show
|
|||||
262 | $new->persistent(); |
||||
263 | } |
||||
264 | if ($this->sslCA) { |
||||
265 | 45 | $new->setSslCa($this->sslCA); |
|||
266 | 45 | } |
|||
267 | 45 | ||||
268 | $new->timeOut($this->settings()->getTimeOut()); |
||||
269 | 45 | $new->connectTimeOut($this->_connectTimeOut);//->keepAlive(); // one sec |
|||
270 | $new->verbose(boolval($this->_verbose)); |
||||
0 ignored issues
–
show
|
|||||
271 | |||||
272 | return $new; |
||||
273 | } |
||||
274 | |||||
275 | /** |
||||
276 | * @param Query $query |
||||
0 ignored issues
–
show
|
|||||
277 | * @param array $urlParams |
||||
0 ignored issues
–
show
|
|||||
278 | * @param bool $query_as_string |
||||
0 ignored issues
–
show
|
|||||
279 | 45 | * @return CurlerRequest |
|||
0 ignored issues
–
show
|
|||||
280 | * @throws \ClickHouseDB\Exception\TransportException |
||||
0 ignored issues
–
show
|
|||||
281 | 45 | */ |
|||
282 | private function makeRequest(Query $query, array $urlParams = [], bool $query_as_string = false): CurlerRequest |
||||
0 ignored issues
–
show
|
|||||
283 | 45 | { |
|||
284 | 1 | $sql = $query->toSql(); |
|||
285 | |||||
286 | if ($query_as_string) { |
||||
0 ignored issues
–
show
|
|||||
287 | $urlParams['query'] = $sql; |
||||
288 | 45 | } |
|||
289 | 45 | ||||
290 | 45 | $extendInfo = [ |
|||
291 | 'sql' => $sql, |
||||
292 | 'query' => $query, |
||||
293 | 45 | 'format' => $query->getFormat() |
|||
0 ignored issues
–
show
|
|||||
294 | ]; |
||||
295 | |||||
296 | $new = $this->newRequest($extendInfo); |
||||
297 | |||||
298 | /* |
||||
299 | 45 | * Build URL after request making, since URL may contain auth data. This will not matter after the |
|||
300 | 45 | * implantation of the todo in the `HTTP:newRequest()` method. |
|||
301 | */ |
||||
302 | |||||
303 | 45 | if ($query->isUseInUrlBindingsParams()) { |
|||
304 | 45 | $urlParams = array_replace_recursive($urlParams, $query->getUrlBindingsParams()); |
|||
0 ignored issues
–
show
|
|||||
305 | } |
||||
306 | 45 | ||||
307 | 45 | $url = $this->getUrl($urlParams); |
|||
308 | $new->url($url); |
||||
309 | |||||
310 | 45 | if (!$query_as_string) { |
|||
0 ignored issues
–
show
|
|||||
311 | $new->parameters_json($sql); |
||||
312 | } |
||||
313 | $new->httpCompression($this->settings()->isEnableHttpCompression()); |
||||
0 ignored issues
–
show
It seems like
$this->settings()->isEnableHttpCompression() can also be of type null ; however, parameter $flag of ClickHouseDB\Transport\C...uest::httpCompression() does only seem to accept boolean , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
314 | |||||
315 | return $new; |
||||
316 | } |
||||
317 | 3 | ||||
318 | /** |
||||
319 | * @param resource $stream |
||||
0 ignored issues
–
show
|
|||||
320 | 3 | * @return void |
|||
321 | 1 | */ |
|||
322 | public function setStdErrOut($stream) |
||||
0 ignored issues
–
show
|
|||||
323 | 2 | { |
|||
324 | if (is_resource($stream)) { |
||||
0 ignored issues
–
show
|
|||||
325 | $this->stdErrOut=$stream; |
||||
0 ignored issues
–
show
|
|||||
326 | } |
||||
327 | 3 | ||||
328 | 3 | } |
|||
0 ignored issues
–
show
|
|||||
329 | 3 | ||||
330 | /** |
||||
331 | * @param string|Query $sql |
||||
0 ignored issues
–
show
|
|||||
332 | 3 | * @return CurlerRequest |
|||
0 ignored issues
–
show
|
|||||
333 | */ |
||||
334 | public function writeStreamData($sql): CurlerRequest |
||||
335 | { |
||||
0 ignored issues
–
show
|
|||||
336 | |||||
337 | if ($sql instanceof Query) { |
||||
338 | 3 | $query = $sql; |
|||
339 | 3 | } else { |
|||
340 | 3 | $query = new Query($sql); |
|||
341 | } |
||||
342 | |||||
343 | 3 | $extendInfo = [ |
|||
344 | 3 | 'sql' => $sql, |
|||
345 | 'query' => $query, |
||||
346 | 'format' => $query->getFormat() |
||||
0 ignored issues
–
show
|
|||||
347 | ]; |
||||
348 | |||||
349 | $request = $this->newRequest($extendInfo); |
||||
350 | |||||
351 | /* |
||||
352 | * Build URL after request making, since URL may contain auth data. This will not matter after the |
||||
353 | * implantation of the todo in the `HTTP:newRequest()` method. |
||||
354 | 8 | */ |
|||
355 | $url = $this->getUrl([ |
||||
356 | 8 | 'readonly' => 0, |
|||
357 | 'query' => $query->toSql() |
||||
0 ignored issues
–
show
|
|||||
358 | ]); |
||||
359 | 8 | ||||
360 | 8 | $request->url($url); |
|||
361 | 8 | return $request; |
|||
0 ignored issues
–
show
|
|||||
362 | } |
||||
0 ignored issues
–
show
|
|||||
363 | |||||
364 | 8 | ||||
365 | /** |
||||
366 | * @param string $sql |
||||
0 ignored issues
–
show
|
|||||
367 | * @param string $file_name |
||||
368 | * @return Statement |
||||
0 ignored issues
–
show
|
|||||
369 | * @throws \ClickHouseDB\Exception\TransportException |
||||
0 ignored issues
–
show
|
|||||
370 | 8 | */ |
|||
371 | 8 | public function writeAsyncCSV($sql, $file_name): Statement |
|||
0 ignored issues
–
show
|
|||||
372 | 8 | { |
|||
373 | $query = new Query($sql); |
||||
374 | |||||
375 | 8 | $extendinfo = [ |
|||
376 | 'sql' => $sql, |
||||
377 | 8 | 'query' => $query, |
|||
378 | 8 | 'format' => $query->getFormat() |
|||
0 ignored issues
–
show
|
|||||
379 | 8 | ]; |
|||
380 | 8 | ||||
381 | $request = $this->newRequest($extendinfo); |
||||
382 | 8 | ||||
383 | /* |
||||
384 | 8 | * Build URL after request making, since URL may contain auth data. This will not matter after the |
|||
385 | 8 | * implantation of the todo in the `HTTP:newRequest()` method. |
|||
386 | */ |
||||
387 | 8 | $url = $this->getUrl([ |
|||
388 | 'readonly' => 0, |
||||
389 | 'query' => $query->toSql() |
||||
0 ignored issues
–
show
|
|||||
390 | ]); |
||||
391 | |||||
392 | $request->url($url); |
||||
393 | |||||
394 | $request->setCallbackFunction(function (CurlerRequest $request) { |
||||
0 ignored issues
–
show
|
|||||
395 | 12 | $handle = $request->getInfileHandle(); |
|||
396 | if (is_resource($handle)) { |
||||
0 ignored issues
–
show
|
|||||
397 | 12 | fclose($handle); |
|||
0 ignored issues
–
show
|
|||||
398 | } |
||||
399 | }); |
||||
400 | |||||
401 | $request->setInfile($file_name); |
||||
0 ignored issues
–
show
|
|||||
402 | $this->_curler->addQueLoop($request); |
||||
403 | |||||
404 | return new Statement($request); |
||||
405 | 2 | } |
|||
406 | |||||
407 | 2 | /** |
|||
408 | 2 | * get Count Pending Query in Queue |
|||
409 | * |
||||
410 | * @return int |
||||
0 ignored issues
–
show
|
|||||
411 | */ |
||||
412 | public function getCountPendingQueue(): int |
||||
413 | { |
||||
414 | return $this->_curler->countPending(); |
||||
415 | 38 | } |
|||
416 | |||||
417 | 38 | /** |
|||
418 | * set Connect TimeOut in seconds [CURLOPT_CONNECTTIMEOUT] ( int ) |
||||
419 | * |
||||
420 | * @param float $connectTimeOut |
||||
0 ignored issues
–
show
|
|||||
421 | 1 | */ |
|||
422 | public function setConnectTimeOut(float $connectTimeOut) |
||||
0 ignored issues
–
show
|
|||||
423 | 1 | { |
|||
424 | $this->_connectTimeOut = $connectTimeOut; |
||||
425 | } |
||||
426 | 1 | ||||
427 | 1 | /** |
|||
428 | 1 | * get ConnectTimeOut in seconds |
|||
429 | 1 | * |
|||
430 | * @return float |
||||
0 ignored issues
–
show
|
|||||
431 | */ |
||||
432 | public function getConnectTimeOut(): float |
||||
433 | 1 | { |
|||
434 | 1 | return $this->_connectTimeOut; |
|||
435 | } |
||||
0 ignored issues
–
show
|
|||||
436 | |||||
437 | |||||
438 | 1 | public function __findXClickHouseProgress($handle): bool |
|||
0 ignored issues
–
show
|
|||||
439 | 1 | { |
|||
440 | $code = curl_getinfo($handle, CURLINFO_HTTP_CODE); |
||||
0 ignored issues
–
show
|
|||||
441 | |||||
442 | // Search X-ClickHouse-Progress |
||||
443 | 1 | if ($code == 200) { |
|||
0 ignored issues
–
show
|
|||||
444 | 1 | $response = curl_multi_getcontent($handle); |
|||
0 ignored issues
–
show
Equals sign not aligned with surrounding assignments; expected 4 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. ![]() |
|||||
445 | $header_size = curl_getinfo($handle, CURLINFO_HEADER_SIZE); |
||||
0 ignored issues
–
show
|
|||||
446 | 1 | if (!$header_size) { |
|||
0 ignored issues
–
show
|
|||||
447 | return false; |
||||
448 | 1 | } |
|||
449 | |||||
450 | $header = substr($response, 0, $header_size); |
||||
0 ignored issues
–
show
|
|||||
451 | 1 | if (!$header) { |
|||
0 ignored issues
–
show
|
|||||
452 | return false; |
||||
453 | } |
||||
454 | |||||
455 | $match = []; |
||||
456 | if (preg_match_all('/^X-ClickHouse-(?:Progress|Summary):(.*?)$/im', $header, $match)) { |
||||
0 ignored issues
–
show
|
|||||
457 | $data = @json_decode(end($match[1]), true); |
||||
0 ignored issues
–
show
|
|||||
458 | 1 | if ($data && is_callable($this->xClickHouseProgress)) { |
|||
0 ignored issues
–
show
|
|||||
459 | |||||
460 | if (is_array($this->xClickHouseProgress)) { |
||||
0 ignored issues
–
show
|
|||||
461 | call_user_func_array($this->xClickHouseProgress, [$data]); |
||||
0 ignored issues
–
show
|
|||||
462 | } else { |
||||
463 | call_user_func($this->xClickHouseProgress, $data); |
||||
0 ignored issues
–
show
|
|||||
464 | } |
||||
465 | |||||
0 ignored issues
–
show
|
|||||
466 | } |
||||
467 | } |
||||
468 | 40 | } |
|||
469 | return false; |
||||
0 ignored issues
–
show
|
|||||
470 | 40 | } |
|||
471 | 40 | ||||
472 | /** |
||||
473 | 40 | * @param Query $query |
|||
0 ignored issues
–
show
|
|||||
474 | * @param null|WhereInFile $whereInFile |
||||
0 ignored issues
–
show
|
|||||
475 | 1 | * @param null|WriteToFile $writeToFile |
|||
0 ignored issues
–
show
|
|||||
476 | * @return CurlerRequest |
||||
0 ignored issues
–
show
|
|||||
477 | 1 | * @throws \Exception |
|||
0 ignored issues
–
show
|
|||||
478 | 1 | */ |
|||
479 | public function getRequestRead(Query $query, $whereInFile = null, $writeToFile = null): CurlerRequest |
||||
0 ignored issues
–
show
|
|||||
480 | { |
||||
481 | $urlParams = ['readonly' => 2]; |
||||
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. ![]() |
|||||
482 | 40 | $query_as_string = false; |
|||
0 ignored issues
–
show
|
|||||
483 | 1 | // --------------------------------------------------------------------------------- |
|||
484 | 1 | if ($whereInFile instanceof WhereInFile && $whereInFile->size()) { |
|||
0 ignored issues
–
show
|
|||||
485 | // $request = $this->prepareSelectWhereIn($request, $whereInFile); |
||||
486 | $structure = $whereInFile->fetchUrlParams(); |
||||
487 | // $structure = []; |
||||
488 | 40 | $urlParams = array_merge($urlParams, $structure); |
|||
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. ![]() |
|||||
489 | $query_as_string = true; |
||||
0 ignored issues
–
show
|
|||||
490 | } |
||||
491 | 40 | // --------------------------------------------------------------------------------- |
|||
492 | 1 | // if result to file |
|||
493 | if ($writeToFile instanceof WriteToFile && $writeToFile->fetchFormat()) { |
||||
0 ignored issues
–
show
|
|||||
494 | $query->setFormat($writeToFile->fetchFormat()); |
||||
495 | unset($urlParams['extremes']); |
||||
496 | 40 | } |
|||
497 | // --------------------------------------------------------------------------------- |
||||
498 | 1 | // makeRequest read |
|||
499 | 1 | $request = $this->makeRequest($query, $urlParams, $query_as_string); |
|||
0 ignored issues
–
show
|
|||||
500 | // --------------------------------------------------------------------------------- |
||||
501 | 1 | // attach files |
|||
502 | if ($whereInFile instanceof WhereInFile && $whereInFile->size()) { |
||||
0 ignored issues
–
show
|
|||||
503 | 1 | $request->attachFiles($whereInFile->fetchFiles()); |
|||
504 | } |
||||
505 | // --------------------------------------------------------------------------------- |
||||
506 | // result to file |
||||
507 | if ($writeToFile instanceof WriteToFile && $writeToFile->fetchFormat()) { |
||||
0 ignored issues
–
show
|
|||||
508 | |||||
509 | $fout = fopen($writeToFile->fetchFile(), 'w'); |
||||
0 ignored issues
–
show
|
|||||
510 | if (is_resource($fout)) { |
||||
0 ignored issues
–
show
|
|||||
511 | |||||
512 | $isGz = $writeToFile->getGzip(); |
||||
513 | |||||
514 | if ($isGz) { |
||||
0 ignored issues
–
show
|
|||||
515 | // write gzip header |
||||
516 | 1 | // "\x1f\x8b\x08\x00\x00\x00\x00\x00" |
|||
517 | // fwrite($fout, "\x1F\x8B\x08\x08".pack("V", time())."\0\xFF", 10); |
||||
518 | 1 | // write the original file name |
|||
519 | // $oname = str_replace("\0", "", basename($writeToFile->fetchFile())); |
||||
520 | // fwrite($fout, $oname."\0", 1+strlen($oname)); |
||||
521 | 40 | ||||
522 | 1 | fwrite($fout, "\x1f\x8b\x08\x00\x00\x00\x00\x00"); |
|||
0 ignored issues
–
show
|
|||||
523 | |||||
0 ignored issues
–
show
|
|||||
524 | } |
||||
525 | 40 | ||||
0 ignored issues
–
show
|
|||||
526 | |||||
527 | $request->setResultFileHandle($fout, $isGz)->setCallbackFunction(function (CurlerRequest $request) { |
||||
0 ignored issues
–
show
|
|||||
528 | fclose($request->getResultFileHandle()); |
||||
0 ignored issues
–
show
|
|||||
529 | 1 | }); |
|||
530 | } |
||||
531 | 1 | } |
|||
532 | 1 | ||||
533 | if ($this->stdErrOut) { |
||||
0 ignored issues
–
show
|
|||||
534 | $request->setStdErrOut($this->stdErrOut); |
||||
535 | 68 | } |
|||
536 | if ($this->xClickHouseProgress) { |
||||
0 ignored issues
–
show
|
|||||
537 | 68 | $request->setFunctionProgress([$this, '__findXClickHouseProgress']); |
|||
538 | 68 | } |
|||
539 | // --------------------------------------------------------------------------------- |
||||
540 | return $request; |
||||
0 ignored issues
–
show
|
|||||
541 | |||||
542 | } |
||||
0 ignored issues
–
show
|
|||||
543 | |||||
544 | public function cleanQueryDegeneration(): bool |
||||
545 | { |
||||
546 | 27 | $this->_query_degenerations = []; |
|||
0 ignored issues
–
show
|
|||||
547 | return true; |
||||
0 ignored issues
–
show
|
|||||
548 | 27 | } |
|||
549 | 27 | ||||
550 | public function addQueryDegeneration(Degeneration $degeneration): bool |
||||
551 | { |
||||
552 | $this->_query_degenerations[] = $degeneration; |
||||
0 ignored issues
–
show
|
|||||
553 | return true; |
||||
0 ignored issues
–
show
|
|||||
554 | } |
||||
555 | 38 | ||||
556 | /** |
||||
557 | 38 | * @param Query $query |
|||
0 ignored issues
–
show
|
|||||
558 | 38 | * @return CurlerRequest |
|||
0 ignored issues
–
show
|
|||||
559 | 38 | * @throws \ClickHouseDB\Exception\TransportException |
|||
0 ignored issues
–
show
|
|||||
560 | */ |
||||
561 | 38 | public function getRequestWrite(Query $query): CurlerRequest |
|||
562 | { |
||||
563 | $urlParams = ['readonly' => 0]; |
||||
564 | return $this->makeRequest($query, $urlParams); |
||||
0 ignored issues
–
show
|
|||||
565 | } |
||||
566 | |||||
567 | /** |
||||
568 | * @throws TransportException |
||||
569 | 46 | */ |
|||
570 | public function ping(): bool |
||||
571 | { |
||||
572 | $request = new CurlerRequest(); |
||||
573 | 46 | $request->url($this->getUri())->verbose(false)->GET()->connectTimeOut($this->getConnectTimeOut()); |
|||
574 | 46 | $this->_curler->execOne($request); |
|||
575 | |||||
576 | return trim($request->response()->body()) === 'Ok.'; |
||||
0 ignored issues
–
show
|
|||||
577 | 46 | } |
|||
578 | |||||
579 | /** |
||||
580 | * @param string $sql |
||||
0 ignored issues
–
show
|
|||||
581 | * @param mixed[] $bindings |
||||
582 | * @return Query |
||||
0 ignored issues
–
show
|
|||||
583 | */ |
||||
584 | private function prepareQuery($sql, $bindings): Query |
||||
0 ignored issues
–
show
|
|||||
585 | { |
||||
0 ignored issues
–
show
|
|||||
586 | |||||
587 | // add Degeneration query |
||||
588 | foreach ($this->_query_degenerations as $degeneration) { |
||||
0 ignored issues
–
show
|
|||||
589 | 39 | $degeneration->bindParams($bindings); |
|||
590 | } |
||||
591 | 39 | ||||
592 | return new Query($sql, $this->_query_degenerations); |
||||
0 ignored issues
–
show
|
|||||
593 | } |
||||
0 ignored issues
–
show
|
|||||
594 | 39 | ||||
595 | 39 | ||||
596 | 39 | /** |
|||
597 | * @param Query|string $sql |
||||
0 ignored issues
–
show
|
|||||
598 | * @param mixed[] $bindings |
||||
0 ignored issues
–
show
|
|||||
599 | * @param null|WhereInFile $whereInFile |
||||
0 ignored issues
–
show
|
|||||
600 | * @param null|WriteToFile $writeToFile |
||||
0 ignored issues
–
show
|
|||||
601 | * @return CurlerRequest |
||||
0 ignored issues
–
show
|
|||||
602 | * @throws \Exception |
||||
0 ignored issues
–
show
|
|||||
603 | */ |
||||
604 | private function prepareSelect($sql, $bindings, $whereInFile, $writeToFile = null): CurlerRequest |
||||
0 ignored issues
–
show
|
|||||
605 | { |
||||
606 | 28 | if ($sql instanceof Query) { |
|||
0 ignored issues
–
show
|
|||||
607 | return $this->getRequestWrite($sql); |
||||
608 | 28 | } |
|||
609 | $query = $this->prepareQuery($sql, $bindings); |
||||
610 | $query->setFormat('JSON'); |
||||
611 | return $this->getRequestRead($query, $whereInFile, $writeToFile); |
||||
0 ignored issues
–
show
|
|||||
612 | 28 | } |
|||
0 ignored issues
–
show
|
|||||
613 | 27 | ||||
614 | |||||
615 | /** |
||||
616 | * @param Query|string $sql |
||||
0 ignored issues
–
show
|
|||||
617 | * @param mixed[] $bindings |
||||
0 ignored issues
–
show
|
|||||
618 | * @return CurlerRequest |
||||
0 ignored issues
–
show
|
|||||
619 | * @throws \ClickHouseDB\Exception\TransportException |
||||
0 ignored issues
–
show
|
|||||
620 | 10 | */ |
|||
621 | private function prepareWrite($sql, $bindings = []): CurlerRequest |
||||
0 ignored issues
–
show
|
|||||
622 | 10 | { |
|||
623 | if ($sql instanceof Query) { |
||||
624 | return $this->getRequestWrite($sql); |
||||
625 | } |
||||
626 | |||||
627 | $query = $this->prepareQuery($sql, $bindings); |
||||
628 | |||||
629 | if (strpos($sql, 'ON CLUSTER') === false) { |
||||
0 ignored issues
–
show
|
|||||
630 | return $this->getRequestWrite($query); |
||||
631 | } |
||||
632 | |||||
633 | if (strpos($sql, 'CREATE') === 0 || strpos($sql, 'DROP') === 0 || strpos($sql, 'ALTER') === 0) { |
||||
0 ignored issues
–
show
|
|||||
634 | 32 | $query->setFormat('JSON'); |
|||
635 | } |
||||
636 | 32 | ||||
637 | 32 | return $this->getRequestWrite($query); |
|||
638 | 32 | } |
|||
639 | |||||
640 | /** |
||||
641 | * @return bool |
||||
0 ignored issues
–
show
|
|||||
642 | * @throws \ClickHouseDB\Exception\TransportException |
||||
0 ignored issues
–
show
|
|||||
643 | */ |
||||
644 | public function executeAsync(): bool |
||||
645 | { |
||||
646 | return $this->_curler->execLoopWait(); |
||||
647 | } |
||||
648 | |||||
649 | /** |
||||
650 | 7 | * @param Query|string $sql |
|||
0 ignored issues
–
show
|
|||||
651 | * @param mixed[] $bindings |
||||
0 ignored issues
–
show
|
|||||
652 | 7 | * @param null|WhereInFile $whereInFile |
|||
0 ignored issues
–
show
|
|||||
653 | 7 | * @param null|WriteToFile $writeToFile |
|||
0 ignored issues
–
show
|
|||||
654 | 7 | * @return Statement |
|||
0 ignored issues
–
show
|
|||||
655 | * @throws \ClickHouseDB\Exception\TransportException |
||||
0 ignored issues
–
show
|
|||||
656 | * @throws \Exception |
||||
0 ignored issues
–
show
|
|||||
657 | */ |
||||
658 | public function select($sql, array $bindings = [], $whereInFile = null, $writeToFile = null): Statement |
||||
0 ignored issues
–
show
|
|||||
659 | { |
||||
660 | 1 | $request = $this->prepareSelect($sql, $bindings, $whereInFile, $writeToFile); |
|||
661 | $this->_curler->execOne($request); |
||||
662 | 1 | return new Statement($request); |
|||
0 ignored issues
–
show
|
|||||
663 | 1 | } |
|||
664 | |||||
665 | /** |
||||
666 | * @param Query|string $sql |
||||
0 ignored issues
–
show
|
|||||
667 | * @param mixed[] $bindings |
||||
0 ignored issues
–
show
|
|||||
668 | * @param null|WhereInFile $whereInFile |
||||
0 ignored issues
–
show
|
|||||
669 | * @param null|WriteToFile $writeToFile |
||||
0 ignored issues
–
show
|
|||||
670 | * @return Statement |
||||
0 ignored issues
–
show
|
|||||
671 | * @throws \ClickHouseDB\Exception\TransportException |
||||
0 ignored issues
–
show
|
|||||
672 | 28 | * @throws \Exception |
|||
0 ignored issues
–
show
|
|||||
673 | */ |
||||
674 | 28 | public function selectAsync($sql, array $bindings = [], $whereInFile = null, $writeToFile = null): Statement |
|||
0 ignored issues
–
show
|
|||||
675 | 27 | { |
|||
676 | 27 | $request = $this->prepareSelect($sql, $bindings, $whereInFile, $writeToFile); |
|||
677 | 27 | $this->_curler->addQueLoop($request); |
|||
678 | 27 | return new Statement($request); |
|||
0 ignored issues
–
show
|
|||||
679 | 3 | } |
|||
680 | |||||
681 | /** |
||||
682 | 25 | * @param callable $callback |
|||
0 ignored issues
–
show
|
|||||
683 | */ |
||||
684 | public function setProgressFunction(callable $callback) : void |
||||
0 ignored issues
–
show
|
|||||
685 | { |
||||
686 | $this->xClickHouseProgress = $callback; |
||||
687 | } |
||||
688 | |||||
689 | /** |
||||
690 | * @param string $sql |
||||
0 ignored issues
–
show
|
|||||
691 | 2 | * @param mixed[] $bindings |
|||
692 | * @param bool $exception |
||||
0 ignored issues
–
show
|
|||||
693 | 2 | * @return Statement |
|||
0 ignored issues
–
show
|
|||||
694 | 2 | * @throws \ClickHouseDB\Exception\TransportException |
|||
0 ignored issues
–
show
|
|||||
695 | */ |
||||
696 | public function write($sql, array $bindings = [], $exception = true): Statement |
||||
0 ignored issues
–
show
|
|||||
697 | { |
||||
698 | $request = $this->prepareWrite($sql, $bindings); |
||||
699 | $this->_curler->execOne($request); |
||||
700 | 2 | $response = new Statement($request); |
|||
701 | if ($exception) { |
||||
0 ignored issues
–
show
|
|||||
702 | if ($response->isError()) { |
||||
703 | $response->error(); |
||||
704 | } |
||||
705 | } |
||||
706 | return $response; |
||||
0 ignored issues
–
show
|
|||||
707 | } |
||||
708 | |||||
709 | /** |
||||
710 | * @param Stream $streamRW |
||||
0 ignored issues
–
show
|
|||||
711 | * @param CurlerRequest $request |
||||
0 ignored issues
–
show
|
|||||
712 | * @return Statement |
||||
0 ignored issues
–
show
|
|||||
713 | 2 | * @throws \ClickHouseDB\Exception\TransportException |
|||
0 ignored issues
–
show
|
|||||
714 | */ |
||||
715 | 1 | private function streaming(Stream $streamRW, CurlerRequest $request): Statement |
|||
716 | 1 | { |
|||
717 | 1 | $callable = $streamRW->getClosure(); |
|||
718 | $stream = $streamRW->getStream(); |
||||
0 ignored issues
–
show
Equals sign not aligned with surrounding assignments; expected 3 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. ![]() |
|||||
719 | |||||
0 ignored issues
–
show
|
|||||
720 | |||||
721 | try { |
||||
0 ignored issues
–
show
|
|||||
722 | |||||
0 ignored issues
–
show
|
|||||
723 | |||||
724 | if (!is_callable($callable)) { |
||||
0 ignored issues
–
show
|
|||||
725 | 2 | if ($streamRW->isWrite()) { |
|||
0 ignored issues
–
show
|
|||||
726 | |||||
727 | $callable = function ($ch, $fd, $length) use ($stream) { |
||||
0 ignored issues
–
show
|
|||||
728 | 2 | return ($line = fread($stream, $length)) ? $line : ''; |
|||
0 ignored issues
–
show
|
|||||
729 | 1 | }; |
|||
730 | } else { |
||||
731 | 1 | $callable = function ($ch, $fd) use ($stream) { |
|||
0 ignored issues
–
show
|
|||||
732 | return fwrite($stream, $fd); |
||||
0 ignored issues
–
show
|
|||||
733 | }; |
||||
734 | } |
||||
735 | } |
||||
736 | |||||
737 | if ($streamRW->isGzipHeader()) { |
||||
0 ignored issues
–
show
|
|||||
738 | 2 | ||||
739 | 2 | if ($streamRW->isWrite()) { |
|||
0 ignored issues
–
show
|
|||||
740 | 2 | $request->header('Content-Encoding', 'gzip'); |
|||
741 | $request->header('Content-Type', 'application/x-www-form-urlencoded'); |
||||
742 | } else { |
||||
743 | 2 | $request->header('Accept-Encoding', 'gzip'); |
|||
744 | } |
||||
745 | 2 | ||||
0 ignored issues
–
show
|
|||||
746 | 2 | } |
|||
747 | |||||
0 ignored issues
–
show
|
|||||
748 | |||||
749 | $request->header('Transfer-Encoding', 'chunked'); |
||||
750 | |||||
0 ignored issues
–
show
|
|||||
751 | |||||
752 | if ($streamRW->isWrite()) { |
||||
0 ignored issues
–
show
|
|||||
753 | $request->setReadFunction($callable); |
||||
754 | } else { |
||||
755 | $request->setWriteFunction($callable); |
||||
756 | |||||
0 ignored issues
–
show
|
|||||
757 | |||||
758 | // $request->setHeaderFunction($callableHead); |
||||
759 | } |
||||
760 | 1 | ||||
0 ignored issues
–
show
|
|||||
761 | |||||
762 | 1 | $this->_curler->execOne($request, true); |
|||
763 | 1 | $response = new Statement($request); |
|||
764 | 1 | if ($response->isError()) { |
|||
0 ignored issues
–
show
|
|||||
765 | $response->error(); |
||||
766 | } |
||||
767 | return $response; |
||||
0 ignored issues
–
show
|
|||||
768 | } finally { |
||||
769 | if ($streamRW->isWrite()) |
||||
0 ignored issues
–
show
|
|||||
770 | fclose($stream); |
||||
0 ignored issues
–
show
|
|||||
771 | } |
||||
772 | |||||
0 ignored issues
–
show
|
|||||
773 | |||||
774 | } |
||||
0 ignored issues
–
show
|
|||||
775 | 1 | ||||
776 | |||||
777 | 1 | /** |
|||
778 | 1 | * @param Stream $streamRead |
|||
0 ignored issues
–
show
|
|||||
779 | 1 | * @param string $sql |
|||
0 ignored issues
–
show
|
|||||
780 | * @param mixed[] $bindings |
||||
781 | * @return Statement |
||||
0 ignored issues
–
show
|
|||||
782 | * @throws \ClickHouseDB\Exception\TransportException |
||||
0 ignored issues
–
show
|
|||||
783 | */ |
||||
784 | public function streamRead(Stream $streamRead, $sql, $bindings = []): Statement |
||||
0 ignored issues
–
show
|
|||||
785 | { |
||||
786 | $sql = $this->prepareQuery($sql, $bindings); |
||||
0 ignored issues
–
show
Equals sign not aligned with surrounding assignments; expected 5 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. ![]() |
|||||
787 | $request = $this->getRequestRead($sql); |
||||
788 | return $this->streaming($streamRead, $request); |
||||
0 ignored issues
–
show
|
|||||
789 | |||||
790 | } |
||||
0 ignored issues
–
show
|
|||||
791 | |||||
792 | /** |
||||
793 | * @param Stream $streamWrite |
||||
0 ignored issues
–
show
|
|||||
794 | * @param string $sql |
||||
0 ignored issues
–
show
|
|||||
795 | * @param mixed[] $bindings |
||||
796 | * @return Statement |
||||
0 ignored issues
–
show
|
|||||
797 | * @throws \ClickHouseDB\Exception\TransportException |
||||
0 ignored issues
–
show
|
|||||
798 | */ |
||||
799 | public function streamWrite(Stream $streamWrite, $sql, $bindings = []): Statement |
||||
0 ignored issues
–
show
|
|||||
800 | { |
||||
801 | $sql = $this->prepareQuery($sql, $bindings); |
||||
0 ignored issues
–
show
Equals sign not aligned with surrounding assignments; expected 5 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. ![]() |
|||||
802 | $request = $this->writeStreamData($sql); |
||||
803 | return $this->streaming($streamWrite, $request); |
||||
0 ignored issues
–
show
|
|||||
804 | } |
||||
805 | } |
||||
806 |