]> git.mxchange.org Git - friendica.git/blob - src/Network/CurlResult.php
Making the tests happy
[friendica.git] / src / Network / CurlResult.php
1 <?php
2
3 namespace Friendica\Network;
4
5 use Friendica\Core\Logger;
6 use Friendica\Network\HTTPException\InternalServerErrorException;
7 use Friendica\Util\Network;
8
9 /**
10  * A content class for Curl call results
11  */
12 class CurlResult
13 {
14         /**
15          * @var int HTTP return code or 0 if timeout or failure
16          */
17         private $returnCode;
18
19         /**
20          * @var string the content type of the Curl call
21          */
22         private $contentType;
23
24         /**
25          * @var string the HTTP headers of the Curl call
26          */
27         private $header;
28
29         /**
30          * @var boolean true (if HTTP 2xx result) or false
31          */
32         private $isSuccess;
33
34         /**
35          * @var string the URL which was called
36          */
37         private $url;
38
39         /**
40          * @var string in case of redirect, content was finally retrieved from this URL
41          */
42         private $redirectUrl;
43
44         /**
45          * @var string fetched content
46          */
47         private $body;
48
49         /**
50          * @var array some informations about the fetched data
51          */
52         private $info;
53
54         /**
55          * @var boolean true if the URL has a redirect
56          */
57         private $isRedirectUrl;
58
59         /**
60          * @var boolean true if the curl request timed out
61          */
62         private $isTimeout;
63
64         /**
65          * @var int the error number or 0 (zero) if no error
66          */
67         private $errorNumber;
68
69         /**
70          * @var string the error message or '' (the empty string) if no
71          */
72         private $error;
73
74         /**
75          * Creates an errored CURL response
76          *
77          * @param string $url optional URL
78          *
79          * @return CurlResult a CURL with error response
80          */
81         public static function createErrorCurl($url = '')
82         {
83                 return new CurlResult($url, '', ['http_code' => 0]);
84         }
85
86         /**
87          * Curl constructor.
88          * @param string $url the URL which was called
89          * @param string $result the result of the curl execution
90          * @param array $info an additional info array
91          * @param int $errorNumber the error number or 0 (zero) if no error
92          * @param string $error the error message or '' (the empty string) if no
93          *
94          * @throws InternalServerErrorException when HTTP code of the CURL response is missing
95          */
96         public function __construct($url, $result, $info, $errorNumber = 0, $error = '')
97         {
98                 if (!array_key_exists('http_code', $info)) {
99                         throw new InternalServerErrorException('CURL response doesn\'t contains a response HTTP code');
100                 }
101
102                 $this->returnCode = $info['http_code'];
103                 $this->url = $url;
104                 $this->info = $info;
105                 $this->errorNumber = $errorNumber;
106                 $this->error = $error;
107
108                 Logger::log($url . ': ' . $this->returnCode . " " . $result, Logger::DATA);
109
110                 $this->parseBodyHeader($result);
111                 $this->checkSuccess();
112                 $this->checkRedirect();
113                 $this->checkInfo();
114         }
115
116         private function parseBodyHeader($result)
117         {
118                 // Pull out multiple headers, e.g. proxy and continuation headers
119                 // allow for HTTP/2.x without fixing code
120
121                 $header = '';
122                 $base = $result;
123                 while (preg_match('/^HTTP\/.+? \d+/', $base)) {
124                         $chunk = substr($base, 0, strpos($base, "\r\n\r\n") + 4);
125                         $header .= $chunk;
126                         $base = substr($base, strlen($chunk));
127                 }
128
129                 $this->body = substr($result, strlen($header));
130                 $this->header = $header;
131         }
132
133         private function checkSuccess()
134         {
135                 $this->isSuccess = ($this->returnCode >= 200 && $this->returnCode <= 299) || $this->errorNumber == 0;
136
137                 // Everything higher or equal 400 is not a success
138                 if ($this->returnCode >= 400) {
139                         $this->isSuccess = false;
140                 }
141
142                 if (!$this->isSuccess) {
143                         Logger::log('error: ' . $this->url . ': ' . $this->returnCode . ' - ' . $this->error, Logger::INFO);
144                         Logger::log('debug: ' . print_r($this->info, true), Logger::DATA);
145                 }
146
147                 if (!$this->isSuccess && $this->errorNumber == CURLE_OPERATION_TIMEDOUT) {
148                         $this->isTimeout = true;
149                 } else {
150                         $this->isTimeout = false;
151                 }
152         }
153
154         private function checkRedirect()
155         {
156                 if (!array_key_exists('url', $this->info)) {
157                         $this->redirectUrl = '';
158                 } else {
159                         $this->redirectUrl = $this->info['url'];
160                 }
161
162                 if ($this->returnCode == 301 || $this->returnCode == 302 || $this->returnCode == 303 || $this->returnCode== 307) {
163                         $redirect_parts = parse_url(defaults($this->info, 'redirect_url', ''));
164                         if (preg_match('/(Location:|URI:)(.*?)\n/i', $this->header, $matches)) {
165                                 $redirect_parts = array_merge($redirect_parts, parse_url(trim(array_pop($matches))));
166                         }
167
168                         $parts = parse_url(defaults($this->info, 'url', ''));
169
170                         /// @todo Checking the corresponding RFC which parts of a redirect can be ommitted.
171                         $components = ['scheme', 'host', 'path', 'query', 'fragment'];
172                         foreach ($components as $component) {
173                                 if (empty($redirect_parts[$component]) && !empty($parts[$component])) {
174                                         $redirect_parts[$component] = $parts[$component];
175                                 }
176                         }
177
178                         $this->redirectUrl = Network::unparseURL($redirect_parts);
179
180                         $this->isRedirectUrl = filter_var($this->redirectUrl, FILTER_VALIDATE_URL) !== false;
181                 } else {
182                         $this->isRedirectUrl = false;
183                 }
184         }
185
186         private function checkInfo()
187         {
188                 if (isset($this->info['content_type'])) {
189                         $this->contentType = $this->info['content_type'];
190                 } else {
191                         $this->contentType = '';
192                 }
193         }
194
195         /**
196          * Gets the Curl Code
197          *
198          * @return string The Curl Code
199          */
200         public function getReturnCode()
201         {
202                 return $this->returnCode;
203         }
204
205         /**
206          * Returns the Curl Content Type
207          *
208          * @return string the Curl Content Type
209          */
210         public function getContentType()
211         {
212                 return $this->contentType;
213         }
214
215         /**
216          * Returns the Curl headers
217          *
218          * @return string the Curl headers
219          */
220         public function getHeader()
221         {
222                 return $this->header;
223         }
224
225         /**
226          * @return bool
227          */
228         public function isSuccess()
229         {
230                 return $this->isSuccess;
231         }
232
233         /**
234          * @return string
235          */
236         public function getUrl()
237         {
238                 return $this->url;
239         }
240
241         /**
242          * @return string
243          */
244         public function getRedirectUrl()
245         {
246                 return $this->redirectUrl;
247         }
248
249         /**
250          * @return string
251          */
252         public function getBody()
253         {
254                 return $this->body;
255         }
256
257         /**
258          * @return array
259          */
260         public function getInfo()
261         {
262                 return $this->info;
263         }
264
265         /**
266          * @return bool
267          */
268         public function isRedirectUrl()
269         {
270                 return $this->isRedirectUrl;
271         }
272
273         /**
274          * @return int
275          */
276         public function getErrorNumber()
277         {
278                 return $this->errorNumber;
279         }
280
281         /**
282          * @return string
283          */
284         public function getError()
285         {
286                 return $this->error;
287         }
288
289         /**
290          * @return bool
291          */
292         public function isTimeout()
293         {
294                 return $this->isTimeout;
295         }
296 }