diff --git a/classes/validator/Validator.class.php b/classes/validator/Validator.class.php index ea7ea10b6..5c630c30c 100644 --- a/classes/validator/Validator.class.php +++ b/classes/validator/Validator.class.php @@ -682,7 +682,7 @@ class Validator return FALSE; } - @file_put_contents($filepath, $content, LOCK_EX); + Rhymix\Framework\Storage::write($filepath, $content); return $filepath; } diff --git a/common/framework/storage.php b/common/framework/storage.php index a1d53bfe8..07a804a36 100644 --- a/common/framework/storage.php +++ b/common/framework/storage.php @@ -7,6 +7,11 @@ namespace Rhymix\Framework; */ class Storage { + /** + * Use atomic rename to overwrite files. + */ + public static $safe_overwrite = true; + /** * Check if a path really exists. * @@ -217,12 +222,18 @@ class Storage if (!self::exists($destination_dir)) { $mkdir_success = self::createDirectory($destination_dir); - if (!$mkdir_success) + if (!$mkdir_success && !self::exists($destination_dir)) { return false; } } + if (self::$safe_overwrite && strncasecmp($mode, 'a', 1)) + { + $original_filename = $filename; + $filename = $filename . '.tmp.' . microtime(true); + } + if ($fp = fopen($filename, $mode)) { flock($fp, \LOCK_EX); @@ -243,11 +254,30 @@ class Storage return false; } + if (self::$safe_overwrite && strncasecmp($mode, 'a', 1)) + { + $rename_success = @rename($filename, $original_filename); + if (!$rename_success) + { + @unlink($original_filename); + $rename_success = @rename($filename, $original_filename); + if (!$rename_success) + { + @unlink($filename); + throw new Exception('foo'); + return false; + } + } + $filename = $original_filename; + } + @chmod($filename, ($perms === null ? (0666 & ~umask()) : $perms)); if (function_exists('opcache_invalidate') && substr($filename, -4) === '.php') { @opcache_invalidate($filename, true); } + + clearstatcache(true, $filename); return $result; } @@ -301,12 +331,35 @@ class Storage $destination = $destination . '/' . basename($source); } + if (self::$safe_overwrite) + { + $original_destination = $destination; + $destination = $destination . '.tmp.' . microtime(true); + } + $copy_success = @copy($source, $destination); if (!$copy_success) { return false; } + if (self::$safe_overwrite) + { + $rename_success = @rename($destination, $original_destination); + if (!$rename_success) + { + @unlink($original_destination); + $rename_success = @rename($destination, $original_destination); + if (!$rename_success) + { + @unlink($destination); + throw new Exception('foo'); + return false; + } + } + $destination = $original_destination; + } + if ($destination_perms === null) { if (is_uploaded_file($source)) @@ -322,6 +375,8 @@ class Storage { @chmod($destination, $destination_perms); } + + clearstatcache(true, $destination); return true; } @@ -358,6 +413,8 @@ class Storage { @opcache_invalidate($source, true); } + + clearstatcache(true, $destination); return $result; } diff --git a/modules/module/module.admin.controller.php b/modules/module/module.admin.controller.php index cb847d6fe..364a22d8c 100644 --- a/modules/module/module.admin.controller.php +++ b/modules/module/module.admin.controller.php @@ -904,7 +904,7 @@ class moduleAdminController extends module { $buff[] = sprintf('$lang[\'%s\'] = \'%s\';', $code, addcslashes($value, "'")); } - if (!@file_put_contents(sprintf('%s/%d.%s.php', $cache_path, $args->site_srl, $langCode), join(PHP_EOL, $buff), LOCK_EX)) + if (!Rhymix\Framework\Storage::write(sprintf('%s/%d.%s.php', $cache_path, $args->site_srl, $langCode), join(PHP_EOL, $buff))) { return; } diff --git a/modules/point/point.admin.controller.php b/modules/point/point.admin.controller.php index 7dfc6269f..3754bfab5 100644 --- a/modules/point/point.admin.controller.php +++ b/modules/point/point.admin.controller.php @@ -328,7 +328,7 @@ class pointAdminController extends point $str .= $key.','.$val."\r\n"; } - @file_put_contents('./files/cache/pointRecal.txt', $str, LOCK_EX); + Rhymix\Framework\Storage::write(\RX_BASEDIR . 'files/cache/pointRecal.txt', $str); $this->add('total', count($member)); $this->add('position', 0);