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