| 94 |
jpm |
1 |
<?php
|
|
|
2 |
/**
|
|
|
3 |
* PEAR_REST
|
|
|
4 |
*
|
|
|
5 |
* PHP versions 4 and 5
|
|
|
6 |
*
|
|
|
7 |
* @category pear
|
|
|
8 |
* @package PEAR
|
|
|
9 |
* @author Greg Beaver <cellog@php.net>
|
| 187 |
mathias |
10 |
* @copyright 1997-2009 The Authors
|
|
|
11 |
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
| 94 |
jpm |
12 |
* @link http://pear.php.net/package/PEAR
|
|
|
13 |
* @since File available since Release 1.4.0a1
|
|
|
14 |
*/
|
|
|
15 |
|
|
|
16 |
/**
|
|
|
17 |
* For downloading xml files
|
|
|
18 |
*/
|
|
|
19 |
require_once 'PEAR.php';
|
|
|
20 |
require_once 'PEAR/XMLParser.php';
|
|
|
21 |
|
|
|
22 |
/**
|
|
|
23 |
* Intelligently retrieve data, following hyperlinks if necessary, and re-directing
|
|
|
24 |
* as well
|
|
|
25 |
* @category pear
|
|
|
26 |
* @package PEAR
|
|
|
27 |
* @author Greg Beaver <cellog@php.net>
|
| 187 |
mathias |
28 |
* @copyright 1997-2009 The Authors
|
|
|
29 |
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
|
|
30 |
* @version Release: 1.10.1
|
| 94 |
jpm |
31 |
* @link http://pear.php.net/package/PEAR
|
|
|
32 |
* @since Class available since Release 1.4.0a1
|
|
|
33 |
*/
|
|
|
34 |
class PEAR_REST
|
|
|
35 |
{
|
|
|
36 |
var $config;
|
|
|
37 |
var $_options;
|
| 187 |
mathias |
38 |
|
|
|
39 |
function __construct(&$config, $options = array())
|
| 94 |
jpm |
40 |
{
|
| 187 |
mathias |
41 |
$this->config = &$config;
|
| 94 |
jpm |
42 |
$this->_options = $options;
|
|
|
43 |
}
|
|
|
44 |
|
|
|
45 |
/**
|
|
|
46 |
* Retrieve REST data, but always retrieve the local cache if it is available.
|
|
|
47 |
*
|
|
|
48 |
* This is useful for elements that should never change, such as information on a particular
|
|
|
49 |
* release
|
|
|
50 |
* @param string full URL to this resource
|
|
|
51 |
* @param array|false contents of the accept-encoding header
|
|
|
52 |
* @param boolean if true, xml will be returned as a string, otherwise, xml will be
|
|
|
53 |
* parsed using PEAR_XMLParser
|
|
|
54 |
* @return string|array
|
|
|
55 |
*/
|
| 187 |
mathias |
56 |
function retrieveCacheFirst($url, $accept = false, $forcestring = false, $channel = false)
|
| 94 |
jpm |
57 |
{
|
|
|
58 |
$cachefile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR .
|
|
|
59 |
md5($url) . 'rest.cachefile';
|
| 187 |
mathias |
60 |
|
| 94 |
jpm |
61 |
if (file_exists($cachefile)) {
|
|
|
62 |
return unserialize(implode('', file($cachefile)));
|
|
|
63 |
}
|
| 187 |
mathias |
64 |
|
|
|
65 |
return $this->retrieveData($url, $accept, $forcestring, $channel);
|
| 94 |
jpm |
66 |
}
|
|
|
67 |
|
|
|
68 |
/**
|
|
|
69 |
* Retrieve a remote REST resource
|
|
|
70 |
* @param string full URL to this resource
|
|
|
71 |
* @param array|false contents of the accept-encoding header
|
|
|
72 |
* @param boolean if true, xml will be returned as a string, otherwise, xml will be
|
|
|
73 |
* parsed using PEAR_XMLParser
|
|
|
74 |
* @return string|array
|
|
|
75 |
*/
|
| 187 |
mathias |
76 |
function retrieveData($url, $accept = false, $forcestring = false, $channel = false)
|
| 94 |
jpm |
77 |
{
|
|
|
78 |
$cacheId = $this->getCacheId($url);
|
|
|
79 |
if ($ret = $this->useLocalCache($url, $cacheId)) {
|
|
|
80 |
return $ret;
|
|
|
81 |
}
|
| 187 |
mathias |
82 |
|
|
|
83 |
$file = $trieddownload = false;
|
| 94 |
jpm |
84 |
if (!isset($this->_options['offline'])) {
|
|
|
85 |
$trieddownload = true;
|
| 187 |
mathias |
86 |
$file = $this->downloadHttp($url, $cacheId ? $cacheId['lastChange'] : false, $accept, $channel);
|
| 94 |
jpm |
87 |
}
|
| 187 |
mathias |
88 |
|
| 94 |
jpm |
89 |
if (PEAR::isError($file)) {
|
| 187 |
mathias |
90 |
if ($file->getCode() !== -9276) {
|
| 94 |
jpm |
91 |
return $file;
|
|
|
92 |
}
|
| 187 |
mathias |
93 |
|
|
|
94 |
$trieddownload = false;
|
|
|
95 |
$file = false; // use local copy if available on socket connect error
|
| 94 |
jpm |
96 |
}
|
| 187 |
mathias |
97 |
|
| 94 |
jpm |
98 |
if (!$file) {
|
|
|
99 |
$ret = $this->getCache($url);
|
|
|
100 |
if (!PEAR::isError($ret) && $trieddownload) {
|
|
|
101 |
// reset the age of the cache if the server says it was unmodified
|
| 187 |
mathias |
102 |
$result = $this->saveCache($url, $ret, null, true, $cacheId);
|
|
|
103 |
if (PEAR::isError($result)) {
|
|
|
104 |
return PEAR::raiseError($result->getMessage());
|
|
|
105 |
}
|
| 94 |
jpm |
106 |
}
|
| 187 |
mathias |
107 |
|
| 94 |
jpm |
108 |
return $ret;
|
|
|
109 |
}
|
| 187 |
mathias |
110 |
|
| 94 |
jpm |
111 |
if (is_array($file)) {
|
| 187 |
mathias |
112 |
$headers = $file[2];
|
| 94 |
jpm |
113 |
$lastmodified = $file[1];
|
| 187 |
mathias |
114 |
$content = $file[0];
|
| 94 |
jpm |
115 |
} else {
|
| 187 |
mathias |
116 |
$headers = array();
|
| 94 |
jpm |
117 |
$lastmodified = false;
|
| 187 |
mathias |
118 |
$content = $file;
|
| 94 |
jpm |
119 |
}
|
| 187 |
mathias |
120 |
|
| 94 |
jpm |
121 |
if ($forcestring) {
|
| 187 |
mathias |
122 |
$result = $this->saveCache($url, $content, $lastmodified, false, $cacheId);
|
|
|
123 |
if (PEAR::isError($result)) {
|
|
|
124 |
return PEAR::raiseError($result->getMessage());
|
|
|
125 |
}
|
|
|
126 |
|
| 94 |
jpm |
127 |
return $content;
|
|
|
128 |
}
|
| 187 |
mathias |
129 |
|
| 94 |
jpm |
130 |
if (isset($headers['content-type'])) {
|
| 187 |
mathias |
131 |
$content_type = explode(";", $headers['content-type']);
|
|
|
132 |
$content_type = $content_type[0];
|
|
|
133 |
switch ($content_type) {
|
| 94 |
jpm |
134 |
case 'text/xml' :
|
|
|
135 |
case 'application/xml' :
|
| 187 |
mathias |
136 |
case 'text/plain' :
|
|
|
137 |
if ($content_type === 'text/plain') {
|
|
|
138 |
$check = substr($content, 0, 5);
|
|
|
139 |
if ($check !== '<?xml') {
|
|
|
140 |
break;
|
|
|
141 |
}
|
|
|
142 |
}
|
|
|
143 |
|
| 94 |
jpm |
144 |
$parser = new PEAR_XMLParser;
|
|
|
145 |
PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
|
|
|
146 |
$err = $parser->parse($content);
|
|
|
147 |
PEAR::popErrorHandling();
|
|
|
148 |
if (PEAR::isError($err)) {
|
|
|
149 |
return PEAR::raiseError('Invalid xml downloaded from "' . $url . '": ' .
|
|
|
150 |
$err->getMessage());
|
|
|
151 |
}
|
|
|
152 |
$content = $parser->getData();
|
|
|
153 |
case 'text/html' :
|
|
|
154 |
default :
|
|
|
155 |
// use it as a string
|
|
|
156 |
}
|
|
|
157 |
} else {
|
|
|
158 |
// assume XML
|
|
|
159 |
$parser = new PEAR_XMLParser;
|
|
|
160 |
$parser->parse($content);
|
|
|
161 |
$content = $parser->getData();
|
|
|
162 |
}
|
| 187 |
mathias |
163 |
|
|
|
164 |
$result = $this->saveCache($url, $content, $lastmodified, false, $cacheId);
|
|
|
165 |
if (PEAR::isError($result)) {
|
|
|
166 |
return PEAR::raiseError($result->getMessage());
|
|
|
167 |
}
|
|
|
168 |
|
| 94 |
jpm |
169 |
return $content;
|
|
|
170 |
}
|
|
|
171 |
|
|
|
172 |
function useLocalCache($url, $cacheid = null)
|
|
|
173 |
{
|
|
|
174 |
if ($cacheid === null) {
|
|
|
175 |
$cacheidfile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR .
|
|
|
176 |
md5($url) . 'rest.cacheid';
|
| 187 |
mathias |
177 |
if (!file_exists($cacheidfile)) {
|
| 94 |
jpm |
178 |
return false;
|
|
|
179 |
}
|
| 187 |
mathias |
180 |
|
|
|
181 |
$cacheid = unserialize(implode('', file($cacheidfile)));
|
| 94 |
jpm |
182 |
}
|
| 187 |
mathias |
183 |
|
| 94 |
jpm |
184 |
$cachettl = $this->config->get('cache_ttl');
|
|
|
185 |
// If cache is newer than $cachettl seconds, we use the cache!
|
|
|
186 |
if (time() - $cacheid['age'] < $cachettl) {
|
|
|
187 |
return $this->getCache($url);
|
|
|
188 |
}
|
| 187 |
mathias |
189 |
|
| 94 |
jpm |
190 |
return false;
|
|
|
191 |
}
|
|
|
192 |
|
|
|
193 |
function getCacheId($url)
|
|
|
194 |
{
|
|
|
195 |
$cacheidfile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR .
|
|
|
196 |
md5($url) . 'rest.cacheid';
|
| 187 |
mathias |
197 |
|
|
|
198 |
if (!file_exists($cacheidfile)) {
|
| 94 |
jpm |
199 |
return false;
|
|
|
200 |
}
|
| 187 |
mathias |
201 |
|
|
|
202 |
$ret = unserialize(implode('', file($cacheidfile)));
|
|
|
203 |
return $ret;
|
| 94 |
jpm |
204 |
}
|
|
|
205 |
|
|
|
206 |
function getCache($url)
|
|
|
207 |
{
|
|
|
208 |
$cachefile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR .
|
|
|
209 |
md5($url) . 'rest.cachefile';
|
| 187 |
mathias |
210 |
|
|
|
211 |
if (!file_exists($cachefile)) {
|
| 94 |
jpm |
212 |
return PEAR::raiseError('No cached content available for "' . $url . '"');
|
|
|
213 |
}
|
| 187 |
mathias |
214 |
|
|
|
215 |
return unserialize(implode('', file($cachefile)));
|
| 94 |
jpm |
216 |
}
|
|
|
217 |
|
|
|
218 |
/**
|
|
|
219 |
* @param string full URL to REST resource
|
|
|
220 |
* @param string original contents of the REST resource
|
|
|
221 |
* @param array HTTP Last-Modified and ETag headers
|
|
|
222 |
* @param bool if true, then the cache id file should be regenerated to
|
|
|
223 |
* trigger a new time-to-live value
|
|
|
224 |
*/
|
|
|
225 |
function saveCache($url, $contents, $lastmodified, $nochange = false, $cacheid = null)
|
|
|
226 |
{
|
| 187 |
mathias |
227 |
$cache_dir = $this->config->get('cache_dir');
|
|
|
228 |
$d = $cache_dir . DIRECTORY_SEPARATOR . md5($url);
|
|
|
229 |
$cacheidfile = $d . 'rest.cacheid';
|
|
|
230 |
$cachefile = $d . 'rest.cachefile';
|
|
|
231 |
|
|
|
232 |
if (!is_dir($cache_dir)) {
|
|
|
233 |
if (System::mkdir(array('-p', $cache_dir)) === false) {
|
|
|
234 |
return PEAR::raiseError("The value of config option cache_dir ($cache_dir) is not a directory and attempts to create the directory failed.");
|
|
|
235 |
}
|
|
|
236 |
}
|
|
|
237 |
|
|
|
238 |
if (!is_writeable($cache_dir)) {
|
|
|
239 |
// If writing to the cache dir is not going to work, silently do nothing.
|
|
|
240 |
// An ugly hack, but retains compat with PEAR 1.9.1 where many commands
|
|
|
241 |
// work fine as non-root user (w/out write access to default cache dir).
|
|
|
242 |
return true;
|
|
|
243 |
}
|
|
|
244 |
|
| 94 |
jpm |
245 |
if ($cacheid === null && $nochange) {
|
|
|
246 |
$cacheid = unserialize(implode('', file($cacheidfile)));
|
|
|
247 |
}
|
|
|
248 |
|
| 187 |
mathias |
249 |
$idData = serialize(array(
|
|
|
250 |
'age' => time(),
|
|
|
251 |
'lastChange' => ($nochange ? $cacheid['lastChange'] : $lastmodified),
|
|
|
252 |
));
|
| 94 |
jpm |
253 |
|
| 187 |
mathias |
254 |
$result = $this->saveCacheFile($cacheidfile, $idData);
|
|
|
255 |
if (PEAR::isError($result)) {
|
|
|
256 |
return $result;
|
|
|
257 |
} elseif ($nochange) {
|
| 94 |
jpm |
258 |
return true;
|
|
|
259 |
}
|
| 187 |
mathias |
260 |
|
|
|
261 |
$result = $this->saveCacheFile($cachefile, serialize($contents));
|
|
|
262 |
if (PEAR::isError($result)) {
|
| 94 |
jpm |
263 |
if (file_exists($cacheidfile)) {
|
| 187 |
mathias |
264 |
@unlink($cacheidfile);
|
| 94 |
jpm |
265 |
}
|
| 187 |
mathias |
266 |
|
|
|
267 |
return $result;
|
| 94 |
jpm |
268 |
}
|
| 187 |
mathias |
269 |
|
| 94 |
jpm |
270 |
return true;
|
|
|
271 |
}
|
|
|
272 |
|
| 187 |
mathias |
273 |
function saveCacheFile($file, $contents)
|
|
|
274 |
{
|
|
|
275 |
$len = strlen($contents);
|
|
|
276 |
|
|
|
277 |
$cachefile_fp = @fopen($file, 'xb'); // x is the O_CREAT|O_EXCL mode
|
|
|
278 |
if ($cachefile_fp !== false) { // create file
|
|
|
279 |
if (fwrite($cachefile_fp, $contents, $len) < $len) {
|
|
|
280 |
fclose($cachefile_fp);
|
|
|
281 |
return PEAR::raiseError("Could not write $file.");
|
|
|
282 |
}
|
|
|
283 |
} else { // update file
|
|
|
284 |
$cachefile_fp = @fopen($file, 'r+b'); // do not truncate file
|
|
|
285 |
if (!$cachefile_fp) {
|
|
|
286 |
return PEAR::raiseError("Could not open $file for writing.");
|
|
|
287 |
}
|
|
|
288 |
|
|
|
289 |
if (OS_WINDOWS) {
|
|
|
290 |
$not_symlink = !is_link($file); // see bug #18834
|
|
|
291 |
} else {
|
|
|
292 |
$cachefile_lstat = lstat($file);
|
|
|
293 |
$cachefile_fstat = fstat($cachefile_fp);
|
|
|
294 |
$not_symlink = $cachefile_lstat['mode'] == $cachefile_fstat['mode']
|
|
|
295 |
&& $cachefile_lstat['ino'] == $cachefile_fstat['ino']
|
|
|
296 |
&& $cachefile_lstat['dev'] == $cachefile_fstat['dev']
|
|
|
297 |
&& $cachefile_fstat['nlink'] === 1;
|
|
|
298 |
}
|
|
|
299 |
|
|
|
300 |
if ($not_symlink) {
|
|
|
301 |
ftruncate($cachefile_fp, 0); // NOW truncate
|
|
|
302 |
if (fwrite($cachefile_fp, $contents, $len) < $len) {
|
|
|
303 |
fclose($cachefile_fp);
|
|
|
304 |
return PEAR::raiseError("Could not write $file.");
|
|
|
305 |
}
|
|
|
306 |
} else {
|
|
|
307 |
fclose($cachefile_fp);
|
|
|
308 |
$link = function_exists('readlink') ? readlink($file) : $file;
|
|
|
309 |
return PEAR::raiseError('SECURITY ERROR: Will not write to ' . $file . ' as it is symlinked to ' . $link . ' - Possible symlink attack');
|
|
|
310 |
}
|
|
|
311 |
}
|
|
|
312 |
|
|
|
313 |
fclose($cachefile_fp);
|
|
|
314 |
return true;
|
|
|
315 |
}
|
|
|
316 |
|
| 94 |
jpm |
317 |
/**
|
|
|
318 |
* Efficiently Download a file through HTTP. Returns downloaded file as a string in-memory
|
|
|
319 |
* This is best used for small files
|
|
|
320 |
*
|
|
|
321 |
* If an HTTP proxy has been configured (http_proxy PEAR_Config
|
|
|
322 |
* setting), the proxy will be used.
|
|
|
323 |
*
|
|
|
324 |
* @param string $url the URL to download
|
|
|
325 |
* @param string $save_dir directory to save file in
|
|
|
326 |
* @param false|string|array $lastmodified header values to check against for caching
|
|
|
327 |
* use false to return the header values from this download
|
|
|
328 |
* @param false|array $accept Accept headers to send
|
|
|
329 |
* @return string|array Returns the contents of the downloaded file or a PEAR
|
|
|
330 |
* error on failure. If the error is caused by
|
|
|
331 |
* socket-related errors, the error object will
|
|
|
332 |
* have the fsockopen error code available through
|
|
|
333 |
* getCode(). If caching is requested, then return the header
|
|
|
334 |
* values.
|
|
|
335 |
*
|
|
|
336 |
* @access public
|
|
|
337 |
*/
|
| 187 |
mathias |
338 |
function downloadHttp($url, $lastmodified = null, $accept = false, $channel = false)
|
| 94 |
jpm |
339 |
{
|
| 187 |
mathias |
340 |
static $redirect = 0;
|
|
|
341 |
// always reset , so we are clean case of error
|
|
|
342 |
$wasredirect = $redirect;
|
|
|
343 |
$redirect = 0;
|
|
|
344 |
|
| 94 |
jpm |
345 |
$info = parse_url($url);
|
|
|
346 |
if (!isset($info['scheme']) || !in_array($info['scheme'], array('http', 'https'))) {
|
|
|
347 |
return PEAR::raiseError('Cannot download non-http URL "' . $url . '"');
|
|
|
348 |
}
|
| 187 |
mathias |
349 |
|
| 94 |
jpm |
350 |
if (!isset($info['host'])) {
|
|
|
351 |
return PEAR::raiseError('Cannot download from non-URL "' . $url . '"');
|
|
|
352 |
}
|
| 187 |
mathias |
353 |
|
|
|
354 |
$host = isset($info['host']) ? $info['host'] : null;
|
|
|
355 |
$port = isset($info['port']) ? $info['port'] : null;
|
|
|
356 |
$path = isset($info['path']) ? $info['path'] : null;
|
|
|
357 |
$schema = (isset($info['scheme']) && $info['scheme'] == 'https') ? 'https' : 'http';
|
|
|
358 |
|
| 94 |
jpm |
359 |
$proxy_host = $proxy_port = $proxy_user = $proxy_pass = '';
|
| 187 |
mathias |
360 |
if ($this->config->get('http_proxy')&&
|
|
|
361 |
$proxy = parse_url($this->config->get('http_proxy'))
|
|
|
362 |
) {
|
| 94 |
jpm |
363 |
$proxy_host = isset($proxy['host']) ? $proxy['host'] : null;
|
| 187 |
mathias |
364 |
if ($schema === 'https') {
|
| 94 |
jpm |
365 |
$proxy_host = 'ssl://' . $proxy_host;
|
|
|
366 |
}
|
| 187 |
mathias |
367 |
|
|
|
368 |
$proxy_port = isset($proxy['port']) ? $proxy['port'] : 8080;
|
|
|
369 |
$proxy_user = isset($proxy['user']) ? urldecode($proxy['user']) : null;
|
|
|
370 |
$proxy_pass = isset($proxy['pass']) ? urldecode($proxy['pass']) : null;
|
|
|
371 |
$proxy_schema = (isset($proxy['scheme']) && $proxy['scheme'] == 'https') ? 'https' : 'http';
|
| 94 |
jpm |
372 |
}
|
| 187 |
mathias |
373 |
|
| 94 |
jpm |
374 |
if (empty($port)) {
|
| 187 |
mathias |
375 |
$port = (isset($info['scheme']) && $info['scheme'] == 'https') ? 443 : 80;
|
| 94 |
jpm |
376 |
}
|
| 187 |
mathias |
377 |
|
|
|
378 |
if (isset($proxy['host'])) {
|
| 94 |
jpm |
379 |
$request = "GET $url HTTP/1.1\r\n";
|
|
|
380 |
} else {
|
|
|
381 |
$request = "GET $path HTTP/1.1\r\n";
|
|
|
382 |
}
|
|
|
383 |
|
| 187 |
mathias |
384 |
$request .= "Host: $host\r\n";
|
| 94 |
jpm |
385 |
$ifmodifiedsince = '';
|
|
|
386 |
if (is_array($lastmodified)) {
|
|
|
387 |
if (isset($lastmodified['Last-Modified'])) {
|
|
|
388 |
$ifmodifiedsince = 'If-Modified-Since: ' . $lastmodified['Last-Modified'] . "\r\n";
|
|
|
389 |
}
|
| 187 |
mathias |
390 |
|
| 94 |
jpm |
391 |
if (isset($lastmodified['ETag'])) {
|
|
|
392 |
$ifmodifiedsince .= "If-None-Match: $lastmodified[ETag]\r\n";
|
|
|
393 |
}
|
|
|
394 |
} else {
|
|
|
395 |
$ifmodifiedsince = ($lastmodified ? "If-Modified-Since: $lastmodified\r\n" : '');
|
|
|
396 |
}
|
| 187 |
mathias |
397 |
|
|
|
398 |
$request .= $ifmodifiedsince .
|
|
|
399 |
"User-Agent: PEAR/1.10.1/PHP/" . PHP_VERSION . "\r\n";
|
|
|
400 |
|
|
|
401 |
$username = $this->config->get('username', null, $channel);
|
|
|
402 |
$password = $this->config->get('password', null, $channel);
|
|
|
403 |
|
| 94 |
jpm |
404 |
if ($username && $password) {
|
|
|
405 |
$tmp = base64_encode("$username:$password");
|
|
|
406 |
$request .= "Authorization: Basic $tmp\r\n";
|
|
|
407 |
}
|
| 187 |
mathias |
408 |
|
| 94 |
jpm |
409 |
if ($proxy_host != '' && $proxy_user != '') {
|
|
|
410 |
$request .= 'Proxy-Authorization: Basic ' .
|
|
|
411 |
base64_encode($proxy_user . ':' . $proxy_pass) . "\r\n";
|
|
|
412 |
}
|
| 187 |
mathias |
413 |
|
| 94 |
jpm |
414 |
if ($accept) {
|
|
|
415 |
$request .= 'Accept: ' . implode(', ', $accept) . "\r\n";
|
|
|
416 |
}
|
| 187 |
mathias |
417 |
|
|
|
418 |
$request .= "Accept-Encoding:\r\n";
|
| 94 |
jpm |
419 |
$request .= "Connection: close\r\n";
|
|
|
420 |
$request .= "\r\n";
|
| 187 |
mathias |
421 |
|
| 94 |
jpm |
422 |
if ($proxy_host != '') {
|
|
|
423 |
$fp = @fsockopen($proxy_host, $proxy_port, $errno, $errstr, 15);
|
|
|
424 |
if (!$fp) {
|
| 187 |
mathias |
425 |
return PEAR::raiseError("Connection to `$proxy_host:$proxy_port' failed: $errstr", -9276);
|
| 94 |
jpm |
426 |
}
|
|
|
427 |
} else {
|
| 187 |
mathias |
428 |
if ($schema === 'https') {
|
| 94 |
jpm |
429 |
$host = 'ssl://' . $host;
|
|
|
430 |
}
|
| 187 |
mathias |
431 |
|
| 94 |
jpm |
432 |
$fp = @fsockopen($host, $port, $errno, $errstr);
|
|
|
433 |
if (!$fp) {
|
|
|
434 |
return PEAR::raiseError("Connection to `$host:$port' failed: $errstr", $errno);
|
|
|
435 |
}
|
|
|
436 |
}
|
| 187 |
mathias |
437 |
|
| 94 |
jpm |
438 |
fwrite($fp, $request);
|
| 187 |
mathias |
439 |
|
| 94 |
jpm |
440 |
$headers = array();
|
| 187 |
mathias |
441 |
$reply = 0;
|
|
|
442 |
while ($line = trim(fgets($fp, 1024))) {
|
|
|
443 |
if (preg_match('/^([^:]+):\s+(.*)\s*\\z/', $line, $matches)) {
|
| 94 |
jpm |
444 |
$headers[strtolower($matches[1])] = trim($matches[2]);
|
|
|
445 |
} elseif (preg_match('|^HTTP/1.[01] ([0-9]{3}) |', $line, $matches)) {
|
| 187 |
mathias |
446 |
$reply = (int)$matches[1];
|
|
|
447 |
if ($reply == 304 && ($lastmodified || ($lastmodified === false))) {
|
| 94 |
jpm |
448 |
return false;
|
|
|
449 |
}
|
| 187 |
mathias |
450 |
|
|
|
451 |
if (!in_array($reply, array(200, 301, 302, 303, 305, 307))) {
|
|
|
452 |
return PEAR::raiseError("File $schema://$host:$port$path not valid (received: $line)");
|
| 94 |
jpm |
453 |
}
|
|
|
454 |
}
|
|
|
455 |
}
|
| 187 |
mathias |
456 |
|
|
|
457 |
if ($reply != 200) {
|
|
|
458 |
if (!isset($headers['location'])) {
|
|
|
459 |
return PEAR::raiseError("File $schema://$host:$port$path not valid (redirected but no location)");
|
|
|
460 |
}
|
|
|
461 |
|
|
|
462 |
if ($wasredirect > 4) {
|
|
|
463 |
return PEAR::raiseError("File $schema://$host:$port$path not valid (redirection looped more than 5 times)");
|
|
|
464 |
}
|
|
|
465 |
|
|
|
466 |
$redirect = $wasredirect + 1;
|
|
|
467 |
return $this->downloadHttp($headers['location'], $lastmodified, $accept, $channel);
|
| 94 |
jpm |
468 |
}
|
| 187 |
mathias |
469 |
|
|
|
470 |
$length = isset($headers['content-length']) ? $headers['content-length'] : -1;
|
|
|
471 |
|
| 94 |
jpm |
472 |
$data = '';
|
|
|
473 |
while ($chunk = @fread($fp, 8192)) {
|
|
|
474 |
$data .= $chunk;
|
|
|
475 |
}
|
|
|
476 |
fclose($fp);
|
| 187 |
mathias |
477 |
|
| 94 |
jpm |
478 |
if ($lastmodified === false || $lastmodified) {
|
|
|
479 |
if (isset($headers['etag'])) {
|
|
|
480 |
$lastmodified = array('ETag' => $headers['etag']);
|
|
|
481 |
}
|
| 187 |
mathias |
482 |
|
| 94 |
jpm |
483 |
if (isset($headers['last-modified'])) {
|
|
|
484 |
if (is_array($lastmodified)) {
|
|
|
485 |
$lastmodified['Last-Modified'] = $headers['last-modified'];
|
|
|
486 |
} else {
|
|
|
487 |
$lastmodified = $headers['last-modified'];
|
|
|
488 |
}
|
|
|
489 |
}
|
| 187 |
mathias |
490 |
|
| 94 |
jpm |
491 |
return array($data, $lastmodified, $headers);
|
|
|
492 |
}
|
| 187 |
mathias |
493 |
|
| 94 |
jpm |
494 |
return $data;
|
|
|
495 |
}
|
|
|
496 |
}
|