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 = array(); 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; } }