xref: /dokuwiki/lib/plugins/config/core/Writer.php (revision 5a5180bed6e19e555b13dbfc262b0488aa57511a)
15a38a129SAndreas Gohr<?php
25a38a129SAndreas Gohr
35a38a129SAndreas Gohrnamespace dokuwiki\plugin\config\core;
40a5b05ebSAndreas Gohruse dokuwiki\plugin\config\core\Setting\Setting;
5*5a5180beSAmmar Abdulhamiduse dokuwiki\Logger;
65a38a129SAndreas Gohr
75a38a129SAndreas Gohr/**
85a38a129SAndreas Gohr * Writes the settings to the correct local file
95a38a129SAndreas Gohr */
105a38a129SAndreas Gohrclass Writer {
115a38a129SAndreas Gohr    /** @var string header info */
125a38a129SAndreas Gohr    protected $header = 'Dokuwiki\'s Main Configuration File - Local Settings';
135a38a129SAndreas Gohr
145a38a129SAndreas Gohr    /** @var string the file where the config will be saved to */
155a38a129SAndreas Gohr    protected $savefile;
165a38a129SAndreas Gohr
175a38a129SAndreas Gohr    /**
185a38a129SAndreas Gohr     * Writer constructor.
195a38a129SAndreas Gohr     */
205a38a129SAndreas Gohr    public function __construct() {
215a38a129SAndreas Gohr        global $config_cascade;
225a38a129SAndreas Gohr        $this->savefile = end($config_cascade['main']['local']);
235a38a129SAndreas Gohr    }
245a38a129SAndreas Gohr
255a38a129SAndreas Gohr    /**
265a38a129SAndreas Gohr     * Save the given settings
275a38a129SAndreas Gohr     *
285a38a129SAndreas Gohr     * @param Setting[] $settings
295a38a129SAndreas Gohr     * @throws \Exception
305a38a129SAndreas Gohr     */
315a38a129SAndreas Gohr    public function save($settings) {
325a38a129SAndreas Gohr        global $conf;
335a38a129SAndreas Gohr        if($this->isLocked()) throw new \Exception('no save');
345a38a129SAndreas Gohr
355a38a129SAndreas Gohr        // backup current file (remove any existing backup)
365a38a129SAndreas Gohr        if(file_exists($this->savefile)) {
3749bcbaeeSAndreas Gohr            if(file_exists($this->savefile . '.bak.php')) @unlink($this->savefile . '.bak.php');
3849bcbaeeSAndreas Gohr            if(!io_rename($this->savefile, $this->savefile . '.bak.php')) throw new \Exception('no backup');
395a38a129SAndreas Gohr        }
405a38a129SAndreas Gohr
415a38a129SAndreas Gohr        if(!$fh = @fopen($this->savefile, 'wb')) {
4249bcbaeeSAndreas Gohr            io_rename($this->savefile . '.bak.php', $this->savefile); // problem opening, restore the backup
435a38a129SAndreas Gohr            throw new \Exception('no save');
445a38a129SAndreas Gohr        }
455a38a129SAndreas Gohr
465a38a129SAndreas Gohr        $out = $this->getHeader();
475a38a129SAndreas Gohr        foreach($settings as $setting) {
48f00299d8SAndreas Gohr            if($setting->shouldBeSaved()) {
495a38a129SAndreas Gohr                $out .= $setting->out('conf', 'php');
505a38a129SAndreas Gohr            }
51f00299d8SAndreas Gohr        }
525a38a129SAndreas Gohr
535a38a129SAndreas Gohr        fwrite($fh, $out);
545a38a129SAndreas Gohr        fclose($fh);
555a38a129SAndreas Gohr        if($conf['fperm']) chmod($this->savefile, $conf['fperm']);
5670b28bcfSAndreas Gohr        $this->opcacheUpdate($this->savefile);
575a38a129SAndreas Gohr    }
585a38a129SAndreas Gohr
595a38a129SAndreas Gohr    /**
605a38a129SAndreas Gohr     * Update last modified time stamp of the config file
615a38a129SAndreas Gohr     *
625a38a129SAndreas Gohr     * Will invalidate all DokuWiki caches
635a38a129SAndreas Gohr     *
645a38a129SAndreas Gohr     * @throws \Exception when the config isn't writable
655a38a129SAndreas Gohr     */
665a38a129SAndreas Gohr    public function touch() {
675a38a129SAndreas Gohr        if($this->isLocked()) throw new \Exception('no save');
685a38a129SAndreas Gohr        @touch($this->savefile);
6970b28bcfSAndreas Gohr        $this->opcacheUpdate($this->savefile);
7070b28bcfSAndreas Gohr    }
7170b28bcfSAndreas Gohr
7270b28bcfSAndreas Gohr    /**
73*5a5180beSAmmar Abdulhamid     * Invalidate the opcache of the given file (if possible)
7470b28bcfSAndreas Gohr     *
7570b28bcfSAndreas Gohr     * @todo this should probably be moved to core
7670b28bcfSAndreas Gohr     * @param string $file
7770b28bcfSAndreas Gohr     */
7870b28bcfSAndreas Gohr    protected function opcacheUpdate($file) {
7970b28bcfSAndreas Gohr        if(!function_exists('opcache_invalidate')) return;
80*5a5180beSAmmar Abdulhamid        set_error_handler(function($errNo, $errMsg) {
81*5a5180beSAmmar Abdulhamid            Logger::debug('Unable to invalidate opcache: ' . $errMsg); }
82*5a5180beSAmmar Abdulhamid        );
83*5a5180beSAmmar Abdulhamid        opcache_invalidate($file);
84*5a5180beSAmmar Abdulhamid        restore_error_handler();
855a38a129SAndreas Gohr    }
865a38a129SAndreas Gohr
875a38a129SAndreas Gohr    /**
885a38a129SAndreas Gohr     * Configuration is considered locked if there is no local settings filename
895a38a129SAndreas Gohr     * or the directory its in is not writable or the file exists and is not writable
905a38a129SAndreas Gohr     *
915a38a129SAndreas Gohr     * @return bool true: locked, false: writable
925a38a129SAndreas Gohr     */
935a38a129SAndreas Gohr    public function isLocked() {
945a38a129SAndreas Gohr        if(!$this->savefile) return true;
955a38a129SAndreas Gohr        if(!is_writable(dirname($this->savefile))) return true;
965a38a129SAndreas Gohr        if(file_exists($this->savefile) && !is_writable($this->savefile)) return true;
975a38a129SAndreas Gohr        return false;
985a38a129SAndreas Gohr    }
995a38a129SAndreas Gohr
1005a38a129SAndreas Gohr    /**
1015a38a129SAndreas Gohr     * Returns the PHP intro header for the config file
1025a38a129SAndreas Gohr     *
1035a38a129SAndreas Gohr     * @return string
1045a38a129SAndreas Gohr     */
1055a38a129SAndreas Gohr    protected function getHeader() {
1065a38a129SAndreas Gohr        return join(
1075a38a129SAndreas Gohr            "\n",
1085a38a129SAndreas Gohr            array(
1095a38a129SAndreas Gohr                '<?php',
1105a38a129SAndreas Gohr                '/*',
1115a38a129SAndreas Gohr                ' * ' . $this->header,
1125a38a129SAndreas Gohr                ' * Auto-generated by config plugin',
1135a38a129SAndreas Gohr                ' * Run for user: ' . $_SERVER['REMOTE_USER'],
1145a38a129SAndreas Gohr                ' * Date: ' . date('r'),
1155a38a129SAndreas Gohr                ' */',
1165a38a129SAndreas Gohr                '',
1175a38a129SAndreas Gohr                ''
1185a38a129SAndreas Gohr            )
1195a38a129SAndreas Gohr        );
1205a38a129SAndreas Gohr    }
1215a38a129SAndreas Gohr}
122