123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269 |
- <?php
- namespace Drupal\Component\PhpStorage;
- /**
- * Stores the code as regular PHP files.
- */
- class FileStorage implements PhpStorageInterface {
- /**
- * The directory where the files should be stored.
- *
- * @var string
- */
- protected $directory;
- /**
- * Constructs this FileStorage object.
- *
- * @param array $configuration
- * An associative array, containing at least these two keys:
- * - directory: The directory where the files should be stored.
- * - bin: The storage bin. Multiple storage objects can be instantiated with
- * the same configuration, but for different bins..
- */
- public function __construct(array $configuration) {
- $this->directory = $configuration['directory'] . '/' . $configuration['bin'];
- }
- /**
- * {@inheritdoc}
- */
- public function exists($name) {
- return file_exists($this->getFullPath($name));
- }
- /**
- * {@inheritdoc}
- */
- public function load($name) {
- // The FALSE returned on failure is enough for the caller to handle this,
- // we do not want a warning too.
- return (@include_once $this->getFullPath($name)) !== FALSE;
- }
- /**
- * {@inheritdoc}
- */
- public function save($name, $code) {
- $path = $this->getFullPath($name);
- $directory = dirname($path);
- $this->ensureDirectory($directory);
- return (bool) file_put_contents($path, $code);
- }
- /**
- * Returns the standard .htaccess lines that Drupal writes to file directories.
- *
- * @param bool $private
- * (optional) Set to FALSE to return the .htaccess lines for an open and
- * public directory. The default is TRUE, which returns the .htaccess lines
- * for a private and protected directory.
- *
- * @return string
- * The desired contents of the .htaccess file.
- *
- * @see file_create_htaccess()
- */
- public static function htaccessLines($private = TRUE) {
- $lines = <<<EOF
- # Turn off all options we don't need.
- Options -Indexes -ExecCGI -Includes -MultiViews
- # Set the catch-all handler to prevent scripts from being executed.
- SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006
- <Files *>
- # Override the handler again if we're run later in the evaluation list.
- SetHandler Drupal_Security_Do_Not_Remove_See_SA_2013_003
- </Files>
- # If we know how to do it safely, disable the PHP engine entirely.
- <IfModule mod_php5.c>
- php_flag engine off
- </IfModule>
- EOF;
- if ($private) {
- $lines = <<<EOF
- # Deny all requests from Apache 2.4+.
- <IfModule mod_authz_core.c>
- Require all denied
- </IfModule>
- # Deny all requests from Apache 2.0-2.2.
- <IfModule !mod_authz_core.c>
- Deny from all
- </IfModule>
- $lines
- EOF;
- }
- return $lines;
- }
- /**
- * Ensures the directory exists, has the right permissions, and a .htaccess.
- *
- * For compatibility with open_basedir, the requested directory is created
- * using a recursion logic that is based on the relative directory path/tree:
- * It works from the end of the path recursively back towards the root
- * directory, until an existing parent directory is found. From there, the
- * subdirectories are created.
- *
- * @param string $directory
- * The directory path.
- * @param int $mode
- * The mode, permissions, the directory should have.
- */
- protected function ensureDirectory($directory, $mode = 0777) {
- if ($this->createDirectory($directory, $mode)) {
- $htaccess_path = $directory . '/.htaccess';
- if (!file_exists($htaccess_path) && file_put_contents($htaccess_path, static::htaccessLines())) {
- @chmod($htaccess_path, 0444);
- }
- }
- }
- /**
- * Ensures the requested directory exists and has the right permissions.
- *
- * For compatibility with open_basedir, the requested directory is created
- * using a recursion logic that is based on the relative directory path/tree:
- * It works from the end of the path recursively back towards the root
- * directory, until an existing parent directory is found. From there, the
- * subdirectories are created.
- *
- * @param string $directory
- * The directory path.
- * @param int $mode
- * The mode, permissions, the directory should have.
- *
- * @return bool
- * TRUE if the directory exists or has been created, FALSE otherwise.
- */
- protected function createDirectory($directory, $mode = 0777) {
- // If the directory exists already, there's nothing to do.
- if (is_dir($directory)) {
- return TRUE;
- }
- // If the parent directory doesn't exist, try to create it.
- $parent_exists = is_dir($parent = dirname($directory));
- if (!$parent_exists) {
- $parent_exists = $this->createDirectory($parent, $mode);
- }
- // If parent exists, try to create the directory and ensure to set its
- // permissions, because mkdir() obeys the umask of the current process.
- if ($parent_exists) {
- // We hide warnings and ignore the return because there may have been a
- // race getting here and the directory could already exist.
- @mkdir($directory);
- // Only try to chmod() if the subdirectory could be created.
- if (is_dir($directory)) {
- // Avoid writing permissions if possible.
- if (fileperms($directory) !== $mode) {
- return chmod($directory, $mode);
- }
- return TRUE;
- }
- else {
- // Something failed and the directory doesn't exist.
- trigger_error('mkdir(): Permission Denied', E_USER_WARNING);
- }
- }
- return FALSE;
- }
- /**
- * {@inheritdoc}
- */
- public function delete($name) {
- $path = $this->getFullPath($name);
- if (file_exists($path)) {
- return $this->unlink($path);
- }
- return FALSE;
- }
- /**
- * {@inheritdoc}
- */
- public function getFullPath($name) {
- return $this->directory . '/' . $name;
- }
- /**
- * {@inheritdoc}
- */
- public function writeable() {
- return TRUE;
- }
- /**
- * {@inheritdoc}
- */
- public function deleteAll() {
- return $this->unlink($this->directory);
- }
- /**
- * Deletes files and/or directories in the specified path.
- *
- * If the specified path is a directory the method will
- * call itself recursively to process the contents. Once the contents have
- * been removed the directory will also be removed.
- *
- * @param string $path
- * A string containing either a file or directory path.
- *
- * @return bool
- * TRUE for success or if path does not exist, FALSE in the event of an
- * error.
- */
- protected function unlink($path) {
- if (file_exists($path)) {
- if (is_dir($path)) {
- // Ensure the folder is writable.
- @chmod($path, 0777);
- foreach (new \DirectoryIterator($path) as $fileinfo) {
- if (!$fileinfo->isDot()) {
- $this->unlink($fileinfo->getPathName());
- }
- }
- return @rmdir($path);
- }
- // Windows needs the file to be writable.
- @chmod($path, 0700);
- return @unlink($path);
- }
- // If there's nothing to delete return TRUE anyway.
- return TRUE;
- }
- /**
- * {@inheritdoc}
- */
- public function listAll() {
- $names = [];
- if (file_exists($this->directory)) {
- foreach (new \DirectoryIterator($this->directory) as $fileinfo) {
- if (!$fileinfo->isDot()) {
- $name = $fileinfo->getFilename();
- if ($name != '.htaccess') {
- $names[] = $name;
- }
- }
- }
- }
- return $names;
- }
- /**
- * {@inheritdoc}
- */
- public function garbageCollection() {
- }
- }
|