Current oav website
This commit is contained in:
264
dotclear._no/inc/core/class.dc.store.reader.php
Normal file
264
dotclear._no/inc/core/class.dc.store.reader.php
Normal file
@ -0,0 +1,264 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Repository modules XML feed reader
|
||||
*
|
||||
* Provides an object to parse XML feed of modules from repository.
|
||||
*
|
||||
* @package Dotclear
|
||||
* @subpackage Core
|
||||
*
|
||||
* @copyright Olivier Meunier & Association Dotclear
|
||||
* @copyright GPL-2.0-only
|
||||
*
|
||||
* @since 2.6
|
||||
*/
|
||||
|
||||
if (!defined('DC_RC_PATH')) {return;}
|
||||
|
||||
class dcStoreReader extends netHttp
|
||||
{
|
||||
/** @var string User agent used to query repository */
|
||||
protected $user_agent = 'DotClear.org RepoBrowser/0.1';
|
||||
/** @var integer User agent used to query repository */
|
||||
protected $timeout = 5;
|
||||
/** @var array HTTP Cache validators */
|
||||
protected $validators = null;
|
||||
/** @var string Cache temporary directory */
|
||||
protected $cache_dir = null;
|
||||
/** @var string Cache file prefix */
|
||||
protected $cache_file_prefix = 'dcrepo';
|
||||
/** @var integer Cache TTL */
|
||||
protected $cache_ttl = '-30 minutes';
|
||||
/** @var boolean 'Cache' TTL on server failed */
|
||||
protected $cache_touch_on_fail = true;
|
||||
/** @var boolean Force query server */
|
||||
protected $force = false;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* Bypass first argument of clearbricks netHttp constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct('');
|
||||
$this->setUserAgent(sprintf('Dotclear/%s)', DC_VERSION));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse modules feed.
|
||||
*
|
||||
* @param string $url XML feed URL
|
||||
* @return object dcStore instance
|
||||
*/
|
||||
public function parse($url)
|
||||
{
|
||||
$this->validators = [];
|
||||
|
||||
if ($this->cache_dir) {
|
||||
return $this->withCache($url);
|
||||
} elseif (!$this->getModulesXML($url) || $this->getStatus() != '200') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return new dcStoreParser($this->getContent());
|
||||
}
|
||||
|
||||
/**
|
||||
* Quick parse modules feed.
|
||||
*
|
||||
* @param string $url XML feed URL
|
||||
* @param string $cache_dir Cache directoy or null for no cache
|
||||
* @param boolean $force Force query repository
|
||||
* @return object Self instance
|
||||
*/
|
||||
public static function quickParse($url, $cache_dir = null, $force = false)
|
||||
{
|
||||
$parser = new self();
|
||||
if ($cache_dir) {
|
||||
$parser->setCacheDir($cache_dir);
|
||||
}
|
||||
if ($force) {
|
||||
$parser->setForce($force);
|
||||
}
|
||||
|
||||
return $parser->parse($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set cache directory.
|
||||
*
|
||||
* @param string $dir Cache directory
|
||||
* @return boolean True if cache dierctory is useable
|
||||
*/
|
||||
public function setCacheDir($dir)
|
||||
{
|
||||
$this->cache_dir = null;
|
||||
|
||||
if (!empty($dir) && is_dir($dir) && is_writeable($dir)) {
|
||||
$this->cache_dir = $dir;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set cache TTL.
|
||||
*
|
||||
* @param string $str Cache TTL
|
||||
*/
|
||||
public function setCacheTTL($str)
|
||||
{
|
||||
$str = trim($str);
|
||||
|
||||
if (!empty($str)) {
|
||||
$this->cache_ttl = substr($str, 0, 1) == '-' ? $str : '-' . $str;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set force query repository.
|
||||
*
|
||||
* @param boolean $force True to force query
|
||||
*/
|
||||
public function setForce($force)
|
||||
{
|
||||
$this->force = $force;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get repository XML feed URL content.
|
||||
*
|
||||
* @param string $url XML feed URL
|
||||
* @return string Feed content
|
||||
*/
|
||||
protected function getModulesXML($url)
|
||||
{
|
||||
if (!self::readURL($url, $ssl, $host, $port, $path, $user, $pass)) {
|
||||
return false;
|
||||
}
|
||||
$this->setHost($host, $port);
|
||||
$this->useSSL($ssl);
|
||||
$this->setAuthorization($user, $pass);
|
||||
|
||||
try {
|
||||
return $this->get($path);
|
||||
} catch (Exception $e) {
|
||||
// @todo Log error when repository query fail
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get repository modules list using cache.
|
||||
*
|
||||
* @param string $url XML feed URL
|
||||
* @return array Feed content or False on fail
|
||||
*/
|
||||
protected function withCache($url)
|
||||
{
|
||||
$url_md5 = md5($url);
|
||||
$cached_file = sprintf('%s/%s/%s/%s/%s.ser',
|
||||
$this->cache_dir,
|
||||
$this->cache_file_prefix,
|
||||
substr($url_md5, 0, 2),
|
||||
substr($url_md5, 2, 2),
|
||||
$url_md5
|
||||
);
|
||||
|
||||
$may_use_cached = false;
|
||||
|
||||
# Use cache file ?
|
||||
if (@file_exists($cached_file) && !$this->force) {
|
||||
$may_use_cached = true;
|
||||
$ts = @filemtime($cached_file);
|
||||
if ($ts > strtotime($this->cache_ttl)) {
|
||||
# Direct cache
|
||||
return unserialize(file_get_contents($cached_file));
|
||||
}
|
||||
$this->setValidator('IfModifiedSince', $ts);
|
||||
}
|
||||
|
||||
# Query repository
|
||||
if (!$this->getModulesXML($url)) {
|
||||
if ($may_use_cached) {
|
||||
# Touch cache TTL even if query failed ?
|
||||
if ($this->cache_touch_on_fail) {
|
||||
@files::touch($cached_file);
|
||||
}
|
||||
# Connection failed - fetched from cache
|
||||
return unserialize(file_get_contents($cached_file));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
# Parse response
|
||||
switch ($this->getStatus()) {
|
||||
# Not modified, use cache
|
||||
case '304':
|
||||
@files::touch($cached_file);
|
||||
return unserialize(file_get_contents($cached_file));
|
||||
# Ok, parse feed
|
||||
case '200':
|
||||
if ($modules = new dcStoreParser($this->getContent())) {
|
||||
try {
|
||||
files::makeDir(dirname($cached_file), true);
|
||||
} catch (Exception $e) {
|
||||
return $modules;
|
||||
}
|
||||
|
||||
if (($fp = @fopen($cached_file, 'wb'))) {
|
||||
fwrite($fp, serialize($modules));
|
||||
fclose($fp);
|
||||
files::inheritChmod($cached_file);
|
||||
}
|
||||
return $modules;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare query.
|
||||
*
|
||||
* @return array Query headers
|
||||
*/
|
||||
protected function buildRequest()
|
||||
{
|
||||
$headers = parent::buildRequest();
|
||||
|
||||
# Cache validators
|
||||
if (!empty($this->validators)) {
|
||||
if (isset($this->validators['IfModifiedSince'])) {
|
||||
$headers[] = 'If-Modified-Since: ' . $this->validators['IfModifiedSince'];
|
||||
}
|
||||
if (isset($this->validators['IfNoneMatch'])) {
|
||||
if (is_array($this->validators['IfNoneMatch'])) {
|
||||
$etags = implode(',', $this->validators['IfNoneMatch']);
|
||||
} else {
|
||||
$etags = $this->validators['IfNoneMatch'];
|
||||
}
|
||||
$headers[] = '';
|
||||
}
|
||||
}
|
||||
|
||||
return $headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tweak query cache validator.
|
||||
*
|
||||
* @param string $key Validator key
|
||||
* @param string $value Validator value
|
||||
*/
|
||||
private function setValidator($key, $value)
|
||||
{
|
||||
if ($key == 'IfModifiedSince') {
|
||||
$value = gmdate('D, d M Y H:i:s', $value) . ' GMT';
|
||||
}
|
||||
|
||||
$this->validators[$key] = $value;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user