diff --git a/NEWS b/NEWS index 199b8cc8..feadcb10 100644 --- a/NEWS +++ b/NEWS @@ -17,6 +17,7 @@ NEWS ( CHANGELOG and HISTORY ) HTMLPurifier (mostly harmless, except for the fact that it would be a little slower) - Configuration objects with different serials do not clobber each others when revision numbers are unequal +- Improve Serializer DefinitionCache directory permissions checks . Rewire some test-cases to swallow errors rather than expect them . HTMLDefinition printer updated with some of the new attributes . DefinitionCache keys reordered to reflect precedence: version number, diff --git a/library/HTMLPurifier/DefinitionCache/Serializer.php b/library/HTMLPurifier/DefinitionCache/Serializer.php index 8272a5af..a03b584d 100644 --- a/library/HTMLPurifier/DefinitionCache/Serializer.php +++ b/library/HTMLPurifier/DefinitionCache/Serializer.php @@ -21,14 +21,14 @@ class HTMLPurifier_DefinitionCache_Serializer extends if (!$this->checkDefType($def)) return; $file = $this->generateFilePath($config); if (file_exists($file)) return false; - $this->_prepareDir($config); + if (!$this->_prepareDir($config)) return false; return $this->_write($file, serialize($def)); } function set($def, $config) { if (!$this->checkDefType($def)) return; $file = $this->generateFilePath($config); - $this->_prepareDir($config); + if (!$this->_prepareDir($config)) return false; return $this->_write($file, serialize($def)); } @@ -36,7 +36,7 @@ class HTMLPurifier_DefinitionCache_Serializer extends if (!$this->checkDefType($def)) return; $file = $this->generateFilePath($config); if (!file_exists($file)) return false; - $this->_prepareDir($config); + if (!$this->_prepareDir($config)) return false; return $this->_write($file, serialize($def)); } @@ -53,6 +53,7 @@ class HTMLPurifier_DefinitionCache_Serializer extends } function flush($config) { + if (!$this->_prepareDir($config)) return false; $dir = $this->generateDirectoryPath($config); $dh = opendir($dir); while (false !== ($filename = readdir($dh))) { @@ -63,7 +64,7 @@ class HTMLPurifier_DefinitionCache_Serializer extends } function cleanup($config) { - $this->_prepareDir($config); + if (!$this->_prepareDir($config)) return false; $dir = $this->generateDirectoryPath($config); $dh = opendir($dir); while (false !== ($filename = readdir($dh))) { @@ -125,12 +126,64 @@ class HTMLPurifier_DefinitionCache_Serializer extends /** * Prepares the directory that this type stores the serials in + * @return True if successful */ function _prepareDir($config) { $directory = $this->generateDirectoryPath($config); if (!is_dir($directory)) { + $base = $this->generateBaseDirectoryPath($config); + if (!is_dir($base)) { + trigger_error('Base directory '.$base.' does not exist, + please create or change using %Cache.SerializerPath', + E_USER_ERROR); + return false; + } elseif (!$this->_testPermissions($base)) { + return false; + } mkdir($directory); + } elseif (!$this->_testPermissions($directory)) { + return false; } + return true; + } + + /** + * Tests permissions on a directory and throws out friendly + * error messages and attempts to chmod it itself if possible + */ + function _testPermissions($dir) { + // early abort, if it is writable, everything is hunky-dory + if (is_writable($dir)) return true; + if (!is_dir($dir)) { + // generally, you'll want to handle this beforehand + // so a more specific error message can be given + trigger_error('Directory '.$dir.' does not exist', + E_USER_ERROR); + return false; + } + if (function_exists('posix_getuid')) { + // POSIX system, we can give more specific advice + if (fileowner($dir) === posix_getuid()) { + // we can chmod it ourselves + chmod($dir, 0755); + return true; + } elseif (filegroup($dir) === posix_getgid()) { + $chmod = '775'; + } else { + // PHP's probably running as nobody, so we'll + // need to give global permissions + $chmod = '777'; + } + trigger_error('Directory '.$dir.' not writable, '. + 'please chmod to ' . $chmod, + E_USER_ERROR); + } else { + // generic error message + trigger_error('Directory '.$dir.' not writable, '. + 'please alter file permissions', + E_USER_ERROR); + } + return false; } }