Passed
Branch master (72025d)
by
unknown
02:31 queued 11s
created

Request::fetch()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 30
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 6
Bugs 0 Features 1
Metric Value
c 6
b 0
f 1
dl 0
loc 30
rs 8.439
cc 5
eloc 14
nc 4
nop 2
1
<?php
2
/**
3
 * Class Request
4
 *
5
 * @filesource   Request.php
6
 * @created      13.02.2016
7
 * @package      chillerlan\TinyCurl
8
 * @author       Smiley <[email protected]>
9
 * @copyright    2016 Smiley
10
 * @license      MIT
11
 */
12
13
namespace chillerlan\TinyCurl;
14
15
use chillerlan\TinyCurl\Response\Response;
16
17
/**
18
 *
19
 */
20
class Request{
21
22
	/**
23
	 * The cURL connection
24
	 *
25
	 * @var resource
26
	 */
27
	protected $curl;
28
29
	/**
30
	 * @var \chillerlan\TinyCurl\RequestOptions
31
	 */
32
	protected $options;
33
34
	/**
35
	 * Request constructor.
36
	 *
37
	 * @param \chillerlan\TinyCurl\RequestOptions|null $options
38
	 */
39
	public function __construct(RequestOptions $options = null){
40
		$this->setOptions($options ?: new RequestOptions);
41
	}
42
43
	/**
44
	 * @param \chillerlan\TinyCurl\RequestOptions $options
45
	 */
46
	public function setOptions(RequestOptions $options){
47
		$this->options = $options;
48
	}
49
50
	/**
51
	 * @param string $url
52
	 *
53
	 * @return \chillerlan\TinyCurl\Response\Response
54
	 */
55
	protected function getResponse($url){
56
		curl_setopt($this->curl, CURLOPT_URL, $url);
57
58
		return new Response($this->curl);
59
	}
60
61
	/**
62
	 * @return void
63
	 */
64
	protected function initCurl(){
65
		$this->curl = curl_init();
66
67
		$ca_info = is_file($this->options->ca_info) ? $this->options->ca_info : null;
68
69
		// set defaults
70
		curl_setopt_array($this->curl, [
71
			CURLOPT_PROTOCOLS => CURLPROTO_HTTP|CURLPROTO_HTTPS|CURLPROTO_FTP|CURLPROTO_FTPS,
72
			CURLOPT_RETURNTRANSFER => true,
73
			CURLOPT_SSL_VERIFYPEER => (bool)$ca_info,
74
			CURLOPT_SSL_VERIFYHOST => 2, // Support for value 1 removed in cURL 7.28.1
75
			CURLOPT_CAINFO         => $ca_info,
76
		]);
77
78
		// set the global request options
79
		curl_setopt_array($this->curl, $this->options->curl_options);
80
	}
81
	/**
82
	 * @param \chillerlan\TinyCurl\URL $url
83
	 * @param array                    $curl_options
84
	 *
85
	 * @return \chillerlan\TinyCurl\Response\Response
86
	 * @throws \chillerlan\TinyCurl\RequestException
87
	 */
88
	public function fetch(URL $url, array $curl_options = []){
89
90
		if(!$url->host || !in_array($url->scheme, ['http', 'https', 'ftp', 'ftps'], true)){
91
			throw new RequestException('$url');
92
		}
93
94
		$this->initCurl();
95
96
		switch($url->method){
97
			case 'GET':
98
				break;
99
			case 'POST':
100
				curl_setopt_array($this->curl, [
101
					CURLOPT_POST        => true,
102
					/*
103
					 * "Passing an array to CURLOPT_POSTFIELDS will encode the data as multipart/form-data,
104
					 *  while passing a URL-encoded string will encode the data as application/x-www-form-urlencoded."
105
					 * - PHP manual
106
					 */
107
					CURLOPT_POSTFIELDS  => $url->body,
108
				]);
109
110
				break;
111
		}
112
113
		// set per-request options
114
		curl_setopt_array($this->curl, $curl_options);
115
116
		return $this->getResponse((string)$url);
117
	}
118
119
	/**
120
	 * @param string $url
121
	 *
122
	 * @return array<string>
123
	 */
124
	public function extractShortUrl($url){
125
		$urls = [$url];
126
127
		while($url = $this->extract($url)){
128
			$urls[] = $url;
129
		}
130
131
		return $urls;
132
	}
133
134
	/**
135
	 * @param string $url
136
	 *
137
	 * @return string
138
	 * @link http://www.internoetics.com/2012/11/12/resolve-short-urls-to-their-destination-url-php-api/
139
	 */
140
	protected function extract($url){
141
		$this->initCurl();
142
143
		curl_setopt_array($this->curl, [
144
			CURLOPT_FOLLOWLOCATION => false
145
		]);
146
147
		$response = $this->getResponse($url);
148
149
		$info    = $response->info;
150
		$headers = $response->headers;
151
152
		switch(true){
153
			// check curl_info()
154
			case in_array($info->http_code, range(300, 308), true) && isset($info->redirect_url) && !empty($info->redirect_url):
155
				return $info->redirect_url;
156
			// look for a location header
157
			case isset($headers->location) && !empty($headers->location):
158
				return $headers->location; // @codeCoverageIgnore
159
			default:
160
				return '';
161
		}
162
163
	}
164
165
}
166