* * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Cache\Adapter; use Symfony\Component\Cache\Exception\InvalidArgumentException; /** * @author Nicolas Grekas */ class FilesystemAdapter extends AbstractAdapter { private $directory; public function __construct($directory, $defaultLifetime = null) { parent::__construct('', $defaultLifetime); if (!file_exists($dir = $directory.'/.')) { @mkdir($directory, 0777, true); } if (false === $dir = realpath($dir)) { throw new InvalidArgumentException(sprintf('Cache directory does not exist (%s)', $directory)); } if (!is_writable($dir .= DIRECTORY_SEPARATOR)) { throw new InvalidArgumentException(sprintf('Cache directory is not writable (%s)', $directory)); } // On Windows the whole path is limited to 258 chars if ('\\' === DIRECTORY_SEPARATOR && strlen($dir) > 190) { throw new InvalidArgumentException(sprintf('Cache directory too long (%s)', $directory)); } $this->directory = $dir; } /** * {@inheritdoc} */ protected function doFetch(array $ids) { $values = array(); $now = time(); foreach ($ids as $id) { $file = $this->getFile($id); if (!$h = @fopen($file, 'rb')) { continue; } flock($h, LOCK_SH); if ($now >= (int) $expiresAt = fgets($h)) { flock($h, LOCK_UN); fclose($h); if (isset($expiresAt[0])) { @unlink($file); } } else { $value = stream_get_contents($h); flock($h, LOCK_UN); fclose($h); $values[$id] = unserialize($value); } } return $values; } /** * {@inheritdoc} */ protected function doHave($id) { $file = $this->getFile($id); return file_exists($file) && (@filemtime($file) > time() || $this->doFetch(array($id))); } /** * {@inheritdoc} */ protected function doClear($namespace) { $ok = true; foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->directory, \FilesystemIterator::SKIP_DOTS)) as $file) { $ok = ($file->isDir() || @unlink($file) || !file_exists($file)) && $ok; } return $ok; } /** * {@inheritdoc} */ protected function doDelete(array $ids) { $ok = true; foreach ($ids as $id) { $file = $this->getFile($id); $ok = (!file_exists($file) || @unlink($file) || !file_exists($file)) && $ok; } return $ok; } /** * {@inheritdoc} */ protected function doSave(array $values, $lifetime) { $ok = true; $expiresAt = $lifetime ? time() + $lifetime : PHP_INT_MAX; foreach ($values as $id => $value) { $file = $this->getFile($id); $dir = dirname($file); if (!file_exists($dir)) { @mkdir($dir, 0777, true); } $value = $expiresAt."\n".serialize($value); if (false !== @file_put_contents($file, $value, LOCK_EX)) { @touch($file, $expiresAt); } else { $ok = false; } } return $ok; } private function getFile($id) { $hash = hash('sha256', $id); return $this->directory.$hash[0].DIRECTORY_SEPARATOR.$hash[1].DIRECTORY_SEPARATOR.$hash; } }