savefile = end($config_cascade['main']['local']); } /** * Save the given settings * * @param Setting[] $settings * @throws \Exception */ public function save($settings) { global $conf; if($this->isLocked()) throw new \Exception('no save'); // backup current file (remove any existing backup) if(file_exists($this->savefile)) { if(file_exists($this->savefile . '.bak.php')) @unlink($this->savefile . '.bak.php'); if(!io_rename($this->savefile, $this->savefile . '.bak.php')) throw new \Exception('no backup'); } if(!$fh = @fopen($this->savefile, 'wb')) { io_rename($this->savefile . '.bak.php', $this->savefile); // problem opening, restore the backup throw new \Exception('no save'); } $out = ''; foreach($settings as $setting) { if($setting->shouldBeSaved()) { $out .= $setting->out('conf', 'php'); } } if($out === '') { throw new \Exception('empty config'); } $out = $this->getHeader() . $out; fwrite($fh, $out); fclose($fh); if($conf['fperm']) chmod($this->savefile, $conf['fperm']); $this->opcacheUpdate($this->savefile); } /** * Update last modified time stamp of the config file * * Will invalidate all DokuWiki caches * * @throws \Exception when the config isn't writable */ public function touch() { if($this->isLocked()) throw new \Exception('no save'); @touch($this->savefile); $this->opcacheUpdate($this->savefile); } /** * Invalidate the opcache of the given file (if possible) * * @todo this should probably be moved to core * @param string $file */ protected function opcacheUpdate($file) { if(!function_exists('opcache_invalidate')) return; set_error_handler(function ($errNo, $errMsg) { Logger::debug('Unable to invalidate opcache: ' . $errMsg); } ); opcache_invalidate($file); restore_error_handler(); } /** * Configuration is considered locked if there is no local settings filename * or the directory its in is not writable or the file exists and is not writable * * @return bool true: locked, false: writable */ public function isLocked() { if(!$this->savefile) return true; if(!is_writable(dirname($this->savefile))) return true; if(file_exists($this->savefile) && !is_writable($this->savefile)) return true; return false; } /** * Returns the PHP intro header for the config file * * @return string */ protected function getHeader() { return join( "\n", array( 'header, ' * Auto-generated by config plugin', ' * Run for user: ' . (isset($_SERVER['REMOTE_USER']) ? $_SERVER['REMOTE_USER'] : 'Unknown'), ' * Date: ' . date('r'), ' */', '', '' ) ); } }