[ Index ] |
|
Code source de PHP PEAR 1.4.5 |
1 <?php 2 /** 3 * PEAR_REST 4 * 5 * PHP versions 4 and 5 6 * 7 * LICENSE: This source file is subject to version 3.0 of the PHP license 8 * that is available through the world-wide-web at the following URI: 9 * http://www.php.net/license/3_0.txt. If you did not receive a copy of 10 * the PHP License and are unable to obtain it through the web, please 11 * send a note to license@php.net so we can mail you a copy immediately. 12 * 13 * @category pear 14 * @package PEAR 15 * @author Greg Beaver <cellog@php.net> 16 * @copyright 1997-2006 The PHP Group 17 * @license http://www.php.net/license/3_0.txt PHP License 3.0 18 * @version CVS: $Id: REST.php,v 1.21 2006/03/27 04:33:11 cellog Exp $ 19 * @link http://pear.php.net/package/PEAR 20 * @since File available since Release 1.4.0a1 21 */ 22 23 /** 24 * For downloading xml files 25 */ 26 require_once 'PEAR.php'; 27 require_once 'PEAR/XMLParser.php'; 28 29 /** 30 * Intelligently retrieve data, following hyperlinks if necessary, and re-directing 31 * as well 32 * @category pear 33 * @package PEAR 34 * @author Greg Beaver <cellog@php.net> 35 * @copyright 1997-2006 The PHP Group 36 * @license http://www.php.net/license/3_0.txt PHP License 3.0 37 * @version Release: 1.5.0 38 * @link http://pear.php.net/package/PEAR 39 * @since Class available since Release 1.4.0a1 40 */ 41 class PEAR_REST 42 { 43 var $config; 44 var $_options; 45 function PEAR_REST(&$config, $options = array()) 46 { 47 $this->config = &$config; 48 $this->_options = $options; 49 } 50 51 /** 52 * Retrieve REST data, but always retrieve the local cache if it is available. 53 * 54 * This is useful for elements that should never change, such as information on a particular 55 * release 56 * @param string full URL to this resource 57 * @param array|false contents of the accept-encoding header 58 * @param boolean if true, xml will be returned as a string, otherwise, xml will be 59 * parsed using PEAR_XMLParser 60 * @return string|array 61 */ 62 function retrieveCacheFirst($url, $accept = false, $forcestring = false) 63 { 64 $cachefile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR . 65 md5($url) . 'rest.cachefile'; 66 if (file_exists($cachefile)) { 67 return unserialize(implode('', file($cachefile))); 68 } 69 return $this->retrieveData($url, $accept, $forcestring); 70 } 71 72 /** 73 * Retrieve a remote REST resource 74 * @param string full URL to this resource 75 * @param array|false contents of the accept-encoding header 76 * @param boolean if true, xml will be returned as a string, otherwise, xml will be 77 * parsed using PEAR_XMLParser 78 * @return string|array 79 */ 80 function retrieveData($url, $accept = false, $forcestring = false) 81 { 82 $cacheId = $this->getCacheId($url); 83 if ($ret = $this->useLocalCache($url, $cacheId)) { 84 return $ret; 85 } 86 if (!isset($this->_options['offline'])) { 87 $trieddownload = true; 88 $file = $this->downloadHttp($url, $cacheId ? $cacheId['lastChange'] : false, $accept); 89 } else { 90 $trieddownload = false; 91 $file = false; 92 } 93 if (PEAR::isError($file)) { 94 if ($file->getCode() == -9276) { 95 $trieddownload = false; 96 $file = false; // use local copy if available on socket connect error 97 } else { 98 return $file; 99 } 100 } 101 if (!$file) { 102 $ret = $this->getCache($url); 103 if (!PEAR::isError($ret) && $trieddownload) { 104 // reset the age of the cache if the server says it was unmodified 105 $this->saveCache($url, $ret, null, true, $cacheId); 106 } 107 return $ret; 108 } 109 if (is_array($file)) { 110 $headers = $file[2]; 111 $lastmodified = $file[1]; 112 $content = $file[0]; 113 } else { 114 $content = $file; 115 $lastmodified = false; 116 $headers = array(); 117 } 118 if ($forcestring) { 119 $this->saveCache($url, $content, $lastmodified, false, $cacheId); 120 return $content; 121 } 122 if (isset($headers['content-type'])) { 123 switch ($headers['content-type']) { 124 case 'text/xml' : 125 case 'application/xml' : 126 $parser = new PEAR_XMLParser; 127 PEAR::pushErrorHandling(PEAR_ERROR_RETURN); 128 $err = $parser->parse($content); 129 PEAR::popErrorHandling(); 130 if (PEAR::isError($err)) { 131 return PEAR::raiseError('Invalid xml downloaded from "' . $url . '": ' . 132 $err->getMessage()); 133 } 134 $content = $parser->getData(); 135 case 'text/html' : 136 default : 137 // use it as a string 138 } 139 } else { 140 // assume XML 141 $parser = new PEAR_XMLParser; 142 $parser->parse($content); 143 $content = $parser->getData(); 144 } 145 $this->saveCache($url, $content, $lastmodified, false, $cacheId); 146 return $content; 147 } 148 149 function useLocalCache($url, $cacheid = null) 150 { 151 if ($cacheid === null) { 152 $cacheidfile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR . 153 md5($url) . 'rest.cacheid'; 154 if (file_exists($cacheidfile)) { 155 $cacheid = unserialize(implode('', file($cacheidfile))); 156 } else { 157 return false; 158 } 159 } 160 $cachettl = $this->config->get('cache_ttl'); 161 // If cache is newer than $cachettl seconds, we use the cache! 162 if (time() - $cacheid['age'] < $cachettl) { 163 return $this->getCache($url); 164 } 165 return false; 166 } 167 168 function getCacheId($url) 169 { 170 $cacheidfile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR . 171 md5($url) . 'rest.cacheid'; 172 if (file_exists($cacheidfile)) { 173 $ret = unserialize(implode('', file($cacheidfile))); 174 return $ret; 175 } else { 176 return false; 177 } 178 } 179 180 function getCache($url) 181 { 182 $cachefile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR . 183 md5($url) . 'rest.cachefile'; 184 if (file_exists($cachefile)) { 185 return unserialize(implode('', file($cachefile))); 186 } else { 187 return PEAR::raiseError('No cached content available for "' . $url . '"'); 188 } 189 } 190 191 /** 192 * @param string full URL to REST resource 193 * @param string original contents of the REST resource 194 * @param array HTTP Last-Modified and ETag headers 195 * @param bool if true, then the cache id file should be regenerated to 196 * trigger a new time-to-live value 197 */ 198 function saveCache($url, $contents, $lastmodified, $nochange = false, $cacheid = null) 199 { 200 $cacheidfile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR . 201 md5($url) . 'rest.cacheid'; 202 $cachefile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR . 203 md5($url) . 'rest.cachefile'; 204 if ($cacheid === null && $nochange) { 205 $cacheid = unserialize(implode('', file($cacheidfile))); 206 } 207 208 $fp = @fopen($cacheidfile, 'wb'); 209 if (!$fp) { 210 $cache_dir = $this->config->get('cache_dir'); 211 if (!is_dir($cache_dir)) { 212 System::mkdir(array('-p', $cache_dir)); 213 $fp = @fopen($cacheidfile, 'wb'); 214 if (!$fp) { 215 return false; 216 } 217 } else { 218 return false; 219 } 220 } 221 222 if ($nochange) { 223 fwrite($fp, serialize(array( 224 'age' => time(), 225 'lastChange' => $cacheid['lastChange'], 226 ))); 227 fclose($fp); 228 return true; 229 } else { 230 fwrite($fp, serialize(array( 231 'age' => time(), 232 'lastChange' => $lastmodified, 233 ))); 234 } 235 fclose($fp); 236 $fp = @fopen($cachefile, 'wb'); 237 if (!$fp) { 238 if (file_exists($cacheidfile)) { 239 @unlink($cacheidfile); 240 } 241 return false; 242 } 243 fwrite($fp, serialize($contents)); 244 fclose($fp); 245 return true; 246 } 247 248 /** 249 * Efficiently Download a file through HTTP. Returns downloaded file as a string in-memory 250 * This is best used for small files 251 * 252 * If an HTTP proxy has been configured (http_proxy PEAR_Config 253 * setting), the proxy will be used. 254 * 255 * @param string $url the URL to download 256 * @param string $save_dir directory to save file in 257 * @param false|string|array $lastmodified header values to check against for caching 258 * use false to return the header values from this download 259 * @param false|array $accept Accept headers to send 260 * @return string|array Returns the contents of the downloaded file or a PEAR 261 * error on failure. If the error is caused by 262 * socket-related errors, the error object will 263 * have the fsockopen error code available through 264 * getCode(). If caching is requested, then return the header 265 * values. 266 * 267 * @access public 268 */ 269 function downloadHttp($url, $lastmodified = null, $accept = false) 270 { 271 $info = parse_url($url); 272 if (!isset($info['scheme']) || !in_array($info['scheme'], array('http', 'https'))) { 273 return PEAR::raiseError('Cannot download non-http URL "' . $url . '"'); 274 } 275 if (!isset($info['host'])) { 276 return PEAR::raiseError('Cannot download from non-URL "' . $url . '"'); 277 } else { 278 $host = $info['host']; 279 if (!array_key_exists('port', $info)) { 280 $info['port'] = null; 281 } 282 if (!array_key_exists('path', $info)) { 283 $info['path'] = null; 284 } 285 $port = $info['port']; 286 $path = $info['path']; 287 } 288 $proxy_host = $proxy_port = $proxy_user = $proxy_pass = ''; 289 if ($this->config->get('http_proxy')&& 290 $proxy = parse_url($this->config->get('http_proxy'))) { 291 $proxy_host = isset($proxy['host']) ? $proxy['host'] : null; 292 if (isset($proxy['scheme']) && $proxy['scheme'] == 'https') { 293 $proxy_host = 'ssl://' . $proxy_host; 294 } 295 $proxy_port = isset($proxy['port']) ? $proxy['port'] : 8080; 296 $proxy_user = isset($proxy['user']) ? urldecode($proxy['user']) : null; 297 $proxy_pass = isset($proxy['pass']) ? urldecode($proxy['pass']) : null; 298 } 299 if (empty($port)) { 300 if (isset($info['scheme']) && $info['scheme'] == 'https') { 301 $port = 443; 302 } else { 303 $port = 80; 304 } 305 } 306 If (isset($proxy['host'])) { 307 $request = "GET $url HTTP/1.1\r\n"; 308 } else { 309 $request = "GET $path HTTP/1.1\r\n"; 310 } 311 312 $ifmodifiedsince = ''; 313 if (is_array($lastmodified)) { 314 if (isset($lastmodified['Last-Modified'])) { 315 $ifmodifiedsince = 'If-Modified-Since: ' . $lastmodified['Last-Modified'] . "\r\n"; 316 } 317 if (isset($lastmodified['ETag'])) { 318 $ifmodifiedsince .= "If-None-Match: $lastmodified[ETag]\r\n"; 319 } 320 } else { 321 $ifmodifiedsince = ($lastmodified ? "If-Modified-Since: $lastmodified\r\n" : ''); 322 } 323 $request .= "Host: $host:$port\r\n" . $ifmodifiedsince . 324 "User-Agent: PEAR/1.5.0/PHP/" . PHP_VERSION . "\r\n"; 325 $username = $this->config->get('username'); 326 $password = $this->config->get('password'); 327 if ($username && $password) { 328 $tmp = base64_encode("$username:$password"); 329 $request .= "Authorization: Basic $tmp\r\n"; 330 } 331 if ($proxy_host != '' && $proxy_user != '') { 332 $request .= 'Proxy-Authorization: Basic ' . 333 base64_encode($proxy_user . ':' . $proxy_pass) . "\r\n"; 334 } 335 if ($accept) { 336 $request .= 'Accept: ' . implode(', ', $accept) . "\r\n"; 337 } 338 $request .= "Connection: close\r\n"; 339 $request .= "\r\n"; 340 if ($proxy_host != '') { 341 $fp = @fsockopen($proxy_host, $proxy_port, $errno, $errstr, 15); 342 if (!$fp) { 343 return PEAR::raiseError("Connection to `$proxy_host:$proxy_port' failed: $errstr", 344 -9276); 345 } 346 } else { 347 if (isset($info['scheme']) && $info['scheme'] == 'https') { 348 $host = 'ssl://' . $host; 349 } 350 $fp = @fsockopen($host, $port, $errno, $errstr); 351 if (!$fp) { 352 return PEAR::raiseError("Connection to `$host:$port' failed: $errstr", $errno); 353 } 354 } 355 fwrite($fp, $request); 356 $headers = array(); 357 while (trim($line = fgets($fp, 1024))) { 358 if (preg_match('/^([^:]+):\s+(.*)\s*$/', $line, $matches)) { 359 $headers[strtolower($matches[1])] = trim($matches[2]); 360 } elseif (preg_match('|^HTTP/1.[01] ([0-9]{3}) |', $line, $matches)) { 361 if ($matches[1] == 304 && ($lastmodified || ($lastmodified === false))) { 362 return false; 363 } 364 if ($matches[1] != 200) { 365 return PEAR::raiseError("File http://$host:$port$path not valid (received: $line)", (int) $matches[1]); 366 } 367 } 368 } 369 if (isset($headers['content-length'])) { 370 $length = $headers['content-length']; 371 } else { 372 $length = -1; 373 } 374 $data = ''; 375 while ($chunk = @fread($fp, 8192)) { 376 $data .= $chunk; 377 } 378 fclose($fp); 379 if ($lastmodified === false || $lastmodified) { 380 if (isset($headers['etag'])) { 381 $lastmodified = array('ETag' => $headers['etag']); 382 } 383 if (isset($headers['last-modified'])) { 384 if (is_array($lastmodified)) { 385 $lastmodified['Last-Modified'] = $headers['last-modified']; 386 } else { 387 $lastmodified = $headers['last-modified']; 388 } 389 } 390 return array($data, $lastmodified, $headers); 391 } 392 return $data; 393 } 394 } 395 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Sun Feb 25 14:08:00 2007 | par Balluche grâce à PHPXref 0.7 |