Release 2.0.1, merged in 1181 to HEAD.
[htmlpurifier.git] / library / HTMLPurifier / DefinitionCache / Serializer.php
blob2b07da13de63a2e8812a41331e6c4ddec5b737de
1 <?php
3 require_once 'HTMLPurifier/DefinitionCache.php';
5 HTMLPurifier_ConfigSchema::define(
6 'Cache', 'SerializerPath', null, 'string/null', '
7 <p>
8 Absolute path with no trailing slash to store serialized definitions in.
9 Default is within the
10 HTML Purifier library inside DefinitionCache/Serializer. This
11 path must be writable by the webserver. This directive has been
12 available since 2.0.0.
13 </p>
14 ');
16 class HTMLPurifier_DefinitionCache_Serializer extends
17 HTMLPurifier_DefinitionCache
20 function add($def, $config) {
21 if (!$this->checkDefType($def)) return;
22 $file = $this->generateFilePath($config);
23 if (file_exists($file)) return false;
24 if (!$this->_prepareDir($config)) return false;
25 return $this->_write($file, serialize($def));
28 function set($def, $config) {
29 if (!$this->checkDefType($def)) return;
30 $file = $this->generateFilePath($config);
31 if (!$this->_prepareDir($config)) return false;
32 return $this->_write($file, serialize($def));
35 function replace($def, $config) {
36 if (!$this->checkDefType($def)) return;
37 $file = $this->generateFilePath($config);
38 if (!file_exists($file)) return false;
39 if (!$this->_prepareDir($config)) return false;
40 return $this->_write($file, serialize($def));
43 function get($config) {
44 $file = $this->generateFilePath($config);
45 if (!file_exists($file)) return false;
46 return unserialize(file_get_contents($file));
49 function remove($config) {
50 $file = $this->generateFilePath($config);
51 if (!file_exists($file)) return false;
52 return unlink($file);
55 function flush($config) {
56 if (!$this->_prepareDir($config)) return false;
57 $dir = $this->generateDirectoryPath($config);
58 $dh = opendir($dir);
59 while (false !== ($filename = readdir($dh))) {
60 if (empty($filename)) continue;
61 if ($filename[0] === '.') continue;
62 unlink($dir . '/' . $filename);
66 function cleanup($config) {
67 if (!$this->_prepareDir($config)) return false;
68 $dir = $this->generateDirectoryPath($config);
69 $dh = opendir($dir);
70 while (false !== ($filename = readdir($dh))) {
71 if (empty($filename)) continue;
72 if ($filename[0] === '.') continue;
73 $key = substr($filename, 0, strlen($filename) - 4);
74 if ($this->isOld($key, $config)) unlink($dir . '/' . $filename);
78 /**
79 * Generates the file path to the serial file corresponding to
80 * the configuration and definition name
82 function generateFilePath($config) {
83 $key = $this->generateKey($config);
84 return $this->generateDirectoryPath($config) . '/' . $key . '.ser';
87 /**
88 * Generates the path to the directory contain this cache's serial files
89 * @note No trailing slash
91 function generateDirectoryPath($config) {
92 $base = $this->generateBaseDirectoryPath($config);
93 return $base . '/' . $this->type;
96 /**
97 * Generates path to base directory that contains all definition type
98 * serials
100 function generateBaseDirectoryPath($config) {
101 $base = $config->get('Cache', 'SerializerPath');
102 $base = is_null($base) ? dirname(__FILE__) . '/Serializer' : $base;
103 return $base;
107 * Convenience wrapper function for file_put_contents
108 * @param $file File name to write to
109 * @param $data Data to write into file
110 * @return Number of bytes written if success, or false if failure.
112 function _write($file, $data) {
113 static $file_put_contents;
114 if ($file_put_contents === null) {
115 $file_put_contents = function_exists('file_put_contents');
117 if ($file_put_contents) {
118 return file_put_contents($file, $data);
120 $fh = fopen($file, 'w');
121 if (!$fh) return false;
122 $status = fwrite($fh, $data);
123 fclose($fh);
124 return $status;
128 * Prepares the directory that this type stores the serials in
129 * @return True if successful
131 function _prepareDir($config) {
132 $directory = $this->generateDirectoryPath($config);
133 if (!is_dir($directory)) {
134 $base = $this->generateBaseDirectoryPath($config);
135 if (!is_dir($base)) {
136 trigger_error('Base directory '.$base.' does not exist,
137 please create or change using %Cache.SerializerPath',
138 E_USER_ERROR);
139 return false;
140 } elseif (!$this->_testPermissions($base)) {
141 return false;
143 mkdir($directory);
144 } elseif (!$this->_testPermissions($directory)) {
145 return false;
147 return true;
151 * Tests permissions on a directory and throws out friendly
152 * error messages and attempts to chmod it itself if possible
154 function _testPermissions($dir) {
155 // early abort, if it is writable, everything is hunky-dory
156 if (is_writable($dir)) return true;
157 if (!is_dir($dir)) {
158 // generally, you'll want to handle this beforehand
159 // so a more specific error message can be given
160 trigger_error('Directory '.$dir.' does not exist',
161 E_USER_ERROR);
162 return false;
164 if (function_exists('posix_getuid')) {
165 // POSIX system, we can give more specific advice
166 if (fileowner($dir) === posix_getuid()) {
167 // we can chmod it ourselves
168 chmod($dir, 0755);
169 return true;
170 } elseif (filegroup($dir) === posix_getgid()) {
171 $chmod = '775';
172 } else {
173 // PHP's probably running as nobody, so we'll
174 // need to give global permissions
175 $chmod = '777';
177 trigger_error('Directory '.$dir.' not writable, '.
178 'please chmod to ' . $chmod,
179 E_USER_ERROR);
180 } else {
181 // generic error message
182 trigger_error('Directory '.$dir.' not writable, '.
183 'please alter file permissions',
184 E_USER_ERROR);
186 return false;