Completed
Push — master ( ad1cee...092247 )
by Stéphane
03:46
created

CurlHandle::getCurlInfo()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
ccs 0
cts 0
cp 0
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 2
1
<?php
2
/**
3
 * This file is part of the bee4/transport package.
4
 * For the full copyright and license information, please view the LICENSE
5
 * file that was distributed with this source code.
6
 *
7
 * @copyright Bee4 2015
8
 * @author  Stephane HULARD <[email protected]>
9
 * @package Bee4\Transport\Handle
10
 */
11
12
namespace Bee4\Transport\Handle;
13
14
use Composer\CaBundle\CaBundle;
15
use Bee4\Transport\Message\Request\AbstractRequest;
16
use Bee4\Transport\Configuration;
17
use Bee4\Transport\Exception\Curl\ExceptionFactory;
18
use Bee4\Transport\Exception\RuntimeException;
19
20
/**
21
 * Define cURL handle wrapper
22
 * @package Bee4\Transport\Handle
23
 */
24
class CurlHandle implements HandleInterface
25
{
26
    /**
27
     * cURL resource handle
28
     * @var resource
29
     */
30
    private $handle;
31
32 9
    /**
33 1
     * Option collection used for the current request
34
     * @var array
35
     */
36
    private $options = [];
37
38
    /**
39
     * Initialize cURL resource
40 9
     */
41 9
    public function __construct()
42 9
    {
43
        // @codeCoverageIgnoreStart
44
        if (!extension_loaded('curl')) {
45
            throw new RuntimeException('The PHP cURL extension must be installed!');
46
        }
47 14
        // @codeCoverageIgnoreEnd
48
49 14
        $this->setDefaults();
50 14
        $this->open();
51 14
    }
52 14
53 14
    /**
54 14
     * Set default CURL options
55 14
     */
56
    private function setDefaults()
57
    {
58
        $this->options = [
59
            CURLOPT_RETURNTRANSFER => true,
60
            CURLOPT_FOLLOWLOCATION => true,
61
            CURLOPT_HEADER => true,
62
            CURLINFO_HEADER_OUT => true
63
        ];
64
    }
65
66
    /**
67
     * Handle destructor
68
     * @codeCoverageIgnore
69
     */
70 9
    public function __destruct()
71
    {
72 9
        $this->close();
73 9
    }
74 9
75 9
    /**
76
     * Open the curl handle to be used
77
     * @return Handle
78
     */
79
    public function open()
80
    {
81
        if (!is_resource($this->handle)) {
82 2
            $this->handle = curl_init();
83
        }
84 2
        return $this;
85 2
    }
86 2
87 2
    /**
88 2
     * Close currently opened handle
89
     * @return Handle
90
     */
91
    public function close()
92
    {
93
        if (is_resource($this->handle)) {
94
            curl_close($this->handle);
95
        }
96
        $this->handle = null;
97 13
        return $this;
98
    }
99 13
100 1
    /**
101
     * Prepare the handle to be configured by a given request
102
     * @param  AbstractRequest $request
103 12
     * @return CurlHandle
104
     */
105 12
    public function prepare(AbstractRequest $request)
106 12
    {
107 12
        $config = $request->getOptions();
108 2
109 2
        $this->options[CURLOPT_URL] = (string)$config->url;
110 2
        $this->options[CURLOPT_UPLOAD] = (bool)$config->upload;
111 2
        $this->options[CURLOPT_HTTPHEADER] = $request->getHeaderLines();
112
113
        if ($config instanceof Configuration\HttpConfiguration) {
114 10
            $this->prepareHttp($config);
115
        }
116
        if ($config instanceof Configuration\FtpConfiguration) {
117
            $this->options[CURLOPT_FTP_USE_EPSV] = $config->passive;
118
            $this->options[CURLOPT_QUOTE] = $config->commandsRequest();
119
            $this->options[CURLOPT_POSTQUOTE] = $config->commandsPost();
120
        }
121 5
        if ($config instanceof Configuration\SshConfiguration) {
122
            $this->options[CURLOPT_POSTQUOTE] = $config->commandsPost();
123 5
        }
124 5
125 5
        if ($config->hasBody()) {
126 5
            $body = $config->body;
127
            if (is_resource($body)) {
128
                $this->options[CURLOPT_INFILE] = $body;
129
                $md = stream_get_meta_data($body);
130
                $this->options[CURLOPT_INFILESIZE] = filesize($md['uri']);
131
            } else {
132
                $this->options[CURLOPT_POSTFIELDS] = $body;
133
            }
134
        } else {
135
            $this->options[CURLOPT_NOBODY] = true;
136
        }
137
138
        return $this;
139
    }
140
141
    /**
142
     * Specific method to prepare HTTP requests options
143
     * @param Configuration\HttpConfiguration $config
144
     */
145
    private function prepareHttp(Configuration\HttpConfiguration $config)
146
    {
147
        switch ($config->method) {
148
            case 'GET':
149
                $this->options[CURLOPT_HTTPGET] = true;
150
                break;
151
            case 'PUT':
152
                if (is_resource($config->body)) {
153
                    $this->options[CURLOPT_PUT] = true;
154
                } else {
155
                    $this->options[CURLOPT_CUSTOMREQUEST] = 'PUT';
156
                }
157
                break;
158
            default:
159
                $this->options[CURLOPT_CUSTOMREQUEST] = $config->method;
160
        }
161
162
        if ($config->redirectsAllowed()) {
163
            $this->options[CURLOPT_AUTOREFERER] = $config->allowRedirectsReferer();
164
            $this->options[CURLOPT_MAXREDIRS] = $config->allowRedirectsMax();
165
        } else {
166
            $this->options[CURLOPT_FOLLOWLOCATION] = false;
167
        }
168
169
        if (null !== $config->accept_encoding) {
170
            $this->options[CURLOPT_ENCODING] = $config->accept_encoding;
171
        }
172
173
        if (true === $config->verify) {
174
            $this->options[CURLOPT_SSL_VERIFYPEER] = true;
175
            $this->options[CURLOPT_SSL_VERIFYHOST] = 2;
176
            $this->options[CURLOPT_CAINFO] = CaBundle::getSystemCaRootBundlePath();
177
        } else {
178
            $this->options[CURLOPT_SSL_VERIFYPEER] = false;
179
            $this->options[CURLOPT_SSL_VERIFYHOST] = 0;
180
        }
181
    }
182
183
    /**
184
     * Execute current handle and return result
185
     * @throws RuntimeException
186
     * @throws CurlException
187
     * @return string
188
     */
189
    public function execute()
190
    {
191
        if (!is_resource($this->handle)) {
192
            throw new RuntimeException('Curl handle has been closed, just open it before execute...');
193
        }
194
195
        curl_setopt_array($this->handle, array_filter($this->options));
196
        $return = curl_exec($this->handle);
197
198
        if ($return === false) {
199
            throw ExceptionFactory::build(
200
                curl_errno($this->handle),
201
                curl_error($this->handle)
202
            );
203
        }
204
205
        return $return;
206
    }
207
208
    /**
209
     * Check PHP version and reset handle option if possible
210
     * @return boolean
211
     */
212
    public function reset()
213
    {
214
        if (is_resource($this->handle)) {
215
            curl_reset($this->handle);
216
            $this->setDefaults();
217
            return true;
218
        }
219
220
        return false;
221
    }
222
223
    /**
224
     * Access to `curl_getinfo` result on the current handle
225
     * @return array
226
     */
227
    public function getCurlInfo()
228
    {
229
        return curl_getinfo($this->handle);
230
    }
231
232
    /**
233
     * Retrieve ExecutionInfos details
234
     * @return ExecutionInfos
235
     */
236
    public function infos()
237
    {
238
        return (new ExecutionInfos($this))
239
            ->status(curl_getinfo($this->handle, CURLINFO_HTTP_CODE))
240
            ->headers(curl_getinfo($this->handle, CURLINFO_HEADER_OUT))
241
            ->effectiveUrl(curl_getinfo($this->handle, CURLINFO_EFFECTIVE_URL))
242
            ->transactionTime(curl_getinfo($this->handle, CURLINFO_TOTAL_TIME));
243
    }
244
}
245