Completed
Push — master ( 9f917b...411202 )
by Nicolas
03:08 queued 22s
created

lib/Elastica/Transport/Http.php (1 issue)

Labels
Severity

Upgrade to new PHP Analysis Engine

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(
73
                $this->sanityzeQueryStringBool($query)
74
                );
75
        }
76
77
        curl_setopt($conn, CURLOPT_URL, $baseUri);
78
        curl_setopt($conn, CURLOPT_TIMEOUT, $connection->getTimeout());
79
        curl_setopt($conn, CURLOPT_FORBID_REUSE, 0);
80
81
        // Tell ES that we support the compressed responses
82
        // An "Accept-Encoding" header containing all supported encoding types is sent
83
        // curl will decode the response automatically if the response is encoded
84
        curl_setopt($conn, CURLOPT_ENCODING, '');
85
86
        /* @see Connection::setConnectTimeout() */
87
        $connectTimeout = $connection->getConnectTimeout();
88
        if ($connectTimeout > 0) {
89
            curl_setopt($conn, CURLOPT_CONNECTTIMEOUT, $connectTimeout);
90
        }
91
92
        $proxy = $connection->getProxy();
93
94
        // See: https://github.com/facebook/hhvm/issues/4875
95 View Code Duplication
        if (is_null($proxy) && defined('HHVM_VERSION')) {
96
            $proxy = getenv('http_proxy') ?: null;
97
        }
98
99
        if (!is_null($proxy)) {
100
            curl_setopt($conn, CURLOPT_PROXY, $proxy);
101
        }
102
103
        $username = $connection->getUsername();
104
        $password = $connection->getPassword();
105
        if (!is_null($username) && !is_null($password)) {
106
            curl_setopt($conn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
107
            curl_setopt($conn, CURLOPT_USERPWD, "$username:$password");
108
        }
109
110
        $this->_setupCurl($conn);
111
112
        $headersConfig = $connection->hasConfig('headers') ? $connection->getConfig('headers') : [];
113
114
        $headers = [];
115
116
        if (!empty($headersConfig)) {
117
            $headers = [];
118
            foreach ($headersConfig as $header => $headerValue) {
0 ignored issues
show
The expression $headersConfig of type array|string is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
119
                array_push($headers, $header.': '.$headerValue);
120
            }
121
        }
122
123
        // TODO: REFACTOR
124
        $data = $request->getData();
125
        $httpMethod = $request->getMethod();
126
127
        if (!empty($data) || '0' === $data) {
128
            if ($this->hasParam('postWithRequestBody') && $this->getParam('postWithRequestBody') == true) {
129
                $httpMethod = Request::POST;
130
            }
131
132
            if (is_array($data)) {
133
                $content = JSON::stringify($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
134
            } else {
135
                $content = $data;
136
137
                // Escaping of / not necessary. Causes problems in base64 encoding of files
138
                $content = str_replace('\/', '/', $content);
139
            }
140
141
            array_push($headers, sprintf('Content-Type: %s', $request->getContentType()));
142
            if ($connection->hasCompression()) {
143
                // Compress the body of the request ...
144
                curl_setopt($conn, CURLOPT_POSTFIELDS, gzencode($content));
145
146
                // ... and tell ES that it is compressed
147
                array_push($headers, 'Content-Encoding: gzip');
148
            } else {
149
                curl_setopt($conn, CURLOPT_POSTFIELDS, $content);
150
            }
151
        } else {
152
            curl_setopt($conn, CURLOPT_POSTFIELDS, '');
153
        }
154
155
        curl_setopt($conn, CURLOPT_HTTPHEADER, $headers);
156
157
        curl_setopt($conn, CURLOPT_NOBODY, $httpMethod == 'HEAD');
158
159
        curl_setopt($conn, CURLOPT_CUSTOMREQUEST, $httpMethod);
160
161
        $start = microtime(true);
162
163
        // cURL opt returntransfer leaks memory, therefore OB instead.
164
        ob_start();
165
        curl_exec($conn);
166
        $responseString = ob_get_clean();
167
168
        $end = microtime(true);
169
170
        // Checks if error exists
171
        $errorNumber = curl_errno($conn);
172
173
        $response = new Response($responseString, curl_getinfo($conn, CURLINFO_HTTP_CODE));
174
        $response->setQueryTime($end - $start);
175
        $response->setTransferInfo(curl_getinfo($conn));
176
        if ($connection->hasConfig('bigintConversion')) {
177
            $response->setJsonBigintConversion($connection->getConfig('bigintConversion'));
178
        }
179
180
        if ($response->hasError()) {
181
            throw new ResponseException($request, $response);
182
        }
183
184
        if ($response->hasFailedShards()) {
185
            throw new PartialShardFailureException($request, $response);
186
        }
187
188
        if ($errorNumber > 0) {
189
            throw new HttpException($errorNumber, $request, $response);
190
        }
191
192
        return $response;
193
    }
194
195
    /**
196
     * Called to add additional curl params.
197
     *
198
     * @param resource $curlConnection Curl connection
199
     */
200
    protected function _setupCurl($curlConnection)
201
    {
202
        if ($this->getConnection()->hasConfig('curl')) {
203
            foreach ($this->getConnection()->getConfig('curl') as $key => $param) {
204
                curl_setopt($curlConnection, $key, $param);
205
            }
206
        }
207
    }
208
209
    /**
210
     * Return Curl resource.
211
     *
212
     * @param bool $persistent False if not persistent connection
213
     *
214
     * @return resource Connection resource
215
     */
216
    protected function _getConnection($persistent = true)
217
    {
218
        if (!$persistent || !self::$_curlConnection) {
219
            self::$_curlConnection = curl_init();
220
        }
221
222
        return self::$_curlConnection;
223
    }
224
}
225