Failed Conditions
Push — interwiki-remove-golucky ( 52fcdb...768be5 )
by Henry
12:48 queued 09:48
created

lib/plugins/extension/helper/repository.php (2 issues)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * DokuWiki Plugin extension (Helper Component)
4
 *
5
 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
6
 * @author  Michael Hamann <[email protected]>
7
 */
8
9
use dokuwiki\Cache\Cache;
0 ignored issues
show
This use statement conflicts with another class in this namespace, Cache.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
10
use dokuwiki\HTTP\DokuHTTPClient;
0 ignored issues
show
This use statement conflicts with another class in this namespace, DokuHTTPClient.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
11
use dokuwiki\Extension\PluginController;
12
13
/**
14
 * Class helper_plugin_extension_repository provides access to the extension repository on dokuwiki.org
15
 */
16
class helper_plugin_extension_repository extends DokuWiki_Plugin
17
{
18
19
    const EXTENSION_REPOSITORY_API = 'http://www.dokuwiki.org/lib/plugins/pluginrepo/api.php';
20
21
    private $loaded_extensions = array();
22
    private $has_access = null;
23
24
    /**
25
     * Initialize the repository (cache), fetches data for all installed plugins
26
     */
27
    public function init()
28
    {
29
        /* @var PluginController $plugin_controller */
30
        global $plugin_controller;
31
        if ($this->hasAccess()) {
32
            $list = $plugin_controller->getList('', true);
33
            $request_data = array('fmt' => 'php');
34
            $request_needed = false;
35
            foreach ($list as $name) {
36
                $cache = new Cache('##extension_manager##'.$name, '.repo');
37
38
                if (!isset($this->loaded_extensions[$name]) &&
39
                    $this->hasAccess() &&
40
                    !$cache->useCache(array('age' => 3600 * 24))
41
                ) {
42
                    $this->loaded_extensions[$name] = true;
43
                    $request_data['ext'][] = $name;
44
                    $request_needed = true;
45
                }
46
            }
47
48
            if ($request_needed) {
49
                $httpclient = new DokuHTTPClient();
50
                $data = $httpclient->post(self::EXTENSION_REPOSITORY_API, $request_data);
51
                if ($data !== false) {
52
                    $extensions = unserialize($data);
53
                    foreach ($extensions as $extension) {
54
                        $cache = new Cache('##extension_manager##'.$extension['plugin'], '.repo');
55
                        $cache->storeCache(serialize($extension));
56
                    }
57
                } else {
58
                    $this->has_access = false;
59
                }
60
            }
61
        }
62
    }
63
64
    /**
65
     * If repository access is available
66
     *
67
     * @param bool $usecache use cached result if still valid
68
     * @return bool If repository access is available
69
     */
70
    public function hasAccess($usecache = true) {
71
        if ($this->has_access === null) {
72
            $cache = new Cache('##extension_manager###hasAccess', '.repo');
73
74
            if (!$cache->useCache(array('age' => 60*10, 'purge' => !$usecache))) {
75
                $httpclient = new DokuHTTPClient();
76
                $httpclient->timeout = 5;
77
                $data = $httpclient->get(self::EXTENSION_REPOSITORY_API.'?cmd=ping');
78
                if ($data !== false) {
79
                    $this->has_access = true;
80
                    $cache->storeCache(1);
81
                } else {
82
                    $this->has_access = false;
83
                    $cache->storeCache(0);
84
                }
85
            } else {
86
                $this->has_access = ($cache->retrieveCache(false) == 1);
87
            }
88
        }
89
        return $this->has_access;
90
    }
91
92
    /**
93
     * Get the remote data of an individual plugin or template
94
     *
95
     * @param string $name  The plugin name to get the data for, template names need to be prefix by 'template:'
96
     * @return array The data or null if nothing was found (possibly no repository access)
97
     */
98
    public function getData($name)
99
    {
100
        $cache = new Cache('##extension_manager##'.$name, '.repo');
101
102
        if (!isset($this->loaded_extensions[$name]) &&
103
            $this->hasAccess() &&
104
            !$cache->useCache(array('age' => 3600 * 24))
105
        ) {
106
            $this->loaded_extensions[$name] = true;
107
            $httpclient = new DokuHTTPClient();
108
            $data = $httpclient->get(self::EXTENSION_REPOSITORY_API.'?fmt=php&ext[]='.urlencode($name));
109
            if ($data !== false) {
110
                $result = unserialize($data);
111
                $cache->storeCache(serialize($result[0]));
112
                return $result[0];
113
            } else {
114
                $this->has_access = false;
115
            }
116
        }
117
        if (file_exists($cache->cache)) {
118
            return unserialize($cache->retrieveCache(false));
119
        }
120
        return array();
121
    }
122
123
    /**
124
     * Search for plugins or templates using the given query string
125
     *
126
     * @param string $q the query string
127
     * @return array a list of matching extensions
128
     */
129
    public function search($q)
130
    {
131
        $query = $this->parseQuery($q);
132
        $query['fmt'] = 'php';
133
134
        $httpclient = new DokuHTTPClient();
135
        $data = $httpclient->post(self::EXTENSION_REPOSITORY_API, $query);
136
        if ($data === false) return array();
137
        $result = unserialize($data);
138
139
        $ids = array();
140
141
        // store cache info for each extension
142
        foreach ($result as $ext) {
143
            $name = $ext['plugin'];
144
            $cache = new Cache('##extension_manager##'.$name, '.repo');
145
            $cache->storeCache(serialize($ext));
146
            $ids[] = $name;
147
        }
148
149
        return $ids;
150
    }
151
152
    /**
153
     * Parses special queries from the query string
154
     *
155
     * @param string $q
156
     * @return array
157
     */
158
    protected function parseQuery($q)
159
    {
160
        $parameters = array(
161
            'tag'  => array(),
162
            'mail' => array(),
163
            'type' => array(),
164
            'ext'  => array()
165
        );
166
167
        // extract tags
168
        if (preg_match_all('/(^|\s)(tag:([\S]+))/', $q, $matches, PREG_SET_ORDER)) {
169
            foreach ($matches as $m) {
170
                $q = str_replace($m[2], '', $q);
171
                $parameters['tag'][] = $m[3];
172
            }
173
        }
174
        // extract author ids
175
        if (preg_match_all('/(^|\s)(authorid:([\S]+))/', $q, $matches, PREG_SET_ORDER)) {
176
            foreach ($matches as $m) {
177
                $q = str_replace($m[2], '', $q);
178
                $parameters['mail'][] = $m[3];
179
            }
180
        }
181
        // extract extensions
182
        if (preg_match_all('/(^|\s)(ext:([\S]+))/', $q, $matches, PREG_SET_ORDER)) {
183
            foreach ($matches as $m) {
184
                $q = str_replace($m[2], '', $q);
185
                $parameters['ext'][] = $m[3];
186
            }
187
        }
188
        // extract types
189
        if (preg_match_all('/(^|\s)(type:([\S]+))/', $q, $matches, PREG_SET_ORDER)) {
190
            foreach ($matches as $m) {
191
                $q = str_replace($m[2], '', $q);
192
                $parameters['type'][] = $m[3];
193
            }
194
        }
195
196
        // FIXME make integer from type value
197
198
        $parameters['q'] = trim($q);
199
        return $parameters;
200
    }
201
}
202
203
// vim:ts=4:sw=4:et:
204