Merge pull request #541 from kijin/pr/umask

파일/폴더 생성시 서버 환경에 따라 적절한 퍼미션을 자동으로 사용
This commit is contained in:
Kijin Sung 2016-07-03 23:37:35 +09:00 committed by GitHub
commit dd5c89b2f8
4 changed files with 166 additions and 19 deletions

View file

@ -5,6 +5,7 @@ namespace Rhymix\Framework\Parsers;
use Rhymix\Framework\Config;
use Rhymix\Framework\DateTime;
use Rhymix\Framework\Security;
use Rhymix\Framework\Storage;
/**
* Config parser class for XE compatibility.
@ -242,6 +243,7 @@ class ConfigParser
}
// Convert miscellaneous configuration.
$config['file']['umask'] = Storage::recommendUmask();
$config['mobile']['enabled'] = $db_info->use_mobile_view === 'N' ? false : true;
$config['use_prepared_statements'] = $db_info->use_prepared_statements === 'Y' ? true : false;
$config['use_rewrite'] = $db_info->use_rewrite === 'Y' ? true : false;

View file

@ -12,6 +12,11 @@ class Storage
*/
public static $safe_overwrite = true;
/**
* Cache the umask here.
*/
protected static $_umask;
/**
* Check if a path really exists.
*
@ -268,6 +273,8 @@ class Storage
return false;
}
@chmod($filename, ($perms === null ? (0666 & ~self::getUmask()) : $perms));
if (self::$safe_overwrite && strncasecmp($mode, 'a', 1))
{
$rename_success = @rename($filename, $original_filename);
@ -285,7 +292,6 @@ class Storage
$filename = $original_filename;
}
@chmod($filename, ($perms === null ? (0666 & ~umask()) : $perms));
if (function_exists('opcache_invalidate') && substr($filename, -4) === '.php')
{
@opcache_invalidate($filename, true);
@ -360,6 +366,22 @@ class Storage
return false;
}
if ($destination_perms === null)
{
if (is_uploaded_file($source))
{
@chmod($destination, 0666 & ~self::getUmask());
}
else
{
@chmod($destination, 0777 & @fileperms($source));
}
}
else
{
@chmod($destination, $destination_perms);
}
if (self::$safe_overwrite)
{
$rename_success = @rename($destination, $original_destination);
@ -377,20 +399,9 @@ class Storage
$destination = $original_destination;
}
if ($destination_perms === null)
if (function_exists('opcache_invalidate') && substr($destination, -4) === '.php')
{
if (is_uploaded_file($source))
{
@chmod($destination, 0666 ^ intval(config('file.umask'), 8));
}
else
{
@chmod($destination, 0777 & @fileperms($source));
}
}
else
{
@chmod($destination, $destination_perms);
@opcache_invalidate($destination, true);
}
clearstatcache(true, $destination);
@ -434,9 +445,16 @@ class Storage
return false;
}
if (function_exists('opcache_invalidate') && substr($source, -4) === '.php')
if (function_exists('opcache_invalidate'))
{
@opcache_invalidate($source, true);
if (substr($source, -4) === '.php')
{
@opcache_invalidate($source, true);
}
if (substr($destination, -4) === '.php')
{
@opcache_invalidate($destination, true);
}
}
clearstatcache(true, $destination);
@ -484,7 +502,7 @@ class Storage
$dirname = rtrim($dirname, '/\\');
if ($mode === null)
{
$mode = 0777 & ~umask();
$mode = 0777 & ~self::getUmask();
}
$result = @mkdir($dirname, $mode, true);
@ -684,4 +702,81 @@ class Storage
return true;
}
}
/**
* Get the current umask.
*
* @return int
*/
public static function getUmask()
{
if (self::$_umask === null)
{
self::$_umask = intval(config('file.umask'), 8) ?: 0;
}
return self::$_umask;
}
/**
* Set the current umask.
*
* @param int $umask
* @return void
*/
public static function setUmask($umask)
{
self::$_umask = intval($umask);
}
/**
* Determine the best umask for this installation of Rhymix.
*
* @return int
*/
public static function recommendUmask()
{
// On Windows, set the umask to 0000.
if (strncasecmp(\PHP_OS, 'Win', 3) === 0)
{
return '0000';
}
// Get the UID of the owner of the current file.
$file_uid = fileowner(__FILE__);
// Get the UID of the current PHP process.
if (function_exists('posix_geteuid'))
{
$php_uid = posix_geteuid();
}
else
{
$testfile = \RX_BASEDIR . 'files/cache/uidcheck';
if (self::exists($testfile))
{
self::delete($testfile);
}
if (self::write($testfile, 'TEST'))
{
$php_uid = fileowner($testfile);
self::delete($testfile);
}
else
{
$php_uid = -1;
}
}
// If both UIDs are the same, set the umask to 0022.
if ($file_uid == $php_uid)
{
return '0022';
}
// Otherwise, set the umask to 0000.
else
{
return '0000';
}
}
}

