Completed
Push — master ( 4afc6b...1d816c )
by Radu
35:29
created

CurlBrowser::parseResponseHeaders()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 8
nc 3
nop 1
dl 0
loc 12
rs 9.4285
c 0
b 0
f 0
1
<?php
2
namespace WebServCo\Framework;
3
4
use WebServCo\Framework\Http;
5
use WebServCo\Framework\Exceptions\ApplicationException;
6
7
final class CurlBrowser implements
8
    \WebServCo\Framework\Interfaces\HttpBrowserInterface
9
{
10
    protected $debug = true;
11
    protected $requestHeaders = [];
12
13
    protected $method;
14
    protected $postData;
15
16
    protected $curl;
17
    protected $debugStderr;
18
    protected $debugOutput;
19
    protected $debugInfo;
20
    protected $response;
21
    protected $responseHeaders;
22
23
    protected $logger;
24
25
    public function __construct($logDir, \WebServCo\Framework\Interfaces\RequestInterface $requestInterface)
26
    {
27
        $this->logger = new \WebServCo\Framework\FileLogger(
28
            'CurlBrowser',
29
            $logDir,
30
            $requestInterface
31
        );
32
        $this->logger->clear();
33
    }
34
35
    public function setDebug(bool $debug)
36
    {
37
        $this->debug = $debug;
38
    }
39
40
    public function setRequestHeaders(array $requestHeaders)
41
    {
42
        $this->requestHeaders = $requestHeaders;
43
    }
44
45
    public function getResponseHeaders()
46
    {
47
        return $this->responseHeaders;
48
    }
49
50
    public function get($url)
51
    {
52
        $this->setMethod(Http::METHOD_GET);
53
        return $this->retrieve($url);
54
    }
55
56
    public function head($url)
57
    {
58
        $this->setMethod(Http::METHOD_HEAD);
59
        return $this->retrieve($url);
60
    }
61
62
    public function post($url, $postData = [])
63
    {
64
        $this->setMethod(Http::METHOD_POST);
65
        $this->setPostData($postData);
66
        return $this->retrieve($url);
67
    }
68
69
    protected function setMethod($method)
70
    {
71
        if (!in_array($method, Http::getMethods())) {
72
            throw new ApplicationException('Unsupported method');
73
        }
74
        $this->method = $method;
75
        return true;
76
    }
77
78
    protected function setPostData(array $postData)
79
    {
80
        $this->postData = $postData;
81
    }
82
83
    protected function debugInit()
84
    {
85
        if ($this->debug) {
86
            ob_start();
87
            $this->debugStderr = fopen('php://output', 'w');
88
            return true;
89
        }
90
        return false;
91
    }
92
93
    protected function debugDo()
94
    {
95
        if ($this->debug) {
96
            //curl_setopt($this->curl, CURLINFO_HEADER_OUT, 1); /* verbose not working if this is enabled */
97
            curl_setopt($this->curl, CURLOPT_VERBOSE, 1);
98
            curl_setopt($this->curl, CURLOPT_STDERR, $this->debugStderr);
99
            return false;
100
        }
101
        return false;
102
    }
103
104
    protected function debugFinish()
105
    {
106
        if ($this->debug) {
107
            fclose($this->debugStderr);
108
            $this->debugOutput = ob_get_clean();
109
110
            $this->logger->debug('CURL INFO:', $this->debugInfo);
111
            $this->logger->debug('CURL VERBOSE:', $this->debugOutput);
112
            $this->logger->debug('CURL RESPONSE:', $this->response);
113
114
            return true;
115
        }
116
        return false;
117
    }
118
119
    protected function getHttpCode()
120
    {
121
        return isset($this->debugInfo['http_code']) ? $this->debugInfo['http_code']: false;
122
    }
123
124
    protected function parseResponseHeaders($headerString)
125
    {
126
        $headers = [];
127
        $lines = explode("\r\n", $headerString);
128
        foreach ($lines as $index => $line) {
129
            if (0 === $index) {
130
                continue; /* we'll get the status code elsewhere */
131
            }
132
            list($key, $value) = explode(': ', $line);
133
            $headers[$key] = $value;
134
        }
135
        return $headers;
136
    }
137
138
    protected function parseRequestHeaders($headers)
139
    {
140
        $data = [];
141
        foreach ($headers as $k => $v) {
142
            $data[] = sprintf('%s: %s', $k, $v);
143
        }
144
        return $data;
145
    }
146
147
    protected function retrieve($url)
148
    {
149
        $this->debugInit();
150
151
        $this->curl = curl_init();
152
        curl_setopt_array(
153
            $this->curl,
154
            [
155
                CURLOPT_RETURNTRANSFER => true, /* return instead of outputting */
156
                CURLOPT_URL => $url,
157
                CURLOPT_HEADER => true, /* include the header in the output */
158
                CURLOPT_FOLLOWLOCATION => true /* follow redirects */
159
            ]
160
        );
161
        if (!empty($this->requestHeaders)) {
162
            curl_setopt(
163
                $this->curl,
164
                CURLOPT_HTTPHEADER,
165
                $this->parseRequestHeaders($this->requestHeaders)
166
            );
167
        }
168
169
        $this->debugDo();
170
171
        switch ($this->method) {
172
            case Http::METHOD_POST:
173
                curl_setopt($this->curl, CURLOPT_POST, true);
174
                if (!empty($this->postData)) {
175
                    curl_setopt($this->curl, CURLOPT_POSTFIELDS, $this->postData);
176
                }
177
                break;
178
            case Http::METHOD_HEAD:
179
                curl_setopt($this->curl, CURLOPT_NOBODY, true);
180
                break;
181
        }
182
183
        $this->response = curl_exec($this->curl);
184
        if (false === $this->response) {
185
            throw new ApplicationException(curl_error($this->curl));
186
        }
187
188
        $this->debugInfo = curl_getinfo($this->curl);
189
190
        $httpCode = $this->getHttpCode();
191
192
        curl_close($this->curl);
193
194
        /**
195
         * For redirects, the response will contain evey header/body pair.
196
         * The last header/body will be at the end of the response.
197
         */
198
        $responseParts = explode("\r\n\r\n", $this->response);
199
        $body = trim(array_pop($responseParts));
200
201
        foreach ($responseParts as $item) {
202
            $this->responseHeaders[] = $this->parseResponseHeaders($item);
203
        }
204
205
        $this->debugFinish();
206
207
        return new \WebServCo\Framework\HttpResponse(
208
            $body,
209
            $httpCode,
210
            end($this->responseHeaders)
211
        );
212
    }
213
}
214