Completed
Push — master ( f62226...8b6b73 )
by Stéphane
10s
created

CurlHandle::prepareHttp()   C

Complexity

Conditions 7
Paths 32

Size

Total Lines 37
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 37
ccs 0
cts 0
cp 0
rs 6.7272
cc 7
eloc 27
nc 32
nop 1
crap 56
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
    protected $handle;
31
32 9
    /**
33 1
     * Option collection used for the current request
34
     * @var array
35
     */
36
    protected $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
102
     * @param Configuration\Configuration $config
0 ignored issues
show
Bug introduced by
There is no parameter named $config. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
103 12
     */
104
    public function prepare(AbstractRequest $request)
105 12
    {
106 12
        $config = $request->getOptions();
107 12
108 2
        $this->options[CURLOPT_URL] = (string)$config->url;
109 2
        $this->options[CURLOPT_UPLOAD] = (bool)$config->upload;
110 2
        $this->options[CURLOPT_HTTPHEADER] = $request->getHeaderLines();
111 2
112
        if ($config instanceof Configuration\HttpConfiguration) {
113
            $this->prepareHttp($config);
114 10
        }
115
        if ($config instanceof Configuration\FtpConfiguration) {
116
            $this->options[CURLOPT_FTP_USE_EPSV] = $config->passive;
117
            $this->options[CURLOPT_QUOTE] = $config->commandsRequest();
118
            $this->options[CURLOPT_POSTQUOTE] = $config->commandsPost();
119
        }
120
        if ($config instanceof Configuration\SshConfiguration) {
121 5
            $this->options[CURLOPT_POSTQUOTE] = $config->commandsPost();
122
        }
123 5
124 5
        if ($config->hasBody()) {
125 5
            $body = $config->body;
126 5
            if (is_resource($body)) {
127
                $this->options[CURLOPT_INFILE] = $body;
128
                $md = stream_get_meta_data($body);
129
                $this->options[CURLOPT_INFILESIZE] = filesize($md['uri']);
130
            } else {
131
                $this->options[CURLOPT_POSTFIELDS] = $body;
132
            }
133
        } else {
134
            $this->options[CURLOPT_NOBODY] = true;
135
        }
136
    }
137
138
    /**
139
     * Specific method to prepare HTTP requests options
140
     * @param Configuration\HttpConfiguration $config
141
     */
142
    private function prepareHttp(Configuration\HttpConfiguration $config)
143
    {
144
        switch ($config->method) {
145
            case 'GET':
146
                $this->options[CURLOPT_HTTPGET] = true;
147
                break;
148
            case 'PUT':
149
                if (is_resource($config->body)) {
150
                    $this->options[CURLOPT_PUT] = true;
151
                } else {
152
                    $this->options[CURLOPT_CUSTOMREQUEST] = 'PUT';
153
                }
154
                break;
155
            default:
156
                $this->options[CURLOPT_CUSTOMREQUEST] = $config->method;
157
        }
158
159
        if ($config->redirectsAllowed()) {
160
            $this->options[CURLOPT_AUTOREFERER] = $config->allowRedirectsReferer();
161
            $this->options[CURLOPT_MAXREDIRS] = $config->allowRedirectsMax();
162
        } else {
163
            $this->options[CURLOPT_FOLLOWLOCATION] = false;
164
        }
165
166
        if (null !== $config->accept_encoding) {
167
            $this->options[CURLOPT_ENCODING] = $config->accept_encoding;
168
        }
169
170
        if (true === $config->verify) {
171
            $this->options[CURLOPT_SSL_VERIFYPEER] = true;
172
            $this->options[CURLOPT_SSL_VERIFYHOST] = 2;
173
            $this->options[CURLOPT_CAINFO] = CaBundle::getSystemCaRootBundlePath();
174
        } else {
175
            $this->options[CURLOPT_SSL_VERIFYPEER] = false;
176
            $this->options[CURLOPT_SSL_VERIFYHOST] = 0;
177
        }
178
    }
179
180
    /**
181
     * Execute current handle and return result
182
     * @throws RuntimeException
183
     * @throws CurlException
184
     * @return string
185
     */
186
    public function execute()
187
    {
188
        if (!is_resource($this->handle)) {
189
            throw new RuntimeException('Curl handle has been closed, just open it before execute...');
190
        }
191
192
        curl_setopt_array($this->handle, array_filter($this->options));
193
        $return = curl_exec($this->handle);
194
        $this->infos = curl_getinfo($this->handle);
0 ignored issues
show
Bug introduced by
The property infos does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
195
196
        if ($return === false) {
197
            throw ExceptionFactory::build(
198
                curl_errno($this->handle),
199
                curl_error($this->handle)
200
            );
201
        }
202
203
        return $return;
204
    }
205
206
    /**
207
     * Check PHP version and reset handle option if possible
208
     * @return boolean
209
     */
210
    public function reset()
211
    {
212
        if (is_resource($this->handle) && function_exists('curl_reset')) {
213
            curl_reset($this->handle);
214
            $this->setDefaults();
215
            return true;
216
        } else {
217
            trigger_error('You must upgrade to PHP5.5 to use `curl_reset`', E_USER_NOTICE);
218
        }
219
220
        return false;
221
    }
222
223
    /**
224
     * Retrieve ExecutionInfos details
225
     * @return ExecutionInfos
226
     */
227
    public function infos()
228
    {
229
        return (new ExecutionInfos($this))
230
            ->status(curl_getinfo($this->handle, CURLINFO_HTTP_CODE))
231
            ->headers(curl_getinfo($this->handle, CURLINFO_HEADER_OUT))
232
            ->effectiveUrl(curl_getinfo($this->handle, CURLINFO_EFFECTIVE_URL))
233
            ->transactionTime(curl_getinfo($this->handle, CURLINFO_TOTAL_TIME));
234
    }
235
}
236