summaryrefslogtreecommitdiff
path: root/platform/www/lib/plugins/config/core/Writer.php
blob: 56de621d9218e03f70e990648b25cf517c2189f4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
<?php

namespace dokuwiki\plugin\config\core;
use dokuwiki\plugin\config\core\Setting\Setting;

/**
 * Writes the settings to the correct local file
 */
class Writer {
    /** @var string header info */
    protected $header = 'Dokuwiki\'s Main Configuration File - Local Settings';

    /** @var string the file where the config will be saved to */
    protected $savefile;

    /**
     * Writer constructor.
     */
    public function __construct() {
        global $config_cascade;
        $this->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 = $this->getHeader();
        foreach($settings as $setting) {
            if($setting->shouldBeSaved()) {
                $out .= $setting->out('conf', 'php');
            }
        }

        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
     *
     * @todo this should probably be moved to core
     * @param string $file
     */
    protected function opcacheUpdate($file) {
        if(!function_exists('opcache_invalidate')) return;
        opcache_invalidate($file);
    }

    /**
     * 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(
                '<?php',
                '/*',
                ' * ' . $this->header,
                ' * Auto-generated by config plugin',
                ' * Run for user: ' . $_SERVER['REMOTE_USER'],
                ' * Date: ' . date('r'),
                ' */',
                '',
                ''
            )
        );
    }
}