These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | namespace Elastica\Transport; |
||
3 | |||
4 | use Elastica\Exception\Connection\HttpException; |
||
5 | use Elastica\Exception\PartialShardFailureException; |
||
6 | use Elastica\Exception\ResponseException; |
||
7 | use Elastica\JSON; |
||
8 | use Elastica\Request; |
||
9 | use Elastica\Response; |
||
10 | use Elastica\Util; |
||
11 | |||
12 | /** |
||
13 | * Elastica Http Transport object. |
||
14 | * |
||
15 | * @author Nicolas Ruflin <[email protected]> |
||
16 | */ |
||
17 | class Http extends AbstractTransport |
||
18 | { |
||
19 | /** |
||
20 | * Http scheme. |
||
21 | * |
||
22 | * @var string Http scheme |
||
23 | */ |
||
24 | protected $_scheme = 'http'; |
||
25 | |||
26 | /** |
||
27 | * Curl resource to reuse. |
||
28 | * |
||
29 | * @var resource Curl resource to reuse |
||
30 | */ |
||
31 | protected static $_curlConnection; |
||
32 | |||
33 | /** |
||
34 | * Makes calls to the elasticsearch server. |
||
35 | * |
||
36 | * All calls that are made to the server are done through this function |
||
37 | * |
||
38 | * @param \Elastica\Request $request |
||
39 | * @param array $params Host, Port, ... |
||
40 | * |
||
41 | * @throws \Elastica\Exception\ConnectionException |
||
42 | * @throws \Elastica\Exception\ResponseException |
||
43 | * @throws \Elastica\Exception\Connection\HttpException |
||
44 | * |
||
45 | * @return \Elastica\Response Response object |
||
46 | */ |
||
47 | public function exec(Request $request, array $params) |
||
48 | { |
||
49 | $connection = $this->getConnection(); |
||
50 | |||
51 | $conn = $this->_getConnection($connection->isPersistent()); |
||
52 | |||
53 | // If url is set, url is taken. Otherwise port, host and path |
||
54 | $url = $connection->hasConfig('url') ? $connection->getConfig('url') : ''; |
||
55 | |||
56 | View Code Duplication | if (!empty($url)) { |
|
57 | $baseUri = $url; |
||
58 | } else { |
||
59 | $baseUri = $this->_scheme.'://'.$connection->getHost().':'.$connection->getPort().'/'.$connection->getPath(); |
||
60 | } |
||
61 | |||
62 | $requestPath = $request->getPath(); |
||
63 | if (!Util::isDateMathEscaped($requestPath)) { |
||
64 | $requestPath = Util::escapeDateMath($requestPath); |
||
65 | } |
||
66 | |||
67 | $baseUri .= $requestPath; |
||
68 | |||
69 | $query = $request->getQuery(); |
||
70 | |||
71 | if (!empty($query)) { |
||
72 | $baseUri .= '?'.http_build_query($query); |
||
73 | } |
||
74 | |||
75 | curl_setopt($conn, CURLOPT_URL, $baseUri); |
||
76 | curl_setopt($conn, CURLOPT_TIMEOUT, $connection->getTimeout()); |
||
77 | curl_setopt($conn, CURLOPT_FORBID_REUSE, 0); |
||
78 | |||
79 | // Tell ES that we support the compressed responses |
||
80 | // An "Accept-Encoding" header containing all supported encoding types is sent |
||
81 | // curl will decode the response automatically if the response is encoded |
||
82 | curl_setopt($conn, CURLOPT_ENCODING, ''); |
||
83 | |||
84 | /* @see Connection::setConnectTimeout() */ |
||
85 | $connectTimeout = $connection->getConnectTimeout(); |
||
86 | if ($connectTimeout > 0) { |
||
87 | curl_setopt($conn, CURLOPT_CONNECTTIMEOUT, $connectTimeout); |
||
88 | } |
||
89 | |||
90 | $proxy = $connection->getProxy(); |
||
91 | |||
92 | // See: https://github.com/facebook/hhvm/issues/4875 |
||
93 | View Code Duplication | if (is_null($proxy) && defined('HHVM_VERSION')) { |
|
0 ignored issues
–
show
|
|||
94 | $proxy = getenv('http_proxy') ?: null; |
||
95 | } |
||
96 | |||
97 | if (!is_null($proxy)) { |
||
98 | curl_setopt($conn, CURLOPT_PROXY, $proxy); |
||
99 | } |
||
100 | |||
101 | $username = $connection->getUsername(); |
||
102 | $password = $connection->getPassword(); |
||
103 | if (!is_null($username) && !is_null($password)) { |
||
104 | curl_setopt($conn, CURLOPT_HTTPAUTH, CURLAUTH_ANY); |
||
105 | curl_setopt($conn, CURLOPT_USERPWD, "$username:$password"); |
||
106 | } |
||
107 | |||
108 | $this->_setupCurl($conn); |
||
109 | |||
110 | $headersConfig = $connection->hasConfig('headers') ? $connection->getConfig('headers') : []; |
||
111 | |||
112 | $headers = []; |
||
113 | |||
114 | if (!empty($headersConfig)) { |
||
115 | $headers = []; |
||
116 | while (list($header, $headerValue) = each($headersConfig)) { |
||
117 | array_push($headers, $header.': '.$headerValue); |
||
118 | } |
||
119 | } |
||
120 | |||
121 | // TODO: REFACTOR |
||
122 | $data = $request->getData(); |
||
123 | $httpMethod = $request->getMethod(); |
||
124 | |||
125 | if (!empty($data) || '0' === $data) { |
||
126 | if ($this->hasParam('postWithRequestBody') && $this->getParam('postWithRequestBody') == true) { |
||
127 | $httpMethod = Request::POST; |
||
128 | } |
||
129 | |||
130 | if (is_array($data)) { |
||
131 | $content = JSON::stringify($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); |
||
132 | } else { |
||
133 | $content = $data; |
||
134 | |||
135 | // Escaping of / not necessary. Causes problems in base64 encoding of files |
||
136 | $content = str_replace('\/', '/', $content); |
||
137 | } |
||
138 | |||
139 | array_push($headers, sprintf('Content-Type: %s', $request->getContentType())); |
||
140 | if ($connection->hasCompression()) { |
||
141 | // Compress the body of the request ... |
||
142 | curl_setopt($conn, CURLOPT_POSTFIELDS, gzencode($content)); |
||
143 | |||
144 | // ... and tell ES that it is compressed |
||
145 | array_push($headers, 'Content-Encoding: gzip'); |
||
146 | } else { |
||
147 | curl_setopt($conn, CURLOPT_POSTFIELDS, $content); |
||
148 | } |
||
149 | } else { |
||
150 | curl_setopt($conn, CURLOPT_POSTFIELDS, ''); |
||
151 | } |
||
152 | |||
153 | curl_setopt($conn, CURLOPT_HTTPHEADER, $headers); |
||
154 | |||
155 | curl_setopt($conn, CURLOPT_NOBODY, $httpMethod == 'HEAD'); |
||
156 | |||
157 | curl_setopt($conn, CURLOPT_CUSTOMREQUEST, $httpMethod); |
||
158 | |||
159 | $start = microtime(true); |
||
160 | |||
161 | // cURL opt returntransfer leaks memory, therefore OB instead. |
||
162 | ob_start(); |
||
163 | curl_exec($conn); |
||
164 | $responseString = ob_get_clean(); |
||
165 | |||
166 | $end = microtime(true); |
||
167 | |||
168 | // Checks if error exists |
||
169 | $errorNumber = curl_errno($conn); |
||
170 | |||
171 | $response = new Response($responseString, curl_getinfo($conn, CURLINFO_HTTP_CODE)); |
||
172 | $response->setQueryTime($end - $start); |
||
173 | $response->setTransferInfo(curl_getinfo($conn)); |
||
174 | if ($connection->hasConfig('bigintConversion')) { |
||
175 | $response->setJsonBigintConversion($connection->getConfig('bigintConversion')); |
||
176 | } |
||
177 | |||
178 | if ($response->hasError()) { |
||
179 | throw new ResponseException($request, $response); |
||
180 | } |
||
181 | |||
182 | if ($response->hasFailedShards()) { |
||
183 | throw new PartialShardFailureException($request, $response); |
||
184 | } |
||
185 | |||
186 | if ($errorNumber > 0) { |
||
187 | throw new HttpException($errorNumber, $request, $response); |
||
188 | } |
||
189 | |||
190 | return $response; |
||
191 | } |
||
192 | |||
193 | /** |
||
194 | * Called to add additional curl params. |
||
195 | * |
||
196 | * @param resource $curlConnection Curl connection |
||
197 | */ |
||
198 | protected function _setupCurl($curlConnection) |
||
199 | { |
||
200 | if ($this->getConnection()->hasConfig('curl')) { |
||
201 | foreach ($this->getConnection()->getConfig('curl') as $key => $param) { |
||
202 | curl_setopt($curlConnection, $key, $param); |
||
203 | } |
||
204 | } |
||
205 | } |
||
206 | |||
207 | /** |
||
208 | * Return Curl resource. |
||
209 | * |
||
210 | * @param bool $persistent False if not persistent connection |
||
211 | * |
||
212 | * @return resource Connection resource |
||
213 | */ |
||
214 | protected function _getConnection($persistent = true) |
||
215 | { |
||
216 | if (!$persistent || !self::$_curlConnection) { |
||
217 | self::$_curlConnection = curl_init(); |
||
218 | } |
||
219 | |||
220 | return self::$_curlConnection; |
||
221 | } |
||
222 | } |
||
223 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.