HtaccessWriter.php 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. <?php
  2. namespace Drupal\Core\File;
  3. use Drupal\Component\FileSecurity\FileSecurity;
  4. use Drupal\Core\Site\Settings;
  5. use Drupal\Core\StreamWrapper\PrivateStream;
  6. use Drupal\Core\StreamWrapper\StreamWrapperManager;
  7. use Drupal\Core\StreamWrapper\StreamWrapperManagerInterface;
  8. use Psr\Log\LoggerInterface;
  9. /**
  10. * Provides functions to manage Apache .htaccess files.
  11. */
  12. class HtaccessWriter implements HtaccessWriterInterface {
  13. /**
  14. * The stream wrapper manager.
  15. *
  16. * @var \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface
  17. */
  18. protected $streamWrapperManager;
  19. /**
  20. * The logger.
  21. *
  22. * @var \Psr\Log\LoggerInterface
  23. */
  24. protected $logger;
  25. /**
  26. * Htaccess constructor.
  27. *
  28. * @param \Psr\Log\LoggerInterface $logger
  29. * The logger.
  30. * @param \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface $stream_wrapper_manager
  31. * The stream wrapper manager.
  32. */
  33. public function __construct(LoggerInterface $logger, StreamWrapperManagerInterface $stream_wrapper_manager) {
  34. $this->logger = $logger;
  35. $this->streamWrapperManager = $stream_wrapper_manager;
  36. }
  37. /**
  38. * {@inheritdoc}
  39. */
  40. public function ensure() {
  41. try {
  42. foreach ($this->defaultProtectedDirs() as $protected_dir) {
  43. $this->write($protected_dir->getPath(), $protected_dir->isPrivate());
  44. }
  45. $staging = Settings::get('config_sync_directory', FALSE);
  46. if ($staging) {
  47. // Note that we log an error here if we can't write the .htaccess file.
  48. // This can occur if the staging directory is read-only. If it is then
  49. // it is the user's responsibility to create the .htaccess file.
  50. $this->write($staging, TRUE);
  51. }
  52. }
  53. catch (\Exception $e) {
  54. $this->logger->error($e->getMessage());
  55. }
  56. }
  57. /**
  58. * Creates a .htaccess file in the given directory.
  59. *
  60. * @param string $directory
  61. * The directory.
  62. * @param bool $deny_public_access
  63. * (Optional) FALSE indicates that $directory should be a web-accessible
  64. * directory. Defaults to TRUE which indicates a private directory.
  65. * @param bool $force_overwrite
  66. * (Optional) Set to TRUE to attempt to overwrite the existing .htaccess
  67. * file if one is already present. Defaults to FALSE.
  68. *
  69. * @internal
  70. *
  71. * @return bool
  72. * TRUE if the .htaccess file was saved or already exists, FALSE otherwise.
  73. *
  74. * @see \Drupal\Component\FileSecurity\FileSecurity::writeHtaccess()
  75. */
  76. public function write($directory, $deny_public_access = TRUE, $force_overwrite = FALSE) {
  77. if (StreamWrapperManager::getScheme($directory)) {
  78. $directory = $this->streamWrapperManager->normalizeUri($directory);
  79. }
  80. else {
  81. $directory = rtrim($directory, '/\\');
  82. }
  83. if (FileSecurity::writeHtaccess($directory, $deny_public_access, $force_overwrite)) {
  84. return TRUE;
  85. }
  86. $this->logger->error("Security warning: Couldn't write .htaccess file. Please create a .htaccess file in your %directory directory which contains the following lines: <pre><code>@htaccess</code></pre>", ['%directory' => $directory, '@htaccess' => FileSecurity::htaccessLines($deny_public_access)]);
  87. return FALSE;
  88. }
  89. /**
  90. * {@inheritdoc}
  91. */
  92. public function defaultProtectedDirs() {
  93. $protected_dirs[] = new ProtectedDirectory('Public files directory', 'public://');
  94. if (PrivateStream::basePath()) {
  95. $protected_dirs[] = new ProtectedDirectory('Private files directory', 'private://', TRUE);
  96. }
  97. $protected_dirs[] = new ProtectedDirectory('Temporary files directory', 'temporary://');
  98. return $protected_dirs;
  99. }
  100. }