Dotclear

source: inc/core/class.dc.store.php @ 3731:3770620079d4

Revision 3731:3770620079d4, 8.3 KB checked in by franck <carnet.franck.paul@…>, 8 years ago (diff)

Simplify licence block at the beginning of each file

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

Sites map