Dotclear

source: inc/core/class.dc.repository.reader.php @ 2214:6d7d4c3f60d9

Revision 2214:6d7d4c3f60d9, 5.9 KB checked in by Denis Jean-Chirstian <contact@…>, 12 years ago (diff)

Document and clean up dcRepository classes

RevLine 
[2146]1<?php
2# -- BEGIN LICENSE BLOCK ---------------------------------------
3#
4# This file is part of Dotclear 2.
5#
6# Copyright (c) 2003-2013 Olivier Meunier & Association Dotclear
7# Licensed under the GPL version 2.0 license.
8# See LICENSE file or
9# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
10#
11# -- END LICENSE BLOCK -----------------------------------------
12if (!defined('DC_RC_PATH')) { return; }
13
14/**
15@ingroup DC_CORE
[2214]16@brief Repository modules XML feed reader
[2146]17
[2214]18Provides an object to parse XML feed of modules from repository.
19This class extends clearbricks netHttp class.
[2146]20*/
21class dcRepositoryReader extends netHttp
22{
[2214]23     /** @var  string    User agent used to query repository */
24     protected $user_agent = 'DotClear.org RepoBrowser/0.1';
25     /** @var  integer   User agent used to query repository */
26     protected $timeout = 5;
27     /** @var  array      HTTP Cache validators */
28     protected $validators = null;
29     /** @var  string    Cache temporary directory */
30     protected $cache_dir = null;
31     /** @var  string    Cache file prefix */
32     protected $cache_file_prefix = 'dcrepo';
33     /** @var  integer   Cache TTL */
34     protected $cache_ttl = '-30 minutes';
35     /** @var  boolean   'Cache' TTL on server failed */
[2146]36     protected $cache_touch_on_fail = true;
[2214]37     /** @var  boolean   Force query server */
38     protected $force = false;
[2146]39
[2214]40     /**
41      * Constructor.
42      *
43      * Bypass first argument of clearbricks netHttp constructor.
44      */
[2146]45     public function __construct()
46     {
47          parent::__construct('');
48          $this->setUserAgent(sprintf('Dotclear/%s)', DC_VERSION));
49     }
50
[2214]51     /**
52      * Parse modules feed.
53      *
54      * @param string    $url      XML feed URL
55      * @return     object    dcRepository instance
56      */
[2146]57     public function parse($url)
58     {
59          $this->validators = array();
[2214]60
61          if ($this->cache_dir) {
[2146]62               return $this->withCache($url);
63          }
[2214]64          elseif (!$this->getModulesXML($url) || $this->getStatus() != '200') {
65               return false;
66          }
[2146]67
[2214]68          return new dcRepositoryParser($this->getContent());
[2146]69     }
70
[2214]71     /**
72      * Quick parse modules feed.
73      *
74      * @param string    $url      XML feed URL
75      * @param string    $cache_dir     Cache directoy or null for no cache
76      * @param boolean   $force         Force query repository
77      * @return     object    Self instance
78      */
[2146]79     public static function quickParse($url, $cache_dir=null, $force=false)
80     {
81          $parser = new self();
82          if ($cache_dir) {
83               $parser->setCacheDir($cache_dir);
84          }
85          if ($force) {
86               $parser->setForce($force);
87          }
88
89          return $parser->parse($url);
90     }
91
[2214]92     /**
93      * Set cache directory.
94      *
95      * @param string    $dir      Cache directory
96      * @return     boolean   True if cache dierctory is useable
97      */
[2146]98     public function setCacheDir($dir)
99     {
100          $this->cache_dir = null;
101
[2214]102          if (!empty($dir) && is_dir($dir) && is_writeable($dir)) {
[2146]103               $this->cache_dir = $dir;
104               return true;
105          }
106
107          return false;
108     }
109
[2214]110     /**
111      * Set cache TTL.
112      *
113      * @param string    $str      Cache TTL
114      */
[2146]115     public function setCacheTTL($str)
116     {
117          $str = trim($str);
[2214]118
119          if (!empty($str)) {
120               $this->cache_ttl = substr($str, 0, 1) == '-' ? $str : '-'.$str;
[2146]121          }
122     }
123
[2214]124     /**
125      * Set force query reposiory.
126      *
127      * @param boolean   $force    True to force query
128      */
[2146]129     public function setForce($force)
130     {
131          $this->force = $force;
132     }
133
[2214]134     /**
135      * Get repository XML feed URL content.
136      *
137      * @param string    $url      XML feed URL
138      * @return     string    Feed content
139      */
[2146]140     protected function getModulesXML($url)
141     {
142          if (!self::readURL($url, $ssl, $host, $port, $path, $user, $pass)) {
143               return false;
144          }
145          $this->setHost($host, $port);
146          $this->useSSL($ssl);
147          $this->setAuthorization($user, $pass);
148
149          return $this->get($path);
150     }
151
[2214]152     /**
153      * Get repository modules list using cache.
154      *
155      * @param string    $url      XML feed URL
156      * @return     array     Feed content or False on fail
157      */
[2146]158     protected function withCache($url)
159     {
160          $url_md5 = md5($url);
161          $cached_file = sprintf('%s/%s/%s/%s/%s.ser',
162               $this->cache_dir,
163               $this->cache_file_prefix,
164               substr($url_md5,0,2),
165               substr($url_md5,2,2),
166               $url_md5
167          );
168
169          $may_use_cached = false;
170
[2214]171          # Use cache file ?
172          if (@file_exists($cached_file) && !$this->force) {
[2146]173               $may_use_cached = true;
174               $ts = @filemtime($cached_file);
[2214]175               if ($ts > strtotime($this->cache_ttl)) {
[2146]176                    # Direct cache
177                    return unserialize(file_get_contents($cached_file));
178               }
179               $this->setValidator('IfModifiedSince', $ts);
180          }
181
[2214]182          # Query repository
183          if (!$this->getModulesXML($url)) {
184               if ($may_use_cached) {
185                    # Touch cache TTL even if query failed ?
[2146]186                    if ($this->cache_touch_on_fail) {
187                         @files::touch($cached_file);
188                    }
[2214]189                    # Connection failed - fetched from cache
[2146]190                    return unserialize(file_get_contents($cached_file));
191               }
192               return false;
193          }
194
[2214]195          # Parse response
[2146]196          switch ($this->getStatus())
197          {
[2214]198               # Not modified, use cache
[2146]199               case '304':
200                    @files::touch($cached_file);
201                    return unserialize(file_get_contents($cached_file));
[2214]202               # Ok, parse feed
[2146]203               case '200':
[2214]204                    if ($modules = new dcRepositoryParser($this->getContent())) {
[2146]205                         try {
206                              files::makeDir(dirname($cached_file), true);
[2214]207                         }
208                         catch (Exception $e) {
[2146]209                              return $modules;
210                         }
211
[2214]212                         if (($fp = @fopen($cached_file, 'wb'))) {
[2146]213                              fwrite($fp, serialize($modules));
214                              fclose($fp);
215                              files::inheritChmod($cached_file);
216                         }
217                         return $modules;
218                    }
219          }
220
221          return false;
222     }
223
[2214]224     /**
225      * Prepare query.
226      *
227      * @return     array     Query headers
228      */
[2146]229     protected function buildRequest()
230     {
231          $headers = parent::buildRequest();
232
233          # Cache validators
[2214]234          if (!empty($this->validators)) {
[2146]235               if (isset($this->validators['IfModifiedSince'])) {
236                    $headers[] = 'If-Modified-Since: '.$this->validators['IfModifiedSince'];
237               }
238               if (isset($this->validators['IfNoneMatch'])) {
239                    if (is_array($this->validators['IfNoneMatch'])) {
240                         $etags = implode(',', $this->validators['IfNoneMatch']);
[2214]241                    }
242                    else {
[2146]243                         $etags = $this->validators['IfNoneMatch'];
244                    }
245                    $headers[] = '';
246               }
247          }
248
249          return $headers;
250     }
251
[2214]252     /**
253      * Tweak query cache validator.
254      *
255      * @param string    $key      Validator key
256      * @param string    $value         Validator value
257      */
[2146]258     private function setValidator($key, $value)
259     {
260          if ($key == 'IfModifiedSince') {
261               $value = gmdate('D, d M Y H:i:s', $value).' GMT';
262          }
263
264          $this->validators[$key] = $value;
265     }
266}
Note: See TracBrowser for help on using the repository browser.

Sites map