diff --git a/NEWS b/NEWS index ffc4961c..3ded73e5 100644 --- a/NEWS +++ b/NEWS @@ -18,6 +18,8 @@ NEWS ( CHANGELOG and HISTORY ) HTMLPurifier ! More types of SPL autoloaders allowed on later versions of PHP. ! Implementations for position, top, left, right, bottom, z-index when %CSS.Trusted is on. +! Add %Cache.SerializerPermissions option for custom serializer + directory/file permissions - Make removal of conditional IE comments ungreedy; thanks Bernd for reporting. - Escape CDATA before removing Internet Explorer comments. diff --git a/configdoc/usage.xml b/configdoc/usage.xml index 42e60aa6..e962ca96 100644 --- a/configdoc/usage.xml +++ b/configdoc/usage.xml @@ -380,6 +380,12 @@ 91 + + + 107 + 124 + + 41 diff --git a/library/HTMLPurifier/ConfigSchema/schema.ser b/library/HTMLPurifier/ConfigSchema/schema.ser index 7946aad4..1a70feba 100644 Binary files a/library/HTMLPurifier/ConfigSchema/schema.ser and b/library/HTMLPurifier/ConfigSchema/schema.ser differ diff --git a/library/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPermissions.txt b/library/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPermissions.txt new file mode 100644 index 00000000..cd0ba3ad --- /dev/null +++ b/library/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPermissions.txt @@ -0,0 +1,11 @@ +Cache.SerializerPermissions +TYPE: int +VERSION: 4.2.1 +DEFAULT: 0755 +--DESCRIPTION-- + +

+ Directory permissions of the files and directories created inside + the DefinitionCache/Serializer or other custom serializer path. +

+--# vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/DefinitionCache/Serializer.php b/library/HTMLPurifier/DefinitionCache/Serializer.php index 7a6aa93f..73d5e90a 100644 --- a/library/HTMLPurifier/DefinitionCache/Serializer.php +++ b/library/HTMLPurifier/DefinitionCache/Serializer.php @@ -9,14 +9,14 @@ class HTMLPurifier_DefinitionCache_Serializer extends $file = $this->generateFilePath($config); if (file_exists($file)) return false; if (!$this->_prepareDir($config)) return false; - return $this->_write($file, serialize($def)); + return $this->_write($file, serialize($def), $config); } public function set($def, $config) { if (!$this->checkDefType($def)) return; $file = $this->generateFilePath($config); if (!$this->_prepareDir($config)) return false; - return $this->_write($file, serialize($def)); + return $this->_write($file, serialize($def), $config); } public function replace($def, $config) { @@ -24,7 +24,7 @@ class HTMLPurifier_DefinitionCache_Serializer extends $file = $this->generateFilePath($config); if (!file_exists($file)) return false; if (!$this->_prepareDir($config)) return false; - return $this->_write($file, serialize($def)); + return $this->_write($file, serialize($def), $config); } public function get($config) { @@ -97,18 +97,34 @@ class HTMLPurifier_DefinitionCache_Serializer extends * Convenience wrapper function for file_put_contents * @param $file File name to write to * @param $data Data to write into file + * @param $config Config object * @return Number of bytes written if success, or false if failure. */ - private function _write($file, $data) { - return file_put_contents($file, $data); + private function _write($file, $data, $config) { + $result = file_put_contents($file, $data); + if ($result !== false) { + // set permissions of the new file (no execute) + $chmod = $config->get('Cache.SerializerPermissions'); + if (!$chmod) { + $chmod = 0644; // invalid config or simpletest + } + $chmod = $chmod & 0666; + chmod($file, $chmod); + } + return $result; } /** * Prepares the directory that this type stores the serials in + * @param $config Config object * @return True if successful */ private function _prepareDir($config) { $directory = $this->generateDirectoryPath($config); + $chmod = $config->get('Cache.SerializerPermissions'); + if (!$chmod) { + $chmod = 0755; // invalid config or simpletest + } if (!is_dir($directory)) { $base = $this->generateBaseDirectoryPath($config); if (!is_dir($base)) { @@ -116,13 +132,13 @@ class HTMLPurifier_DefinitionCache_Serializer extends please create or change using %Cache.SerializerPath', E_USER_WARNING); return false; - } elseif (!$this->_testPermissions($base)) { + } elseif (!$this->_testPermissions($base, $chmod)) { return false; } - $old = umask(0022); // disable group and world writes - mkdir($directory); + $old = umask(0000); + mkdir($directory, $chmod); umask($old); - } elseif (!$this->_testPermissions($directory)) { + } elseif (!$this->_testPermissions($directory, $chmod)) { return false; } return true; @@ -131,8 +147,11 @@ class HTMLPurifier_DefinitionCache_Serializer extends /** * Tests permissions on a directory and throws out friendly * error messages and attempts to chmod it itself if possible + * @param $dir Directory path + * @param $chmod Permissions + * @return True if directory writable */ - private function _testPermissions($dir) { + private function _testPermissions($dir, $chmod) { // early abort, if it is writable, everything is hunky-dory if (is_writable($dir)) return true; if (!is_dir($dir)) { @@ -146,17 +165,17 @@ class HTMLPurifier_DefinitionCache_Serializer extends // POSIX system, we can give more specific advice if (fileowner($dir) === posix_getuid()) { // we can chmod it ourselves - chmod($dir, 0755); - return true; + $chmod = $chmod | 0700; + if (chmod($dir, $chmod)) return true; } elseif (filegroup($dir) === posix_getgid()) { - $chmod = '775'; + $chmod = $chmod | 0070; } else { // PHP's probably running as nobody, so we'll // need to give global permissions - $chmod = '777'; + $chmod = $chmod | 0777; } trigger_error('Directory '.$dir.' not writable, '. - 'please chmod to ' . $chmod, + 'please chmod to ' . decoct($chmod), E_USER_WARNING); } else { // generic error message diff --git a/tests/HTMLPurifier/DefinitionCache/SerializerTest.php b/tests/HTMLPurifier/DefinitionCache/SerializerTest.php index 857930dc..12b427ae 100644 --- a/tests/HTMLPurifier/DefinitionCache/SerializerTest.php +++ b/tests/HTMLPurifier/DefinitionCache/SerializerTest.php @@ -194,6 +194,27 @@ class HTMLPurifier_DefinitionCache_SerializerTest extends HTMLPurifier_Definitio } + function testAlternatePermissions() { + + $cache = new HTMLPurifier_DefinitionCache_Serializer('Test'); + $config = $this->generateConfigMock('serial'); + $config->version = '1.0.0'; + $config->setReturnValue('get', 1, array('Test.DefinitionRev')); + $dir = dirname(__FILE__) . '/SerializerTest'; + $config->setReturnValue('get', $dir, array('Cache.SerializerPath')); + $config->setReturnValue('get', 0777, array('Cache.SerializerPermissions')); + + $def_original = $this->generateDefinition(); + $cache->add($def_original, $config); + $this->assertFileExist($dir . '/Test/1.0.0,serial,1.ser'); + + $this->assertEqual(0666, 0777 & fileperms($dir . '/Test/1.0.0,serial,1.ser')); + $this->assertEqual(0777, 0777 & fileperms($dir . '/Test')); + + unlink($dir . '/Test/1.0.0,serial,1.ser'); + rmdir( $dir . '/Test'); + + } } // vim: et sw=4 sts=4