xref: /plugin/farmer/helper.php (revision 909f2ff613e29f5b8b1c93d90fa17b2c73aef1b8)
1<?php
2/**
3 * DokuWiki Plugin farmer (Helper Component)
4 *
5 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
6 * @author  Michael Große <grosse@cosmocode.de>
7 */
8
9// must be run within Dokuwiki
10if(!defined('DOKU_INC')) die();
11
12class helper_plugin_farmer extends DokuWiki_Plugin {
13
14    private $allPlugins = array();
15
16    /**
17     * Copy a file, or recursively copy a folder and its contents. Adapted for DokuWiki.
18     *
19     * @todo: needs tests
20     *
21     * @author      Aidan Lister <aidan@php.net>
22     * @author      Michael Große <grosse@cosmocode.de>
23     * @version     1.0.1
24     * @link        http://aidanlister.com/2004/04/recursively-copying-directories-in-php/
25     *
26     * @param       string $source       Source path
27     * @param       string $destination  Destination path
28     *
29     * @return      bool     Returns TRUE on success, FALSE on failure
30     */
31    function io_copyDir($source, $destination) {
32        if (is_link($source)) {
33            io_lock($destination);
34            $result=symlink(readlink($source), $destination);
35            io_unlock($destination);
36            return $result;
37        }
38
39        if (is_file($source)) {
40            io_lock($destination);
41            $result=copy($source, $destination);
42            io_unlock($destination);
43            return $result;
44        }
45
46        if (!is_dir($destination)) {
47            io_mkdir_p($destination);
48        }
49
50        $dir = dir($source);
51        while (false !== ($entry = $dir->read())) {
52            if ($entry == '.' || $entry == '..') {
53                continue;
54            }
55
56            // recurse into directories
57            $this->io_copyDir("$source/$entry", "$destination/$entry");
58        }
59
60        $dir->close();
61        return true;
62    }
63
64    /**
65     * get a list of all Plugins installed in the farmer wiki, regardless whether they are active or not.
66     *
67     * @return array
68     */
69    public function getAllPlugins() {
70        $dir = dir(DOKU_PLUGIN);
71        $plugins = array();
72        while (false !== ($entry = $dir->read())) {
73            if($entry == '.' || $entry == '..' || $entry == 'testing' || $entry == 'farmer') {
74                continue;
75            }
76            if (!is_dir(DOKU_PLUGIN ."/$entry")) {
77                continue;
78            }
79            $plugins[] = $entry;
80        }
81        sort($plugins);
82        return $plugins;
83    }
84
85    /**
86     * List of all animals, i.e. directories within DOKU_FARMDIR without the template.
87     *
88     * @return array
89     */
90    public function getAllAnimals() {
91        $animals = array();
92
93        $dir = dir(DOKU_FARMDIR);
94        while (false !== ($entry = $dir->read())) {
95            if ($entry == '.' || $entry == '..' || $entry == '_animal' || $entry == '.htaccess') {
96                continue;
97            }
98            if (!is_dir(DOKU_FARMDIR . $entry)) {
99                continue;
100            }
101            $animals[] = $entry;
102        }
103        $dir->close();
104        return $animals;
105    }
106
107    /**
108     * Actiate a specific plugin in a specific animal
109     *
110     * @param string $plugin Name of the plugin to be activated
111     * @param string $animal Directory of the animal within DOKU_FARMDIR
112     */
113    public function activatePlugin($plugin, $animal) {
114        if (isset($this->allPlugins[$animal])) {
115            $plugins = $this->allPlugins[$animal];
116        } else {
117            include(DOKU_FARMDIR . $animal . '/conf/plugins.local.php');
118        }
119        if (isset($plugins[$plugin]) && $plugins[$plugin] === 0) {
120            unset($plugins[$plugin]);
121            $this->writePluginConf($plugins, $animal);
122        }
123        $this->allPlugins[$animal] = $plugins;
124    }
125
126    /**
127     * @param string $plugin Name of the plugin to be deactivated
128     * @param string $animal Directory of the animal within DOKU_FARMDIR
129     */
130    public function deactivatePlugin($plugin, $animal) {
131        if (isset($this->allPlugins[$animal])) {
132            $plugins = $this->allPlugins[$animal];
133        } else {
134            include(DOKU_FARMDIR . $animal . '/conf/plugins.local.php');
135        }
136        if (!isset($plugins[$plugin]) || $plugins[$plugin] !== 0) {
137            $plugins[$plugin] = 0;
138            $this->writePluginConf($plugins, $animal);
139        }
140        $this->allPlugins[$animal] = $plugins;
141    }
142
143    /**
144     * Write the list of (deactivated) plugins as plugin configuration of an animal to file
145     *
146     * @param array  $plugins associative array with the key being the plugin name and the value 0 or 1
147     * @param string $animal  Directory of the animal within DOKU_FARMDIR
148     */
149    public function writePluginConf($plugins, $animal) {
150        $pluginConf = '<?php' . "\n";
151        foreach ($plugins as $plugin => $status) {
152            $pluginConf .= '$plugins["' . $plugin  . '"] = ' . $status . ";\n";
153        }
154        io_saveFile(DOKU_FARMDIR . $animal . '/conf/plugins.local.php', $pluginConf);
155        touch(DOKU_FARMDIR . $animal . '/conf/local.php');
156    }
157
158    /**
159     * Show a message for all errors which occured during form validation
160     *
161     * @param \dokuwiki\Form\Form $form        The form to which the errors should be added.
162     * @param array               $errorArray  An associative array with the key being the name of the element at fault
163     *                                         and the value being the associated error message.
164     */
165    public function addErrorsToForm(\dokuwiki\Form\Form &$form, $errorArray) {
166        foreach ($errorArray as $elementName => $errorMessage) {
167            $offset = 0;
168            msg($errorMessage, -1);
169            while ($form->findPositionByAttribute('name',$elementName, $offset)) {
170                $offset = $form->findPositionByAttribute('name',$elementName, $offset);
171                $form->getElementAt($offset)->addClass('error');
172                ++$offset;
173            }
174        }
175    }
176
177    /**
178     * @param string|null $page load adminpage $page, reload the current page if $page is ommited or null
179     */
180    public function reloadAdminPage($page = null) {
181        global $ID;
182        $get = $_GET;
183        if(isset($get['id'])) unset($get['id']);
184        if ($page !== null ) {
185            $get['page'] = $page;
186        }
187        $self = wl($ID, $get, false, '&');
188        send_redirect($self);
189    }
190
191    /**
192     * Download and extract the animal template
193     *
194     * @param string $animalpath
195     *
196     * @throws \splitbrain\PHPArchive\ArchiveIOException
197     */
198    public function downloadTemplate($animalpath) {
199        file_put_contents($animalpath . '/_animal.zip',fopen('https://www.dokuwiki.org/_media/dokuwiki_farm_animal.zip','r'));
200        $zip = new splitbrain\PHPArchive\Zip();
201        $zip->open($animalpath.'/_animal.zip');
202        $zip->extract($animalpath);
203        $zip->close();
204        unlink($animalpath.'/_animal.zip');
205    }
206
207    /**
208     * recursive function to test wether a (non-existing) path points into an existint path
209     *
210     * @param $path string
211     *
212     * @param $container string has to exist
213     *
214     * @throws BadMethodCallException
215     *
216     * @return bool
217     */
218    public function isInPath ($path, $container) {
219        if (!file_exists($container)) {
220            throw new BadMethodCallException('The Container has to exist and be accessable by realpath().');
221        }
222        if (realpath($path) === false) {
223            return $this->isInPath(dirname($path), $container);
224        }
225        if (strpos(realpath($path), realpath($container)) !== false) {
226            return true;
227        } else {
228            return false;
229        }
230    }
231
232    /**
233     * Check if the farm is correctly configured for this farmer plugin
234     *
235     * @return bool
236     */
237    public function checkFarmSetup () {
238        if(defined('DOKU_FARMDIR') && defined('DOKU_FARMTYPE')) {
239            if (DOKU_FARMTYPE == 'subdomain') {
240                return true;
241            } elseif (DOKU_FARMTYPE == 'htaccess') {
242                return defined('DOKU_FARMRELDIR');
243            } else {
244                return false;
245            }
246        }
247        return false;
248    }
249
250    /**
251     * The subdomain must contain at least two dots
252     *
253     * @link http://stackoverflow.com/questions/17986371/regular-expression-to-validate-fqdn-in-c-sharp-and-javascript
254     *
255     * @param string $subdomain
256     *
257     * @return bool
258     */
259    public function validateSubdomain ($subdomain) {
260        return preg_match("/^(?=.{1,254}$)((?=[a-z0-9-]{1,63}\.)(xn--+)?[a-z0-9]+(-[a-z0-9]+)*\.){2,}[a-z]{2,63}$/i",$subdomain) === 1;
261    }
262
263    /**
264     * @param string $animalname
265     *
266     * @return bool
267     */
268    public function validateAnimalName ($animalname) {
269        return preg_match("/^[a-z0-9]+(-[a-z0-9]+)*$/i",$animalname) === 1;
270    }
271
272}
273