1<?php 2 3use dokuwiki\Extension\Plugin; 4 5/** 6 * DokuWiki Plugin farmer (Helper Component) 7 * 8 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 9 * @author Michael Große <grosse@cosmocode.de> 10 * @author Andreas Gohr <gohr@cosmocode.de> 11 */ 12class helper_plugin_farmer extends Plugin 13{ 14 protected $defaultPluginState; 15 protected $animalPluginState = []; 16 17 /** 18 * Returns the name of the current animal if any, false otherwise 19 * 20 * @return string|false 21 */ 22 public function getAnimal() 23 { 24 if (!isset($GLOBALS['FARMCORE'])) return false; 25 return $GLOBALS['FARMCORE']->getAnimal(); 26 } 27 28 /** 29 * Get the farm config 30 * 31 * @return array 32 */ 33 public function getConfig() 34 { 35 if (!isset($GLOBALS['FARMCORE'])) return []; 36 return $GLOBALS['FARMCORE']->getConfig(); 37 } 38 39 /** 40 * Was the current animal requested by host? 41 * 42 * @return bool 43 */ 44 public function isHostbased() 45 { 46 if (!isset($GLOBALS['FARMCORE'])) return false; 47 return $GLOBALS['FARMCORE']->isHostbased(); 48 } 49 50 /** 51 * Was an animal requested that could not be found? 52 * 53 * @return bool 54 */ 55 public function wasNotfound() 56 { 57 if (!isset($GLOBALS['FARMCORE'])) return false; 58 return $GLOBALS['FARMCORE']->wasNotfound(); 59 } 60 61 /** 62 * Guess the URL for an animal 63 * 64 * @param $animal 65 * @return string 66 */ 67 public function getAnimalURL($animal) 68 { 69 $config = $this->getConfig(); 70 71 if (strpos($animal, '.') !== false) { 72 return 'http://' . $animal; 73 } elseif ($config['base']['basedomain']) { 74 return 'http://' . $animal . '.' . $config['base']['basedomain']; 75 } else { 76 return DOKU_URL . '!' . $animal . '/'; 77 } 78 } 79 80 /** 81 * List of all animals, i.e. directories within DOKU_FARMDIR without the template. 82 * 83 * @return array 84 */ 85 public function getAllAnimals() 86 { 87 $animals = []; 88 $list = glob(DOKU_FARMDIR . '*/conf/', GLOB_ONLYDIR); 89 foreach ($list as $path) { 90 $animal = basename(dirname($path)); 91 if ($animal == '_animal') continue; // old template 92 $animals[] = $animal; 93 } 94 sort($animals); 95 return $animals; 96 } 97 98 /** 99 * checks wether $path is in under $container 100 * 101 * Also returns false if $path and $container are the same directory 102 * 103 * @param string $path 104 * @param string $container 105 * @return bool 106 */ 107 public function isInPath($path, $container) 108 { 109 $path = fullpath($path) . '/'; 110 $container = fullpath($container) . '/'; 111 if ($path === $container) return false; 112 return (strpos($path, $container) === 0); 113 } 114 115 /** 116 * Check if the farm is correctly configured for this farmer plugin 117 * 118 * @return bool 119 */ 120 public function checkFarmSetup() 121 { 122 return defined('DOKU_FARMDIR') && isset($GLOBALS['FARMCORE']); 123 } 124 125 /** 126 * @param string $animalname 127 * 128 * @return bool 129 */ 130 public function validateAnimalName($animalname) 131 { 132 return preg_match("/^[a-z0-9]+([\\.\\-][a-z0-9]+)*$/i", $animalname) === 1; 133 } 134 135 /** 136 * Copy a file, or recursively copy a folder and its contents. Adapted for DokuWiki. 137 * 138 * @todo: needs tests 139 * 140 * @author Aidan Lister <aidan@php.net> 141 * @author Michael Große <grosse@cosmocode.de> 142 * @author Andreas Gohr <gohr@cosmocode.de> 143 * @link http://aidanlister.com/2004/04/recursively-copying-directories-in-php/ 144 * 145 * @param string $source Source path 146 * @param string $destination Destination path 147 * @param string $exclude Regular expression to exclude files or directories (complete with delimiters) 148 * @return bool Returns TRUE on success, FALSE on failure 149 */ 150 public function copyDir($source, $destination, $exclude = '') 151 { 152 if ($exclude && preg_match($exclude, $source)) { 153 return true; 154 } 155 156 if (is_link($source)) { 157 io_lock($destination); 158 $result = symlink(readlink($source), $destination); 159 io_unlock($destination); 160 return $result; 161 } 162 163 if (is_file($source)) { 164 io_lock($destination); 165 $result = copy($source, $destination); 166 io_unlock($destination); 167 return $result; 168 } 169 170 if (!is_dir($destination)) { 171 io_mkdir_p($destination); 172 } 173 174 $dir = @dir($source); 175 if ($dir === false) return false; 176 while (false !== ($entry = $dir->read())) { 177 if ($entry == '.' || $entry == '..') { 178 continue; 179 } 180 181 // recurse into directories 182 $this->copyDir("$source/$entry", "$destination/$entry", $exclude); 183 } 184 185 $dir->close(); 186 return true; 187 } 188 189 /** 190 * get a list of all Plugins installed in the farmer wiki, regardless whether they are active or not. 191 * 192 * @param bool $all get all plugins, even disabled ones 193 * @return array 194 */ 195 public function getAllPlugins($all = true) 196 { 197 198 /** @var Doku_Plugin_Controller $plugin_controller */ 199 global $plugin_controller; 200 201 $plugins = $plugin_controller->getList('', $all); 202 203 // filter out a few plugins 204 $plugins = array_filter( 205 $plugins, 206 function ($item) { 207 if ($item == 'farmer') return false; 208 if ($item == 'extension') return false; 209 if ($item == 'upgrade') return false; 210 if ($item == 'testing') return false; 211 return true; 212 } 213 ); 214 215 sort($plugins); 216 return $plugins; 217 } 218 219 /** 220 * Get the plugin states configured locally in the given animal 221 * 222 * Response is cached 223 * 224 * @param $animal 225 * @return array 226 */ 227 public function getAnimalPluginLocalStates($animal) 228 { 229 if (isset($this->animalPluginState[$animal])) return $this->animalPluginState[$animal]; 230 231 $localfile = DOKU_FARMDIR . $animal . '/conf/plugins.local.php'; 232 $plugins = []; 233 if (file_exists($localfile)) { 234 include($localfile); 235 } 236 237 $this->animalPluginState[$animal] = $plugins; 238 return $plugins; 239 } 240 241 /** 242 * Return the default state plugins would have in animals 243 * 244 * Response is cached 245 * 246 * @return array 247 */ 248 public function getDefaultPluginStates() 249 { 250 if (!is_null($this->defaultPluginState)) return $this->defaultPluginState; 251 252 $farmconf = $this->getConfig(); 253 $all = $this->getAllPlugins(); 254 255 $plugins = []; 256 foreach ($all as $one) { 257 if ($farmconf['inherit']['plugins']) { 258 $plugins[$one] = !plugin_isdisabled($one); 259 } else { 260 $plugins[$one] = true; // default state is enabled 261 } 262 } 263 264 ksort($plugins); 265 $this->defaultPluginState = $plugins; 266 return $plugins; 267 } 268 269 /** 270 * Return a structure giving detailed info about the state of all plugins in an animal 271 * 272 * @param $animal 273 * @return array 274 */ 275 public function getAnimalPluginRealState($animal) 276 { 277 $info = []; 278 279 $defaults = $this->getDefaultPluginStates(); 280 $local = $this->getAnimalPluginLocalStates($animal); 281 282 foreach ($defaults as $plugin => $set) { 283 $current = ['name' => $plugin, 'default' => $set, 'actual' => $set, 'isdefault' => true]; 284 285 if (isset($local[$plugin])) { 286 $current['actual'] = (bool) $local[$plugin]; 287 $current['isdefault'] = false; 288 } 289 290 $info[$plugin] = $current; 291 } 292 293 ksort($info); 294 return $info; 295 } 296 297 /** 298 * Set the state of a plugin in an animal 299 * 300 * @param string $plugin 301 * @param string $animal 302 * @param int $state -1 = default, 1 = enabled, 0 = disabled 303 */ 304 public function setPluginState($plugin, $animal, $state) 305 { 306 $state = (int) $state; 307 308 $plugins = $this->getAnimalPluginLocalStates($animal); 309 if ($state < 0) { 310 if (isset($plugins[$plugin])) unset($plugins[$plugin]); 311 } else { 312 $plugins[$plugin] = $state; 313 } 314 315 $this->writePluginConf($plugins, $animal); 316 317 // clear state cache 318 if (isset($this->animalPluginState[$animal])) unset($this->animalPluginState[$animal]); 319 } 320 321 /** 322 * Write the list of (deactivated) plugins as plugin configuration of an animal to file 323 * 324 * updates the plugin state cache 325 * 326 * @param array $plugins associative array with the key being the plugin name and the value 0 or 1 327 * @param string $animal Directory of the animal within DOKU_FARMDIR 328 */ 329 public function writePluginConf($plugins, $animal) 330 { 331 $pluginConf = '<?php' . "\n# plugins enabled and disabled by the farmer plugin\n"; 332 foreach ($plugins as $plugin => $status) { 333 $pluginConf .= '$plugins[\'' . $plugin . '\'] = ' . $status . ";\n"; 334 } 335 io_saveFile(DOKU_FARMDIR . $animal . '/conf/plugins.local.php', $pluginConf); 336 touch(DOKU_FARMDIR . $animal . '/conf/local.php'); 337 338 if (function_exists('opcache_invalidate')) { 339 opcache_invalidate(DOKU_FARMDIR . $animal . '/conf/plugins.local.php'); 340 opcache_invalidate(DOKU_FARMDIR . $animal . '/conf/local.php'); 341 } 342 343 $this->animalPluginState[$animal] = $plugins; 344 } 345} 346