59 $cachefile = $this->config->get(
'cache_dir') . DIRECTORY_SEPARATOR .
60 md5($url) .
'rest.cachefile';
62 if (file_exists($cachefile)) {
63 return unserialize(implode(
'', file($cachefile)));
66 return $this->
retrieveData($url, $accept, $forcestring, $channel);
77 function retrieveData($url, $accept =
false, $forcestring =
false, $channel =
false)
84 $file = $trieddownload =
false;
85 if (!isset($this->_options[
'offline'])) {
86 $trieddownload =
true;
87 $file = $this->
downloadHttp($url, $cacheId ? $cacheId[
'lastChange'] :
false, $accept, $channel);
90 if (PEAR::isError($file)) {
91 if ($file->getCode() !== -9276) {
95 $trieddownload =
false;
101 if (!PEAR::isError($ret) && $trieddownload) {
105 return PEAR::raiseError(
$result->getMessage());
112 if (is_array($file)) {
114 $lastmodified = $file[1];
118 $lastmodified =
false;
125 return PEAR::raiseError(
$result->getMessage());
131 if (isset($headers[
'content-type'])) {
132 $content_type = explode(
";", $headers[
'content-type']);
133 $content_type = $content_type[0];
134 switch ($content_type) {
136 case 'application/xml' :
138 if ($content_type ===
'text/plain') {
139 $check = substr($content, 0, 5);
140 if ($check !==
'<?xml') {
147 $err = $parser->parse($content);
148 PEAR::popErrorHandling();
149 if (PEAR::isError($err)) {
150 return PEAR::raiseError(
'Invalid xml downloaded from "' . $url .
'": ' .
153 $content = $parser->getData();
161 $parser->
parse($content);
162 $content = $parser->getData();
167 return PEAR::raiseError(
$result->getMessage());
225 function saveCache($url, $contents, $lastmodified, $nochange =
false, $cacheid =
null)
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';
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.");
238 if (!is_writeable($cache_dir)) {
245 if ($cacheid ===
null && $nochange) {
246 $cacheid = unserialize(implode(
'', file($cacheidfile)));
249 $idData = serialize(array(
251 'lastChange' => ($nochange ? $cacheid[
'lastChange'] : $lastmodified),
257 } elseif ($nochange) {
263 if (file_exists($cacheidfile)) {
264 @unlink($cacheidfile);
275 $len = strlen($contents);
277 $cachefile_fp = @fopen($file,
'xb');
278 if ($cachefile_fp !==
false) {
279 if (fwrite($cachefile_fp, $contents, $len) < $len) {
280 fclose($cachefile_fp);
281 return PEAR::raiseError(
"Could not write $file.");
284 $cachefile_fp = @fopen($file,
'r+b');
285 if (!$cachefile_fp) {
286 return PEAR::raiseError(
"Could not open $file for writing.");
290 $not_symlink = !is_link($file);
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;
301 ftruncate($cachefile_fp, 0);
302 if (fwrite($cachefile_fp, $contents, $len) < $len) {
303 fclose($cachefile_fp);
304 return PEAR::raiseError(
"Could not write $file.");
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');
313 fclose($cachefile_fp);
338 function downloadHttp($url, $lastmodified =
null, $accept =
false, $channel =
false)
340 static $redirect = 0;
342 $wasredirect = $redirect;
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 .
'"');
350 if (!isset($info[
'host'])) {
351 return PEAR::raiseError(
'Cannot download from non-URL "' . $url .
'"');
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';
362 $port = (isset($info[
'scheme']) && $info[
'scheme'] ==
'https') ? 443 : 80;
365 if ($proxy->isProxyConfigured() && $schema ===
'http') {
366 $request =
"GET $url HTTP/1.1\r\n";
368 $request =
"GET $path HTTP/1.1\r\n";
371 $request .=
"Host: $host\r\n";
372 $ifmodifiedsince =
'';
373 if (is_array($lastmodified)) {
374 if (isset($lastmodified[
'Last-Modified'])) {
375 $ifmodifiedsince =
'If-Modified-Since: ' . $lastmodified[
'Last-Modified'] .
"\r\n";
378 if (isset($lastmodified[
'ETag'])) {
379 $ifmodifiedsince .=
"If-None-Match: $lastmodified[ETag]\r\n";
382 $ifmodifiedsince = ($lastmodified ?
"If-Modified-Since: $lastmodified\r\n" :
'');
385 $request .= $ifmodifiedsince .
386 "User-Agent: PEAR/1.10.18/PHP/" . PHP_VERSION .
"\r\n";
388 $username = $this->config->get(
'username',
null, $channel);
389 $password = $this->config->get(
'password',
null, $channel);
391 if ($username && $password) {
392 $tmp = base64_encode(
"$username:$password");
393 $request .=
"Authorization: Basic $tmp\r\n";
396 $proxyAuth = $proxy->getProxyAuth();
398 $request .=
'Proxy-Authorization: Basic ' .
403 $request .=
'Accept: ' . implode(
', ', $accept) .
"\r\n";
406 $request .=
"Accept-Encoding:\r\n";
407 $request .=
"Connection: close\r\n";
410 $secure = ($schema ==
'https');
411 $fp = $proxy->openSocket($host,
$port, $secure);
412 if (PEAR::isError($fp)) {
416 fwrite($fp, $request);
420 while ($line = trim(fgets($fp, 1024))) {
421 if (preg_match(
'/^([^:]+):\s+(.*)\s*\\z/', $line, $matches)) {
422 $headers[strtolower($matches[1])] = trim($matches[2]);
423 } elseif (preg_match(
'|^HTTP/1.[01] ([0-9]{3}) |', $line, $matches)) {
424 $reply = (int)$matches[1];
425 if ($reply == 304 && ($lastmodified || ($lastmodified ===
false))) {
429 if (!in_array($reply, array(200, 301, 302, 303, 305, 307))) {
430 return PEAR::raiseError(
"File $schema://$host:$port$path not valid (received: $line)");
436 if (!isset($headers[
'location'])) {
437 return PEAR::raiseError(
"File $schema://$host:$port$path not valid (redirected but no location)");
440 if ($wasredirect > 4) {
441 return PEAR::raiseError(
"File $schema://$host:$port$path not valid (redirection looped more than 5 times)");
444 $redirect = $wasredirect + 1;
445 return $this->
downloadHttp($headers[
'location'], $lastmodified, $accept, $channel);
448 $length = isset($headers[
'content-length']) ? $headers[
'content-length'] : -1;
451 if (isset($headers[
'transfer-encoding']) && strtolower($headers[
'transfer-encoding']) ===
'chunked') {
453 $chunk_size = hexdec(fgets($fp));
454 if ($chunk_size === 0) {
457 $data .= fread($fp, $chunk_size);
461 while ($chunk = @fread($fp, 8192)) {
467 if ($lastmodified ===
false || $lastmodified) {
468 if (isset($headers[
'etag'])) {
469 $lastmodified = array(
'ETag' => $headers[
'etag']);
472 if (isset($headers[
'last-modified'])) {
473 if (is_array($lastmodified)) {
474 $lastmodified[
'Last-Modified'] = $headers[
'last-modified'];
476 $lastmodified = $headers[
'last-modified'];
480 return array($data, $lastmodified, $headers);