PageRenderTime 26ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/web/core/tests/Drupal/KernelTests/Core/File/DirectoryTest.php

https://gitlab.com/mohamed_hussein/prodt
PHP | 247 lines | 128 code | 37 blank | 82 comment | 9 complexity | 9ddb57165b80bc923333f562a0bd2980 MD5 | raw file
  1. <?php
  2. namespace Drupal\KernelTests\Core\File;
  3. use Drupal\Component\FileSecurity\FileSecurity;
  4. use Drupal\Component\FileSystem\FileSystem;
  5. use Drupal\Component\Render\FormattableMarkup;
  6. use Drupal\Core\Database\Database;
  7. use Drupal\Core\File\Exception\FileException;
  8. use Drupal\Core\File\FileSystemInterface;
  9. /**
  10. * Tests operations dealing with directories.
  11. *
  12. * @group File
  13. */
  14. class DirectoryTest extends FileTestBase {
  15. /**
  16. * Tests local directory handling functions.
  17. */
  18. public function testFileCheckLocalDirectoryHandling() {
  19. $site_path = $this->container->getParameter('site.path');
  20. $directory = $site_path . '/files';
  21. // Check a new recursively created local directory for correct file system
  22. // permissions.
  23. $parent = $this->randomMachineName();
  24. $child = $this->randomMachineName();
  25. // Files directory already exists.
  26. $this->assertDirectoryExists($directory);
  27. // Make files directory writable only.
  28. $old_mode = fileperms($directory);
  29. // Create the directories.
  30. $parent_path = $directory . DIRECTORY_SEPARATOR . $parent;
  31. $child_path = $parent_path . DIRECTORY_SEPARATOR . $child;
  32. /** @var \Drupal\Core\File\FileSystemInterface $file_system */
  33. $file_system = \Drupal::service('file_system');
  34. $this->assertTrue($file_system->mkdir($child_path, 0775, TRUE), 'No error reported when creating new local directories.');
  35. // Ensure new directories also exist.
  36. $this->assertDirectoryExists($parent_path);
  37. $this->assertDirectoryExists($child_path);
  38. // Check that new directory permissions were set properly.
  39. $this->assertDirectoryPermissions($parent_path, 0775);
  40. $this->assertDirectoryPermissions($child_path, 0775);
  41. // Check that existing directory permissions were not modified.
  42. $this->assertDirectoryPermissions($directory, $old_mode);
  43. // Check creating a directory using an absolute path.
  44. $absolute_path = $file_system->realpath($directory) . DIRECTORY_SEPARATOR . $this->randomMachineName() . DIRECTORY_SEPARATOR . $this->randomMachineName();
  45. $this->assertTrue($file_system->mkdir($absolute_path, 0775, TRUE), 'No error reported when creating new absolute directories.', 'File');
  46. $this->assertDirectoryPermissions($absolute_path, 0775);
  47. }
  48. /**
  49. * Tests directory handling functions.
  50. */
  51. public function testFileCheckDirectoryHandling() {
  52. // A directory to operate on.
  53. $default_scheme = 'public';
  54. $directory = $default_scheme . '://' . $this->randomMachineName() . '/' . $this->randomMachineName();
  55. $this->assertDirectoryDoesNotExist($directory);
  56. // Non-existent directory.
  57. /** @var \Drupal\Core\File\FileSystemInterface $file_system */
  58. $file_system = \Drupal::service('file_system');
  59. $this->assertFalse($file_system->prepareDirectory($directory, 0), 'Error reported for non-existing directory.', 'File');
  60. // Make a directory.
  61. $this->assertTrue($file_system->prepareDirectory($directory, FileSystemInterface::CREATE_DIRECTORY), 'No error reported when creating a new directory.', 'File');
  62. // Make sure directory actually exists.
  63. $this->assertDirectoryExists($directory);
  64. $file_system = \Drupal::service('file_system');
  65. if (substr(PHP_OS, 0, 3) != 'WIN') {
  66. // PHP on Windows doesn't support any kind of useful read-only mode for
  67. // directories. When executing a chmod() on a directory, PHP only sets the
  68. // read-only flag, which doesn't prevent files to actually be written
  69. // in the directory on any recent version of Windows.
  70. // Make directory read only.
  71. @$file_system->chmod($directory, 0444);
  72. $this->assertFalse($file_system->prepareDirectory($directory, 0), 'Error reported for a non-writable directory.', 'File');
  73. // Test directory permission modification.
  74. $this->setSetting('file_chmod_directory', 0777);
  75. $this->assertTrue($file_system->prepareDirectory($directory, FileSystemInterface::MODIFY_PERMISSIONS), 'No error reported when making directory writable.', 'File');
  76. }
  77. // Test that the directory has the correct permissions.
  78. $this->assertDirectoryPermissions($directory, 0777, 'file_chmod_directory setting is respected.');
  79. // Remove .htaccess file to then test that it gets re-created.
  80. @$file_system->unlink($default_scheme . '://.htaccess');
  81. $this->assertFileDoesNotExist($default_scheme . '://.htaccess');
  82. $this->container->get('file.htaccess_writer')->ensure();
  83. $this->assertFileExists($default_scheme . '://.htaccess');
  84. // Remove .htaccess file again to test that it is re-created by a cron run.
  85. @$file_system->unlink($default_scheme . '://.htaccess');
  86. $this->assertFileDoesNotExist($default_scheme . '://.htaccess');
  87. system_cron();
  88. $this->assertFileExists($default_scheme . '://.htaccess');
  89. // Verify contents of .htaccess file.
  90. $file = file_get_contents($default_scheme . '://.htaccess');
  91. $this->assertEquals(FileSecurity::htaccessLines(FALSE), $file, 'The .htaccess file contains the proper content.');
  92. }
  93. /**
  94. * This will take a directory and path, and find a valid filepath that is not
  95. * taken by another file.
  96. */
  97. public function testFileCreateNewFilepath() {
  98. // First we test against an imaginary file that does not exist in a
  99. // directory.
  100. $basename = 'xyz.txt';
  101. $directory = 'core/misc';
  102. $original = $directory . '/' . $basename;
  103. /** @var \Drupal\Core\File\FileSystemInterface $file_system */
  104. $file_system = \Drupal::service('file_system');
  105. $path = $file_system->createFilename($basename, $directory);
  106. $this->assertEquals($original, $path, new FormattableMarkup('New filepath %new equals %original.', ['%new' => $path, '%original' => $original]));
  107. // Then we test against a file that already exists within that directory.
  108. $basename = 'druplicon.png';
  109. $original = $directory . '/' . $basename;
  110. $expected = $directory . '/druplicon_0.png';
  111. $path = $file_system->createFilename($basename, $directory);
  112. $this->assertEquals($expected, $path, new FormattableMarkup('Creating a new filepath from %original equals %new (expected %expected).', ['%new' => $path, '%original' => $original, '%expected' => $expected]));
  113. // @TODO: Finally we copy a file into a directory several times, to ensure a properly iterating filename suffix.
  114. }
  115. /**
  116. * This will test the filepath for a destination based on passed flags and
  117. * whether or not the file exists.
  118. *
  119. * If a file exists, ::getDestinationFilename($destination, $replace) will
  120. * either return:
  121. * - the existing filepath, if $replace is FileSystemInterface::EXISTS_REPLACE
  122. * - a new filepath if FileSystemInterface::EXISTS_RENAME
  123. * - an error (returning FALSE) if FileSystemInterface::EXISTS_ERROR.
  124. * If the file doesn't currently exist, then it will simply return the
  125. * filepath.
  126. */
  127. public function testFileDestination() {
  128. // First test for non-existent file.
  129. $destination = 'core/misc/xyz.txt';
  130. /** @var \Drupal\Core\File\FileSystemInterface $file_system */
  131. $file_system = \Drupal::service('file_system');
  132. $path = $file_system->getDestinationFilename($destination, FileSystemInterface::EXISTS_REPLACE);
  133. $this->assertEquals($destination, $path, 'Non-existing filepath destination is correct with FileSystemInterface::EXISTS_REPLACE.');
  134. $path = $file_system->getDestinationFilename($destination, FileSystemInterface::EXISTS_RENAME);
  135. $this->assertEquals($destination, $path, 'Non-existing filepath destination is correct with FileSystemInterface::EXISTS_RENAME.');
  136. $path = $file_system->getDestinationFilename($destination, FileSystemInterface::EXISTS_ERROR);
  137. $this->assertEquals($destination, $path, 'Non-existing filepath destination is correct with FileSystemInterface::EXISTS_ERROR.');
  138. $destination = 'core/misc/druplicon.png';
  139. $path = $file_system->getDestinationFilename($destination, FileSystemInterface::EXISTS_REPLACE);
  140. $this->assertEquals($destination, $path, 'Existing filepath destination remains the same with FileSystemInterface::EXISTS_REPLACE.');
  141. $path = $file_system->getDestinationFilename($destination, FileSystemInterface::EXISTS_RENAME);
  142. $this->assertNotEquals($destination, $path, 'A new filepath destination is created when filepath destination already exists with FileSystemInterface::EXISTS_RENAME.');
  143. $path = $file_system->getDestinationFilename($destination, FileSystemInterface::EXISTS_ERROR);
  144. $this->assertFalse($path, 'An error is returned when filepath destination already exists with FileSystemInterface::EXISTS_ERROR.');
  145. // Invalid UTF-8 causes an exception.
  146. $this->expectException(FileException::class);
  147. $this->expectExceptionMessage("Invalid filename 'a\xFFtest\x80€.txt'");
  148. $file_system->getDestinationFilename("core/misc/a\xFFtest\x80€.txt", FileSystemInterface::EXISTS_REPLACE);
  149. }
  150. /**
  151. * Ensure that the getTempDirectory() method always returns a value.
  152. */
  153. public function testFileDirectoryTemp() {
  154. $tmp_directory = \Drupal::service('file_system')->getTempDirectory();
  155. $this->assertNotEmpty($tmp_directory);
  156. $this->assertEquals($tmp_directory, FileSystem::getOsTemporaryDirectory());
  157. }
  158. /**
  159. * Tests directory creation.
  160. */
  161. public function testDirectoryCreation() {
  162. /** @var \Drupal\Core\File\FileSystemInterface $file_system */
  163. $file_system = $this->container->get('file_system');
  164. // mkdir() recursion should work with or without a trailing slash.
  165. $dir = $this->siteDirectory . '/files';
  166. $this->assertTrue($file_system->mkdir($dir . '/foo/bar', 0775, TRUE));
  167. $this->assertTrue($file_system->mkdir($dir . '/foo/baz/', 0775, TRUE));
  168. }
  169. /**
  170. * Tests asynchronous directory creation.
  171. *
  172. * Image style generation can result in many calls to create similar directory
  173. * paths. This test forks the process to create the same situation.
  174. */
  175. public function testMultiplePrepareDirectory() {
  176. if (!function_exists('pcntl_fork')) {
  177. $this->markTestSkipped('Requires the pcntl_fork() function');
  178. }
  179. $directories = [];
  180. for ($i = 1; $i <= 10; $i++) {
  181. $directories[] = 'public://a/b/c/d/e/f/g/h/' . $i;
  182. }
  183. $file_system = $this->container->get('file_system');
  184. $time_to_start = microtime(TRUE) + 0.1;
  185. // This loop creates a new fork to create each directory.
  186. foreach ($directories as $directory) {
  187. $pid = pcntl_fork();
  188. if ($pid == -1) {
  189. $this->fail("Error forking");
  190. }
  191. elseif ($pid == 0) {
  192. // Sleep so that all the forks start preparing the directory at the same
  193. // time.
  194. usleep((int) (($time_to_start - microtime(TRUE)) * 1000000));
  195. $file_system->prepareDirectory($directory, FileSystemInterface::CREATE_DIRECTORY);
  196. exit();
  197. }
  198. }
  199. // This while loop holds the parent process until all the child threads
  200. // are complete - at which point the script continues to execute.
  201. while (pcntl_waitpid(0, $status) != -1);
  202. foreach ($directories as $directory) {
  203. $this->assertDirectoryExists($directory);
  204. }
  205. // Remove the database connection because it will have been destroyed when
  206. // the forks exited. This allows
  207. // \Drupal\KernelTests\KernelTestBase::tearDown() to reopen it.
  208. Database::removeConnection('default');
  209. }
  210. }