Completed
Push — master ( 14e79d...7a4940 )
by Richard
08:21
created

HTMLPurifier_DefinitionCache_Serializer::cleanup()   C

Complexity

Conditions 7
Paths 7

Size

Total Lines 25
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 16
nc 7
nop 1
dl 0
loc 25
rs 6.7272
c 0
b 0
f 0
1
<?php
2
3
class HTMLPurifier_DefinitionCache_Serializer extends HTMLPurifier_DefinitionCache
4
{
5
6
    /**
7
     * @param HTMLPurifier_Definition $def
8
     * @param HTMLPurifier_Config $config
9
     * @return int|bool
10
     */
11
    public function add($def, $config)
12
    {
13
        if (!$this->checkDefType($def)) {
14
            return null;
15
        }
16
        $file = $this->generateFilePath($config);
17
        if (file_exists($file)) {
18
            return false;
19
        }
20
        if (!$this->_prepareDir($config)) {
21
            return false;
22
        }
23
        return $this->_write($file, serialize($def), $config);
24
    }
25
26
    /**
27
     * @param HTMLPurifier_Definition $def
28
     * @param HTMLPurifier_Config $config
29
     * @return int|bool
30
     */
31
    public function set($def, $config)
32
    {
33
        if (!$this->checkDefType($def)) {
34
            return null;
35
        }
36
        $file = $this->generateFilePath($config);
37
        if (!$this->_prepareDir($config)) {
38
            return false;
39
        }
40
        return $this->_write($file, serialize($def), $config);
41
    }
42
43
    /**
44
     * @param HTMLPurifier_Definition $def
45
     * @param HTMLPurifier_Config $config
46
     * @return int|bool
47
     */
48
    public function replace($def, $config)
49
    {
50
        if (!$this->checkDefType($def)) {
51
            return;
52
        }
53
        $file = $this->generateFilePath($config);
54
        if (!file_exists($file)) {
55
            return false;
56
        }
57
        if (!$this->_prepareDir($config)) {
58
            return false;
59
        }
60
        return $this->_write($file, serialize($def), $config);
61
    }
62
63
    /**
64
     * @param HTMLPurifier_Config $config
65
     * @return bool|HTMLPurifier_Config
66
     */
67
    public function get($config)
68
    {
69
        $file = $this->generateFilePath($config);
70
        if (!file_exists($file)) {
71
            return false;
72
        }
73
        return unserialize(file_get_contents($file));
74
    }
75
76
    /**
77
     * @param HTMLPurifier_Config $config
78
     * @return bool
79
     */
80
    public function remove($config)
81
    {
82
        $file = $this->generateFilePath($config);
83
        if (!file_exists($file)) {
84
            return false;
85
        }
86
        return unlink($file);
87
    }
88
89
    /**
90
     * @param HTMLPurifier_Config $config
91
     * @return bool
92
     */
93
    public function flush($config)
94
    {
95
        if (!$this->_prepareDir($config)) {
96
            return false;
97
        }
98
        $dir = $this->generateDirectoryPath($config);
99
        $dh = opendir($dir);
100
        // Apparently, on some versions of PHP, readdir will return
101
        // an empty string if you pass an invalid argument to readdir.
102
        // So you need this test.  See #49.
103
        if (false === $dh) {
104
            return false;
105
        }
106
        while (false !== ($filename = readdir($dh))) {
107
            if (empty($filename)) {
108
                continue;
109
            }
110
            if ($filename[0] === '.') {
111
                continue;
112
            }
113
            unlink($dir . '/' . $filename);
114
        }
115
        return true;
116
    }
117
118
    /**
119
     * @param HTMLPurifier_Config $config
120
     * @return bool
121
     */
122
    public function cleanup($config)
123
    {
124
        if (!$this->_prepareDir($config)) {
125
            return false;
126
        }
127
        $dir = $this->generateDirectoryPath($config);
128
        $dh = opendir($dir);
129
        // See #49 (and above).
130
        if (false === $dh) {
131
            return false;
132
        }
133
        while (false !== ($filename = readdir($dh))) {
134
            if (empty($filename)) {
135
                continue;
136
            }
137
            if ($filename[0] === '.') {
138
                continue;
139
            }
140
            $key = substr($filename, 0, strlen($filename) - 4);
141
            if ($this->isOld($key, $config)) {
142
                unlink($dir . '/' . $filename);
143
            }
144
        }
145
        return true;
146
    }
147
148
    /**
149
     * Generates the file path to the serial file corresponding to
150
     * the configuration and definition name
151
     * @param HTMLPurifier_Config $config
152
     * @return string
153
     * @todo Make protected
154
     */
155
    public function generateFilePath($config)
156
    {
157
        $key = $this->generateKey($config);
158
        return $this->generateDirectoryPath($config) . '/' . $key . '.ser';
159
    }
160
161
    /**
162
     * Generates the path to the directory contain this cache's serial files
163
     * @param HTMLPurifier_Config $config
164
     * @return string
165
     * @note No trailing slash
166
     * @todo Make protected
167
     */
168
    public function generateDirectoryPath($config)
169
    {
170
        $base = $this->generateBaseDirectoryPath($config);
171
        return $base . '/' . $this->type;
172
    }
173
174
    /**
175
     * Generates path to base directory that contains all definition type
176
     * serials
177
     * @param HTMLPurifier_Config $config
178
     * @return mixed|string
179
     * @todo Make protected
180
     */
181
    public function generateBaseDirectoryPath($config)
182
    {
183
        $base = $config->get('Cache.SerializerPath');
184
        $base = is_null($base) ? HTMLPURIFIER_PREFIX . '/HTMLPurifier/DefinitionCache/Serializer' : $base;
185
        return $base;
186
    }
187
188
    /**
189
     * Convenience wrapper function for file_put_contents
190
     * @param string $file File name to write to
191
     * @param string $data Data to write into file
192
     * @param HTMLPurifier_Config $config
193
     * @return int|bool Number of bytes written if success, or false if failure.
194
     */
195
    private function _write($file, $data, $config)
196
    {
197
        $result = file_put_contents($file, $data);
198
        if ($result !== false) {
199
            // set permissions of the new file (no execute)
200
            $chmod = $config->get('Cache.SerializerPermissions');
201
            if ($chmod === null) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
202
                // don't do anything
203
            } else {
204
            $chmod = $chmod & 0666;
205
            chmod($file, $chmod);
206
        }
207
        }
208
        return $result;
209
    }
