Completed
Push — master ( 2e4030...c0d263 )
by Renato
11s
created

CurlHelper::handleOutput()   C

Complexity

Conditions 8
Paths 16

Size

Total Lines 30
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 24
CRAP Score 8

Importance

Changes 0
Metric Value
dl 0
loc 30
ccs 24
cts 24
cp 1
rs 5.3846
c 0
b 0
f 0
cc 8
eloc 20
nc 16
nop 3
crap 8
1
<?php
2
3
namespace VCR\Util;
4
5
use VCR\Request;
6
use VCR\Response;
7
8
/**
9
* cURL helper class.
10
*/
11
class CurlHelper
12
{
13
    /**
14
     * @var array List of cURL info constants.
15
     */
16
    private static $curlInfoList = array(
17
        //"certinfo"?
18
        CURLINFO_HTTP_CODE => 'http_code',
19
        CURLINFO_EFFECTIVE_URL => 'url',
20
        CURLINFO_FILETIME => 'filetime',
21
        CURLINFO_TOTAL_TIME => 'total_time',
22
        CURLINFO_NAMELOOKUP_TIME => 'namelookup_time',
23
        CURLINFO_CONNECT_TIME => 'connect_time',
24
        CURLINFO_PRETRANSFER_TIME => 'pretransfer_time',
25
        CURLINFO_STARTTRANSFER_TIME => 'starttransfer_time',
26
        CURLINFO_REDIRECT_COUNT => 'redirect_count',
27
        CURLINFO_REDIRECT_TIME => 'redirect_time',
28
        CURLINFO_SIZE_UPLOAD => 'size_upload',
29
        CURLINFO_SIZE_DOWNLOAD => 'size_download',
30
        CURLINFO_SPEED_DOWNLOAD => 'speed_download',
31
        CURLINFO_SPEED_UPLOAD => 'speed_upload',
32
        CURLINFO_HEADER_SIZE => 'header_size',
33
        CURLINFO_HEADER_OUT => 'request_header',
34
        CURLINFO_FILETIME => 'filetime',
35
        CURLINFO_REQUEST_SIZE => 'request_size',
36
        CURLINFO_SSL_VERIFYRESULT => 'ssl_verify_result',
37
        CURLINFO_CONTENT_LENGTH_DOWNLOAD => 'download_content_length',
38
        CURLINFO_CONTENT_LENGTH_UPLOAD => 'upload_content_length',
39
        CURLINFO_CONTENT_TYPE => 'content_type'
40
    );
41
42
    /**
43
     * Outputs a response depending on the set cURL option.
44
     *
45
     * The response body can be written to a file, returned, echoed or
46
     * passed to a custom function.
47
     *
48
     * The response header might be passed to a custom function.
49
     *
50
     * @param  Response $response    Response which contains the response body.
51
     * @param  array    $curlOptions cURL options which are not stored within the Response.
52
     * @param  resource $ch          cURL handle to add headers if needed.
53
     *
54
     * @return null|string
55
     */
56 132
    public static function handleOutput(Response $response, array $curlOptions, $ch)
57
    {
58
        // If there is a header function set, feed the http status and headers to it.
59 132
        if (isset($curlOptions[CURLOPT_HEADERFUNCTION])) {
60 7
            $headerList = array(HttpUtil::formatAsStatusString($response));
61 7
            $headerList = array_merge($headerList, HttpUtil::formatHeadersForCurl($response->getHeaders()));
62 7
            $headerList[] = '';
63 7
            foreach ($headerList as $header) {
64 7
                call_user_func($curlOptions[CURLOPT_HEADERFUNCTION], $ch, $header);
65 3
            }
66 3
        }
67
68 132
        $body = $response->getBody();
69
70 132
        if (!empty($curlOptions[CURLOPT_HEADER])) {
71 7
            $body = HttpUtil::formatAsStatusWithHeadersString($response) . $body;
72 3
        }
73
74 132
        if (isset($curlOptions[CURLOPT_WRITEFUNCTION])) {
75 7
            call_user_func($curlOptions[CURLOPT_WRITEFUNCTION], $ch, $body);
76 128
        } elseif (isset($curlOptions[CURLOPT_RETURNTRANSFER]) && $curlOptions[CURLOPT_RETURNTRANSFER] == true) {
77 63
            return $body;
78 62
        } elseif (isset($curlOptions[CURLOPT_FILE])) {
79 14
            $fp = $curlOptions[CURLOPT_FILE];
80 14
            fwrite($fp, $body);
81 14
            fflush($fp);
82 6
        } else {
83 48
            echo $body;
84
        }
85 69
    }
86
87
    /**
88
     * Returns a cURL option from a Response.
89
     *
90
     * @param  Response $response Response to get cURL option from.
91
     * @param  integer $option cURL option to get.
92
     *
93
     * @throws \BadMethodCallException
94
     * @return mixed Value of the cURL option.
95
     */
96 56
    public static function getCurlOptionFromResponse(Response $response, $option = 0)
97
    {
98
        switch ($option) {
99 56
            case 0: // 0 == array of all curl options
100 14
                $info = array();
101 14
                foreach (self::$curlInfoList as $option => $key) {
102 14
                    $info[$key] = $response->getCurlInfo($key);
103 6
                }
104 14
                break;
105 42
            case CURLINFO_HTTP_CODE:
106 7
                $info = $response->getStatusCode();
107 7
                break;
108 35
            case CURLINFO_SIZE_DOWNLOAD:
109
                $info = $response->getHeader('Content-Length');
110
                break;
111 35
            case CURLINFO_HEADER_SIZE:
112 35
                $info =  mb_strlen(HttpUtil::formatAsStatusWithHeadersString($response), 'ISO-8859-1');
113 35
                break;
114
            default:
115
                $info = $response->getCurlInfo($option);
116
                break;
117
        }
118
119 56
        if (!is_null($info)) {
120 56
            return $info;
121
        }
122
123
        $constants = get_defined_constants(true);
124
        $constantNames = array_flip($constants['curl']);
125
        throw new \BadMethodCallException("Not implemented: {$constantNames[$option]} ({$option}) ");
126
    }
127
128
    /**
129
     * Sets a cURL option on a Request.
130
     *
131
     * @param Request  $request Request to set cURL option to.
132
     * @param integer  $option  cURL option to set.
133
     * @param mixed    $value   Value of the cURL option.
134
     * @param resource $curlHandle cURL handle where this option is set on (optional).
135
     */
136 230
    public static function setCurlOptionOnRequest(Request $request, $option, $value, $curlHandle = null)
0 ignored issues
show
Unused Code introduced by
The parameter $curlHandle is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
137
    {
138
        switch ($option) {
139 230
            case CURLOPT_URL:
140 21
                $request->setUrl($value);
141 21
                break;
142 230
            case CURLOPT_CUSTOMREQUEST:
143 20
                $request->setCurlOption(CURLOPT_CUSTOMREQUEST, $value);
144 20
                break;
145 217
            case CURLOPT_POST:
146 21
                if ($value == true) {
147
                    $request->setMethod('POST');
148
                }
149 21
                break;
150 217
            case CURLOPT_POSTFIELDS:
151
                // todo: check for file @
152 56
                if (is_array($value)) {
153 35
                    foreach ($value as $name => $fieldValue) {
154 28
                        $request->setPostField($name, $fieldValue);
155 15
                    }
156
157 35
                    if (count($value) == 0) {
158 23
                        $request->removeHeader('Content-Type');
159 3
                    }
160 15
                } else {
161 21
                    $request->setBody($value);
162
                }
163 56
                $request->setMethod('POST');
164 56
                break;
165 168
            case CURLOPT_HTTPHEADER:
166 84
                foreach ($value as $header) {
167 84
                    $headerParts = explode(': ', $header, 2);
168 84
                    if (!isset($headerParts[1])) {
169
                        $headerParts[0] = rtrim($headerParts[0], ':');
170
                        $headerParts[1] = null;
171
                    }
172 84
                    $request->setHeader($headerParts[0], $headerParts[1]);
173 36
                }
174 84
                break;
175 84
            case CURLOPT_FILE:
176 80
            case CURLOPT_HEADER:
177 80
            case CURLOPT_WRITEFUNCTION:
178 80
            case CURLOPT_HEADERFUNCTION:
179 80
            case CURLOPT_UPLOAD:
180
                // Ignore header, file and writer functions.
181
                // These options are stored and will be handled later in handleOutput().
182 7
                break;
183 33
            default:
184 77
                $request->setCurlOption($option, $value);
185 77
                break;
186 33
        }
187 230
    }
188
    
189
    /**
190
     * Makes sure we've properly handled the POST body, such as ensuring that
191
     * CURLOPT_INFILESIZE is set if CURLOPT_READFUNCTION is set.
192
     *
193
     * @param Request  $request Request to set cURL option to.
194
     * @param resource $curlHandle cURL handle associated with the request.
195
     */
196 104
    public static function validateCurlPOSTBody(Request $request, $curlHandle = null)
197
    {
198 104
        $readFunction = $request->getCurlOption(CURLOPT_READFUNCTION);
199 104
        if (is_null($readFunction)) {
200 90
            return;
201
        }
202
        
203
        // Guzzle 4 sometimes sets the post body in CURLOPT_POSTFIELDS even if
204
        // they have already set CURLOPT_READFUNCTION.
205 14
        if ($request->getBody()) {
206
            return;
207
        }
208
        
209 14
        $bodySize = $request->getCurlOption(CURLOPT_INFILESIZE);
210 14
        Assertion::notEmpty($bodySize, 'To set a CURLOPT_READFUNCTION, CURLOPT_INFILESIZE must be set.');
211 7
        $body = call_user_func_array($readFunction, array($curlHandle, fopen('php://memory', 'r'), $bodySize));
212 7
        $request->setBody($body);
213 7
    }
214
}
215