View file

@ -195,6 +195,9 @@ class installController extends install
// Set the default URL.
$config['url']['default'] = Context::getRequestUri();
// Set the default umask.
$config['file']['umask'] = Rhymix\Framework\Storage::recommendUmask();
// Load the new configuration.
Rhymix\Framework\Config::setAll($config);
Context::loadDBInfo($config);
@ -240,7 +243,7 @@ class installController extends install
}
// Apply site lock.
if (Context::get('use_sitelock') === 'Y')
{
$user_ip_range = getView('install')->detectUserIPRange();

View file

@ -138,7 +138,7 @@ class StorageTest extends \Codeception\TestCase\Test
$this->assertTrue(Rhymix\Framework\Storage::write($testfile, 'foobarbazzjazz'));
$this->assertTrue(file_exists($testfile));
$this->assertEquals('foobarbazzjazz', file_get_contents($testfile));
$this->assertEquals(0666 & ~umask(), fileperms($testfile) & 0777);
$this->assertEquals(0666 & ~Rhymix\Framework\Storage::getUmask(), fileperms($testfile) & 0777);
// Append test
$this->assertTrue(Rhymix\Framework\Storage::write($testfile, 'rhymix', 'a', 0666));
@ -164,6 +164,18 @@ class StorageTest extends \Codeception\TestCase\Test
$this->assertTrue(Rhymix\Framework\Storage::write($copyfile, $stream, 'a'));
$this->assertEquals('foobarbazzjazzrhymixfoobarbazzjazzrhymixrhymix', file_get_contents($copyfile));
fclose($stream);
// Umask test
if (strncasecmp(\PHP_OS, 'Win', 3) !== 0)
{
$umask = Rhymix\Framework\Storage::getUmask();
Rhymix\Framework\Storage::setUmask(0046);
$this->assertEquals(0046, Rhymix\Framework\Storage::getUmask());
$this->assertTrue(Rhymix\Framework\Storage::write($testfile, 'foobarbazzjazz'));
$this->assertEquals('foobarbazzjazz', file_get_contents($testfile));
$this->assertEquals(0620, fileperms($testfile) & 0777);
Rhymix\Framework\Storage::setUmask($umask);
}
}
public function testReadWritePHPData()
@ -221,6 +233,18 @@ class StorageTest extends \Codeception\TestCase\Test
$this->assertTrue(Rhymix\Framework\Storage::createDirectory($emptydir));
$this->assertTrue(file_exists($emptydir) && is_dir($emptydir));
// Umask test
if (strncasecmp(\PHP_OS, 'Win', 3) !== 0)
{
$umask = Rhymix\Framework\Storage::getUmask();
Rhymix\Framework\Storage::setUmask(0037);
$this->assertEquals(0037, Rhymix\Framework\Storage::getUmask());
$this->assertTrue(Rhymix\Framework\Storage::createDirectory($emptydir . '/umasktest'));
$this->assertTrue(is_dir($emptydir . '/umasktest'));
$this->assertEquals(0740, fileperms($emptydir . '/umasktest') & 0777);
Rhymix\Framework\Storage::setUmask($umask);
}
}
public function testReadDirectory()
@ -300,4 +324,27 @@ class StorageTest extends \Codeception\TestCase\Test
$this->assertTrue(file_exists($sourcedir));
$this->assertFalse(Rhymix\Framework\Storage::deleteDirectory($nonexistent));
}
public function testRecommendUmask()
{
$umask = Rhymix\Framework\Storage::recommendUmask();
if (strncasecmp(\PHP_OS, 'Win', 3) !== 0)
{
if (get_current_user() === exec('whoami'))
{
$this->assertEquals('0022', $umask);
}
else
{
$this->assertEquals('0000', $umask);
}
}
else
{
$this->assertEquals('0000', $umask);
}
$this->assertFalse(file_exists(\RX_BASEDIR . 'files/cache/uidcheck'));
}
}