Dotclear

source: inc/core/class.dc.store.php @ 3730:5c45a5df9a59

Revision 3730:5c45a5df9a59, 8.5 KB checked in by franck <carnet.franck.paul@…>, 8 years ago (diff)

Code formatting (PSR-2)

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@since 2.6
18
19Provides an object to parse XML feed of modules from repository.
20 */
21class dcStore
22{
23    /** @var    object    dcCore instance */
24    public $core;
25    /** @var    object    dcModules instance */
26    public $modules;
27
28    /** @var    array    Modules fields to search on and their weighting */
29    public static $weighting = array('id' => 10, 'name' => 8, 'author' => 6, 'tags' => 4, 'desc' => 2);
30
31    /** @var    string    User agent used to query repository */
32    protected $user_agent = 'DotClear.org RepoBrowser/0.1';
33    /** @var    string    XML feed URL */
34    protected $xml_url;
35    /** @var    array    Array of new/update modules from repository */
36    protected $data;
37
38    /**
39     * Constructor.
40     *
41     * @param    object    $modules        dcModules instance
42     * @param    string    $xml_url        XML feed URL
43     */
44    public function __construct(dcModules $modules, $xml_url)
45    {
46        $this->core       = $modules->core;
47        $this->modules    = $modules;
48        $this->xml_url    = $xml_url;
49        $this->user_agent = sprintf('Dotclear/%s)', DC_VERSION);
50
51        $this->check();
52    }
53
54    /**
55     * Check repository.
56     *
57     * @param    boolean    $force        Force query repository
58     * @return    boolean    True if get feed or cache
59     */
60    public function check($force = false)
61    {
62        if (!$this->xml_url) {
63            return false;
64        }
65        if (($parser = dcStoreReader::quickParse($this->xml_url, DC_TPL_CACHE, $force)) === false) {
66            return false;
67        }
68
69        $raw_datas = $parser->getModules();
70
71        uasort($raw_datas, array('self', 'sort'));
72
73        $skipped = array_keys($this->modules->getDisabledModules());
74        foreach ($skipped as $p_id) {
75            if (isset($raw_datas[$p_id])) {
76                unset($raw_datas[$p_id]);
77            }
78        }
79
80        $updates = array();
81        $current = $this->modules->getModules();
82        foreach ($current as $p_id => $p_infos) {
83            if (isset($raw_datas[$p_id])) {
84                if (dcUtils::versionsCompare($raw_datas[$p_id]['version'], $p_infos['version'], '>')) {
85                    $updates[$p_id]                    = $raw_datas[$p_id];
86                    $updates[$p_id]['root']            = $p_infos['root'];
87                    $updates[$p_id]['root_writable']   = $p_infos['root_writable'];
88                    $updates[$p_id]['current_version'] = $p_infos['version'];
89                }
90                unset($raw_datas[$p_id]);
91            }
92        }
93
94        $this->data = array(
95            'new'    => $raw_datas,
96            'update' => $updates
97        );
98
99        return true;
100    }
101
102    /**
103     * Get a list of modules.
104     *
105     * @param    boolean    $update    True to get update modules, false for new ones
106     * @return    array    List of update/new modules
107     */
108    public function get($update = false)
109    {
110        return $this->data[$update ? 'update' : 'new'];
111    }
112
113    /**
114     * Search a module.
115     *
116     * Search string is cleaned, split and compare to split:
117     * - module id and clean id,
118     * - module name, clean name,
119     * - module desccription.
120     *
121     * Every time a part of query is find on module,
122     * result accuracy grow. Result is sorted by accuracy.
123     *
124     * @param    string    $pattern    String to search
125     * @return    array    Match modules
126     */
127    public function search($pattern)
128    {
129        $result = array();
130
131        # Split query into small clean words
132        if (!($patterns = self::patternize($pattern))) {
133            return $result;
134        }
135
136        # For each modules
137        foreach ($this->data['new'] as $id => $module) {
138            $module['id'] = $id;
139
140            # Loop through required module fields
141            foreach (self::$weighting as $field => $weight) {
142
143                # Skip fields which not exsist on module
144                if (empty($module[$field])) {
145                    continue;
146                }
147
148                # Split field value into small clean word
149                if (!($subjects = self::patternize($module[$field]))) {
150                    continue;
151                }
152
153                # Check contents
154                if (!($nb = preg_match_all('/(' . implode('|', $patterns) . ')/', implode(' ', $subjects), $_))) {
155                    continue;
156                }
157
158                # Add module to result
159                if (!isset($sorter[$id])) {
160                    $sorter[$id] = 0;
161                    $result[$id] = $module;
162                }
163
164                # Increment score by matches count * field weight
165                $sorter[$id] += $nb * $weight;
166                $result[$id]['score'] = $sorter[$id];
167            }
168        }
169        # Sort response by matches count
170        if (!empty($result)) {
171            array_multisort($sorter, SORT_DESC, $result);
172        }
173        return $result;
174    }
175
176    /**
177     * Quick download and install module.
178     *
179     * @param    string    $url    Module package URL
180     * @param    string    $dest    Path to install module
181     * @return    integer        1 = installed, 2 = update
182     */
183    public function process($url, $dest)
184    {
185        $this->download($url, $dest);
186        return $this->install($dest);
187    }
188
189    /**
190     * Download a module.
191     *
192     * @param    string    $url    Module package URL
193     * @param    string    $dest    Path to put module package
194     */
195    public function download($url, $dest)
196    {
197        // Check and add default protocol if necessary
198        if (!preg_match('%^http[s]?:\/\/%', $url)) {
199            $url = 'http://' . $url;
200        }
201        // Download package
202        if ($client = netHttp::initClient($url, $path)) {
203            try {
204                $client->setUserAgent($this->user_agent);
205                $client->useGzip(false);
206                $client->setPersistReferers(false);
207                $client->setOutput($dest);
208                $client->get($path);
209                unset($client);
210            } catch (Exception $e) {
211                unset($client);
212                throw new Exception(__('An error occurred while downloading the file.'));
213            }
214        } else {
215            throw new Exception(__('An error occurred while downloading the file.'));
216        }
217    }
218
219    /**
220     * Install a previously downloaded module.
221     *
222     * @param    string    $path    Module package URL
223     * @param    string    $path    Path to module package
224     * @return    integer        1 = installed, 2 = update
225     */
226    public function install($path)
227    {
228        return dcModules::installPackage($path, $this->modules);
229    }
230
231    /**
232     * User Agent String.
233     *
234     * @param    string    $str        User agent string
235     */
236    public function agent($str)
237    {
238        $this->user_agent = $str;
239    }
240
241    /**
242     * Split and clean pattern.
243     *
244     * @param    string    $str        String to sanitize
245     * @return    array    Array of cleaned pieces of string or false if none
246     */
247    public static function patternize($str)
248    {
249        $arr = array();
250
251        foreach (explode(' ', $str) as $_) {
252            $_ = strtolower(preg_replace('/[^A-Za-z0-9]/', '', $_));
253            if (strlen($_) > 2) {
254                $arr[] = $_;
255            }
256        }
257
258        return empty($arr) ? false : $arr;
259    }
260
261    /**
262     * Compare version.
263     *
264     * @param    string    $v1        Version
265     * @param    string    $v2        Version
266     * @param    string    $op        Comparison operator
267     * @return    boolean    True is comparison is true, dude!
268     */
269    private static function compare($v1, $v2, $op)
270    {
271        return version_compare(
272            preg_replace('!-r(\d+)$!', '-p$1', $v1),
273            preg_replace('!-r(\d+)$!', '-p$1', $v2),
274            $op
275        );
276    }
277
278    /**
279     * Sort modules list.
280     *
281     * @param    array    $a        A module
282     * @param    array    $b        A module
283     * @return    integer
284     */
285    private static function sort($a, $b)
286    {
287        $c = strtolower($a['id']);
288        $d = strtolower($b['id']);
289        if ($c == $d) {
290            return 0;
291        }
292        return ($c < $d) ? -1 : 1;
293    }
294}
Note: See TracBrowser for help on using the repository browser.

Sites map