File indexing completed on 2024-12-22 05:36:19
0001 <?php 0002 0003 class HTMLPurifier_DefinitionCache_Serializer extends HTMLPurifier_DefinitionCache 0004 { 0005 0006 /** 0007 * @param HTMLPurifier_Definition $def 0008 * @param HTMLPurifier_Config $config 0009 * @return int|bool 0010 */ 0011 public function add($def, $config) 0012 { 0013 if (!$this->checkDefType($def)) { 0014 return; 0015 } 0016 $file = $this->generateFilePath($config); 0017 if (file_exists($file)) { 0018 return false; 0019 } 0020 if (!$this->_prepareDir($config)) { 0021 return false; 0022 } 0023 return $this->_write($file, serialize($def), $config); 0024 } 0025 0026 /** 0027 * @param HTMLPurifier_Definition $def 0028 * @param HTMLPurifier_Config $config 0029 * @return int|bool 0030 */ 0031 public function set($def, $config) 0032 { 0033 if (!$this->checkDefType($def)) { 0034 return; 0035 } 0036 $file = $this->generateFilePath($config); 0037 if (!$this->_prepareDir($config)) { 0038 return false; 0039 } 0040 return $this->_write($file, serialize($def), $config); 0041 } 0042 0043 /** 0044 * @param HTMLPurifier_Definition $def 0045 * @param HTMLPurifier_Config $config 0046 * @return int|bool 0047 */ 0048 public function replace($def, $config) 0049 { 0050 if (!$this->checkDefType($def)) { 0051 return; 0052 } 0053 $file = $this->generateFilePath($config); 0054 if (!file_exists($file)) { 0055 return false; 0056 } 0057 if (!$this->_prepareDir($config)) { 0058 return false; 0059 } 0060 return $this->_write($file, serialize($def), $config); 0061 } 0062 0063 /** 0064 * @param HTMLPurifier_Config $config 0065 * @return bool|HTMLPurifier_Config 0066 */ 0067 public function get($config) 0068 { 0069 $file = $this->generateFilePath($config); 0070 if (!file_exists($file)) { 0071 return false; 0072 } 0073 return unserialize(file_get_contents($file)); 0074 } 0075 0076 /** 0077 * @param HTMLPurifier_Config $config 0078 * @return bool 0079 */ 0080 public function remove($config) 0081 { 0082 $file = $this->generateFilePath($config); 0083 if (!file_exists($file)) { 0084 return false; 0085 } 0086 return unlink($file); 0087 } 0088 0089 /** 0090 * @param HTMLPurifier_Config $config 0091 * @return bool 0092 */ 0093 public function flush($config) 0094 { 0095 if (!$this->_prepareDir($config)) { 0096 return false; 0097 } 0098 $dir = $this->generateDirectoryPath($config); 0099 $dh = opendir($dir); 0100 // Apparently, on some versions of PHP, readdir will return 0101 // an empty string if you pass an invalid argument to readdir. 0102 // So you need this test. See #49. 0103 if (false === $dh) { 0104 return false; 0105 } 0106 while (false !== ($filename = readdir($dh))) { 0107 if (empty($filename)) { 0108 continue; 0109 } 0110 if ($filename[0] === '.') { 0111 continue; 0112 } 0113 unlink($dir . '/' . $filename); 0114 } 0115 closedir($dh); 0116 return true; 0117 } 0118 0119 /** 0120 * @param HTMLPurifier_Config $config 0121 * @return bool 0122 */ 0123 public function cleanup($config) 0124 { 0125 if (!$this->_prepareDir($config)) { 0126 return false; 0127 } 0128 $dir = $this->generateDirectoryPath($config); 0129 $dh = opendir($dir); 0130 // See #49 (and above). 0131 if (false === $dh) { 0132 return false; 0133 } 0134 while (false !== ($filename = readdir($dh))) { 0135 if (empty($filename)) { 0136 continue; 0137 } 0138 if ($filename[0] === '.') { 0139 continue; 0140 } 0141 $key = substr($filename, 0, strlen($filename) - 4); 0142 if ($this->isOld($key, $config)) { 0143 unlink($dir . '/' . $filename); 0144 } 0145 } 0146 closedir($dh); 0147 return true; 0148 } 0149 0150 /** 0151 * Generates the file path to the serial file corresponding to 0152 * the configuration and definition name 0153 * @param HTMLPurifier_Config $config 0154 * @return string 0155 * @todo Make protected 0156 */ 0157 public function generateFilePath($config) 0158 { 0159 $key = $this->generateKey($config); 0160 return $this->generateDirectoryPath($config) . '/' . $key . '.ser'; 0161 } 0162 0163 /** 0164 * Generates the path to the directory contain this cache's serial files 0165 * @param HTMLPurifier_Config $config 0166 * @return string 0167 * @note No trailing slash 0168 * @todo Make protected 0169 */ 0170 public function generateDirectoryPath($config) 0171 { 0172 $base = $this->generateBaseDirectoryPath($config); 0173 return $base . '/' . $this->type; 0174 } 0175 0176 /** 0177 * Generates path to base directory that contains all definition type 0178 * serials 0179 * @param HTMLPurifier_Config $config 0180 * @return mixed|string 0181 * @todo Make protected 0182 */ 0183 public function generateBaseDirectoryPath($config) 0184 { 0185 $base = $config->get('Cache.SerializerPath'); 0186 $base = is_null($base) ? HTMLPURIFIER_PREFIX . '/HTMLPurifier/DefinitionCache/Serializer' : $base; 0187 return $base; 0188 } 0189 0190 /** 0191 * Convenience wrapper function for file_put_contents 0192 * @param string $file File name to write to 0193 * @param string $data Data to write into file 0194 * @param HTMLPurifier_Config $config 0195 * @return int|bool Number of bytes written if success, or false if failure. 0196 */ 0197 private function _write($file, $data, $config) 0198 { 0199 $result = file_put_contents($file, $data); 0200 if ($result !== false) { 0201 // set permissions of the new file (no execute) 0202 $chmod = $config->get('Cache.SerializerPermissions'); 0203 if ($chmod !== null) { 0204 chmod($file, $chmod & 0666); 0205 } 0206 } 0207 return $result; 0208 } 0209 0210 /** 0211 * Prepares the directory that this type stores the serials in 0212 * @param HTMLPurifier_Config $config 0213 * @return bool True if successful 0214 */ 0215 private function _prepareDir($config) 0216 { 0217 $directory = $this->generateDirectoryPath($config); 0218 $chmod = $config->get('Cache.SerializerPermissions'); 0219 if ($chmod === null) { 0220 // TODO: This races 0221 if (is_dir($directory)) return true; 0222 return mkdir($directory); 0223 } 0224 if (!is_dir($directory)) { 0225 $base = $this->generateBaseDirectoryPath($config); 0226 if (!is_dir($base)) { 0227 trigger_error( 0228 'Base directory ' . $base . ' does not exist, 0229 please create or change using %Cache.SerializerPath', 0230 E_USER_WARNING 0231 ); 0232 return false; 0233 } elseif (!$this->_testPermissions($base, $chmod)) { 0234 return false; 0235 } 0236 if (!mkdir($directory, $chmod)) { 0237 trigger_error( 0238 'Could not create directory ' . $directory . '', 0239 E_USER_WARNING 0240 ); 0241 return false; 0242 } 0243 if (!$this->_testPermissions($directory, $chmod)) { 0244 return false; 0245 } 0246 } elseif (!$this->_testPermissions($directory, $chmod)) { 0247 return false; 0248 } 0249 return true; 0250 } 0251 0252 /** 0253 * Tests permissions on a directory and throws out friendly 0254 * error messages and attempts to chmod it itself if possible 0255 * @param string $dir Directory path 0256 * @param int $chmod Permissions 0257 * @return bool True if directory is writable 0258 */ 0259 private function _testPermissions($dir, $chmod) 0260 { 0261 // early abort, if it is writable, everything is hunky-dory 0262 if (is_writable($dir)) { 0263 return true; 0264 } 0265 if (!is_dir($dir)) { 0266 // generally, you'll want to handle this beforehand 0267 // so a more specific error message can be given 0268 trigger_error( 0269 'Directory ' . $dir . ' does not exist', 0270 E_USER_WARNING 0271 ); 0272 return false; 0273 } 0274 if (function_exists('posix_getuid') && $chmod !== null) { 0275 // POSIX system, we can give more specific advice 0276 if (fileowner($dir) === posix_getuid()) { 0277 // we can chmod it ourselves 0278 $chmod = $chmod | 0700; 0279 if (chmod($dir, $chmod)) { 0280 return true; 0281 } 0282 } elseif (filegroup($dir) === posix_getgid()) { 0283 $chmod = $chmod | 0070; 0284 } else { 0285 // PHP's probably running as nobody, so we'll 0286 // need to give global permissions 0287 $chmod = $chmod | 0777; 0288 } 0289 trigger_error( 0290 'Directory ' . $dir . ' not writable, ' . 0291 'please chmod to ' . decoct($chmod), 0292 E_USER_WARNING 0293 ); 0294 } else { 0295 // generic error message 0296 trigger_error( 0297 'Directory ' . $dir . ' not writable, ' . 0298 'please alter file permissions', 0299 E_USER_WARNING 0300 ); 0301 } 0302 return false; 0303 } 0304 } 0305 0306 // vim: et sw=4 sts=4