952e48d4704c24ff950b05d137451b3500a838ac
[yaffs-website] / vendor / ezyang / htmlpurifier / library / HTMLPurifier / DefinitionCache / Serializer.php
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;
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;
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         closedir($dh);
116         return true;
117     }
118
119     /**
120      * @param HTMLPurifier_Config $config
121      * @return bool
122      */
123     public function cleanup($config)
124     {
125         if (!$this->_prepareDir($config)) {
126             return false;
127         }
128         $dir = $this->generateDirectoryPath($config);
129         $dh = opendir($dir);
130         // See #49 (and above).
131         if (false === $dh) {
132             return false;
133         }
134         while (false !== ($filename = readdir($dh))) {
135             if (empty($filename)) {
136                 continue;
137             }
138             if ($filename[0] === '.') {
139                 continue;
140             }
141             $key = substr($filename, 0, strlen($filename) - 4);
142             if ($this->isOld($key, $config)) {
143                 unlink($dir . '/' . $filename);
144             }
145         }
146         closedir($dh);
147         return true;
148     }
149
150     /**
151      * Generates the file path to the serial file corresponding to
152      * the configuration and definition name
153      * @param HTMLPurifier_Config $config
154      * @return string
155      * @todo Make protected
156      */
157     public function generateFilePath($config)
158     {
159         $key = $this->generateKey($config);
160         return $this->generateDirectoryPath($config) . '/' . $key . '.ser';
161     }
162
163     /**
164      * Generates the path to the directory contain this cache's serial files
165      * @param HTMLPurifier_Config $config
166      * @return string
167      * @note No trailing slash
168      * @todo Make protected
169      */
170     public function generateDirectoryPath($config)
171     {
172         $base = $this->generateBaseDirectoryPath($config);
173         return $base . '/' . $this->type;
174     }
175
176     /**
177      * Generates path to base directory that contains all definition type
178      * serials
179      * @param HTMLPurifier_Config $config
180      * @return mixed|string
181      * @todo Make protected
182      */
183     public function generateBaseDirectoryPath($config)
184     {
185         $base = $config->get('Cache.SerializerPath');
186         $base = is_null($base) ? HTMLPURIFIER_PREFIX . '/HTMLPurifier/DefinitionCache/Serializer' : $base;
187         return $base;
188     }
189
190     /**
191      * Convenience wrapper function for file_put_contents
192      * @param string $file File name to write to
193      * @param string $data Data to write into file
194      * @param HTMLPurifier_Config $config
195      * @return int|bool Number of bytes written if success, or false if failure.
196      */
197     private function _write($file, $data, $config)
198     {
199         $result = file_put_contents($file, $data);
200         if ($result !== false) {
201             // set permissions of the new file (no execute)
202             $chmod = $config->get('Cache.SerializerPermissions');
203             if ($chmod !== null) {
204                 chmod($file, $chmod & 0666);
205             }
206         }
207         return $result;
208     }
209
210     /**
211      * Prepares the directory that this type stores the serials in
212      * @param HTMLPurifier_Config $config
213      * @return bool True if successful
214      */
215     private function _prepareDir($config)
216     {
217         $directory = $this->generateDirectoryPath($config);
218         $chmod = $config->get('Cache.SerializerPermissions');
219         if ($chmod === null) {
220             // TODO: This races
221             if (is_dir($directory)) return true;
222             return mkdir($directory);
223         }
224         if (!is_dir($directory)) {
225             $base = $this->generateBaseDirectoryPath($config);
226             if (!is_dir($base)) {
227                 trigger_error(
228                     'Base directory ' . $base . ' does not exist,
229                     please create or change using %Cache.SerializerPath',
230                     E_USER_WARNING
231                 );
232                 return false;
233             } elseif (!$this->_testPermissions($base, $chmod)) {
234                 return false;
235             }
236             if (!mkdir($directory, $chmod)) {
237                 trigger_error(
238                     'Could not create directory ' . $directory . '',
239                     E_USER_WARNING
240                 );
241                 return false;
242             }
243             if (!$this->_testPermissions($directory, $chmod)) {
244                 return false;
245             }
246         } elseif (!$this->_testPermissions($directory, $chmod)) {
247             return false;
248         }
249         return true;
250     }
251
252     /**
253      * Tests permissions on a directory and throws out friendly
254      * error messages and attempts to chmod it itself if possible
255      * @param string $dir Directory path
256      * @param int $chmod Permissions
257      * @return bool True if directory is writable
258      */
259     private function _testPermissions($dir, $chmod)
260     {
261         // early abort, if it is writable, everything is hunky-dory
262         if (is_writable($dir)) {
263             return true;
264         }
265         if (!is_dir($dir)) {
266             // generally, you'll want to handle this beforehand
267             // so a more specific error message can be given
268             trigger_error(
269                 'Directory ' . $dir . ' does not exist',
270                 E_USER_WARNING
271             );
272             return false;
273         }
274         if (function_exists('posix_getuid') && $chmod !== null) {
275             // POSIX system, we can give more specific advice
276             if (fileowner($dir) === posix_getuid()) {
277                 // we can chmod it ourselves
278                 $chmod = $chmod | 0700;
279                 if (chmod($dir, $chmod)) {
280                     return true;
281                 }
282             } elseif (filegroup($dir) === posix_getgid()) {
283                 $chmod = $chmod | 0070;
284             } else {
285                 // PHP's probably running as nobody, so we'll
286                 // need to give global permissions
287                 $chmod = $chmod | 0777;
288             }
289             trigger_error(
290                 'Directory ' . $dir . ' not writable, ' .
291                 'please chmod to ' . decoct($chmod),
292                 E_USER_WARNING
293             );
294         } else {
295             // generic error message
296             trigger_error(
297                 'Directory ' . $dir . ' not writable, ' .
298                 'please alter file permissions',
299                 E_USER_WARNING
300             );
301         }
302         return false;
303     }
304 }
305
306 // vim: et sw=4 sts=4