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