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

Line 
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
16@brief Repository modules XML feed reader
17
18Provides an object to parse XML feed of modules from repository.
19This class extends clearbricks netHttp class.
20*/
21class dcRepositoryReader extends netHttp
22{
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 */
36     protected $cache_touch_on_fail = true;
37     /** @var  boolean   Force query server */
38     protected $force = false;
39
40     /**
41      * Constructor.
42      *
43      * Bypass first argument of clearbricks netHttp constructor.
44      */
45     public function __construct()
46     {
47          parent::__construct('');
48          $this->setUserAgent(sprintf('Dotclear/%s)', DC_VERSION));
49     }
50
51     /**
52      * Parse modules feed.
53      *
54      * @param string    $url      XML feed URL
55      * @return     object    dcRepository instance
56      */
57     public function parse($url)
58     {
59          $this->validators = array();
60
61          if ($this->cache_dir) {
62               return $this->withCache($url);
63          }
64          elseif (!$this->getModulesXML($url) || $this->getStatus() != '200') {
65               return false;
66          }
67
68          return new dcRepositoryParser($this->getContent());
69     }
70
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      */
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
92     /**
93      * Set cache directory.
94      *
95      * @param string    $dir      Cache directory
96      * @return     boolean   True if cache dierctory is useable
97      */
98     public function setCacheDir($dir)
99     {
100          $this->cache_dir = null;
101
102          if (!empty($dir) && is_dir($dir) && is_writeable($dir)) {
103               $this->cache_dir = $dir;
104               return true;
105          }
106
107          return false;
108     }
109
110     /**
111      * Set cache TTL.
112      *
113      * @param string    $str      Cache TTL
114      */
115     public function setCacheTTL($str)
116     {
117          $str = trim($str);
118
119          if (!empty($str)) {
120               $this->cache_ttl = substr($str, 0, 1) == '-' ? $str : '-'.$str;
121          }
122     }
123
124     /**
125      * Set force query reposiory.
126      *
127      * @param boolean   $force    True to force query
128      */
129     public function setForce($force)
130     {
131          $this->force = $force;
132     }
133
134     /**
135      * Get repository XML feed URL content.
136      *
137      * @param string    $url      XML feed URL
138      * @return     string    Feed content
139      */
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
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      */
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
171          # Use cache file ?
172          if (@file_exists($cached_file) && !$this->force) {
173               $may_use_cached = true;
174               $ts = @filemtime($cached_file);
175               if ($ts > strtotime($this->cache_ttl)) {
176                    # Direct cache
177                    return unserialize(file_get_contents($cached_file));
178               }
179               $this->setValidator('IfModifiedSince', $ts);
180          }
181
182          # Query repository
183          if (!$this->getModulesXML($url)) {
184               if ($may_use_cached) {
185                    # Touch cache TTL even if query failed ?
186                    if ($this->cache_touch_on_fail) {
187                         @files::touch($cached_file);
188                    }
189                    # Connection failed - fetched from cache
190                    return unserialize(file_get_contents($cached_file));
191               }
192               return false;
193          }
194
195          # Parse response
196          switch ($this->getStatus())
197          {
198               # Not modified, use cache
199               case '304':
200                    @files::touch($cached_file);
201                    return unserialize(file_get_contents($cached_file));
202               # Ok, parse feed
203               case '200':
204                    if ($modules = new dcRepositoryParser($this->getContent())) {
205                         try {
206                              files::makeDir(dirname($cached_file), true);
207                         }
208                         catch (Exception $e) {
209                              return $modules;
210                         }
211
212                         if (($fp = @fopen($cached_file, 'wb'))) {
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
224     /**
225      * Prepare query.
226      *
227      * @return     array     Query headers
228      */
229     protected function buildRequest()
230     {
231          $headers = parent::buildRequest();
232
233          # Cache validators
234          if (!empty($this->validators)) {
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']);
241                    }
242                    else {
243                         $etags = $this->validators['IfNoneMatch'];
244                    }
245                    $headers[] = '';
246               }
247          }
248
249          return $headers;
250     }
251
252     /**
253      * Tweak query cache validator.
254      *
255      * @param string    $key      Validator key
256      * @param string    $value         Validator value
257      */
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