Implements Drupal\Component\PhpStorage\PhpStorageInterface::save().
Overrides FileStorage::save
public function save($name, $data) {
$this
->ensureDirectory();
// Write the file out to a temporary location. Prepend with a '.' to keep it
// hidden from listings and web servers.
$temporary_path = $this->directory . '/.' . str_replace('/', '#', $name);
if (!@file_put_contents($temporary_path, $data)) {
return FALSE;
}
chmod($temporary_path, 0400);
// Prepare a directory dedicated for just this file. Ensure it has a current
// mtime so that when the file (hashed on that mtime) is moved into it, the
// mtime remains the same (unless the clock ticks to the next second during
// the rename, in which case we'll try again).
$directory = $this
->getContainingDirectoryFullPath($name);
if (file_exists($directory)) {
$this
->cleanDirectory($directory);
touch($directory);
}
else {
mkdir($directory);
}
// Move the file to its final place. The mtime of a directory is the time of
// the last file create or delete in the directory. So the moving will
// update the directory mtime. However, this update will very likely not
// show up, because it has a coarse, one second granularity and typical
// moves takes significantly less than that. In the unlucky case the clock
// ticks during the move, we need to keep trying until the mtime we hashed
// on and the updated mtime match.
$previous_mtime = 0;
$i = 0;
while (($mtime = $this
->getUncachedMTime($directory)) && $mtime != $previous_mtime) {
$previous_mtime = $mtime;
chmod($directory, 0700);
// Reset the file back in the temporary location if this is not the first
// iteration.
if ($i > 0) {
rename($full_path, $temporary_path);
// Make sure to not loop infinitely on a hopelessly slow filesystem.
if ($i > 10) {
$this
->unlink($temporary_path);
return FALSE;
}
}
$full_path = $this
->getFullPath($name, $directory, $mtime);
rename($temporary_path, $full_path);
// Leave the directory neither readable nor writable. Since the file
// itself is not writable (set to 0400 at the beginning of this function),
// there's no way to tamper with it without access to change permissions.
chmod($directory, 0100);
$i++;
}
return TRUE;
}