210
211
    /**
212
     * Prepares the directory that this type stores the serials in
213
     * @param HTMLPurifier_Config $config
214
     * @return bool True if successful
215
     */
216
    private function _prepareDir($config)
217
    {
218
        $directory = $this->generateDirectoryPath($config);
219
        $chmod = $config->get('Cache.SerializerPermissions');
220
        if (!is_dir($directory)) {
221
            $base = $this->generateBaseDirectoryPath($config);
222
            if (!is_dir($base)) {
223
                trigger_error(
224
                    'Base directory ' . $base . ' does not exist,
225
                    please create or change using %Cache.SerializerPath',
226
                    E_USER_WARNING
227
                );
228
                return false;
229
            } elseif (!$this->_testPermissions($base, $chmod)) {
230
                return false;
231
            }
232
            if ($chmod === null) {
233
                trigger_error(
234
                    'Base directory ' . $base . ' does not exist,
235
                    please create or change using %Cache.SerializerPath',
236
                    E_USER_WARNING
237
                );
238
                return false;
239
            }
240
            if ($chmod !== null) {
241
            mkdir($directory, $chmod);
242
            } else {
243
                mkdir($directory);
244
            }
245
            if (!$this->_testPermissions($directory, $chmod)) {
246
                trigger_error(
247
                    'Base directory ' . $base . ' does not exist,
248
                    please create or change using %Cache.SerializerPath',
249
                    E_USER_WARNING
250
                );
251
                return false;
252
            }
253
        } elseif (!$this->_testPermissions($directory, $chmod)) {
254
            return false;
255
        }
256
        return true;
257
    }
258
259
    /**
260
     * Tests permissions on a directory and throws out friendly
261
     * error messages and attempts to chmod it itself if possible
262
     * @param string $dir Directory path
263
     * @param int $chmod Permissions
264
     * @return bool True if directory is writable
265
     */
266
    private function _testPermissions($dir, $chmod)
267
    {
268
        // early abort, if it is writable, everything is hunky-dory
269
        if (is_writable($dir)) {
270
            return true;
271
        }
272
        if (!is_dir($dir)) {
273
            // generally, you'll want to handle this beforehand
274
            // so a more specific error message can be given
275
            trigger_error(
276
                'Directory ' . $dir . ' does not exist',
277
                E_USER_WARNING
278
            );
279
            return false;
280
        }
281
        if (function_exists('posix_getuid') && $chmod !== null) {
282
            // POSIX system, we can give more specific advice
283
            if (fileowner($dir) === posix_getuid()) {
284
                // we can chmod it ourselves
285
                $chmod = $chmod | 0700;
286
                if (chmod($dir, $chmod)) {
287
                    return true;
288
                }
289
            } elseif (filegroup($dir) === posix_getgid()) {
290
                $chmod = $chmod | 0070;
291
            } else {
292
                // PHP's probably running as nobody, so we'll
293
                // need to give global permissions
294
                $chmod = $chmod | 0777;
295
            }
296
            trigger_error(
297
                'Directory ' . $dir . ' not writable, ' .
298
                'please chmod to ' . decoct($chmod),
299
                E_USER_WARNING
300
            );
301
        } else {
302
            // generic error message
303
            trigger_error(
304
                'Directory ' . $dir . ' not writable, ' .
305
                'please alter file permissions',
306
                E_USER_WARNING
307
            );
308
        }
309
        return false;
310
    }
311
}
312
313
// vim: et sw=4 sts=4
314