Download.php 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. <?php
  2. /**
  3. * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
  4. * SPDX-License-Identifier: AGPL-3.0-or-later
  5. */
  6. use PHPUnit\Framework\Assert;
  7. use Psr\Http\Message\StreamInterface;
  8. require __DIR__ . '/../../vendor/autoload.php';
  9. trait Download {
  10. /** @var string * */
  11. private $downloadedFile;
  12. /** @AfterScenario **/
  13. public function cleanupDownloadedFile() {
  14. $this->downloadedFile = null;
  15. }
  16. /**
  17. * @When user :user downloads zip file for entries :entries in folder :folder
  18. */
  19. public function userDownloadsZipFileForEntriesInFolder($user, $entries, $folder) {
  20. $folder = trim($folder, '/');
  21. $this->asAn($user);
  22. $this->sendingToDirectUrl('GET', "/remote.php/dav/files/$user/$folder?accept=zip&files=[" . $entries . ']');
  23. $this->theHTTPStatusCodeShouldBe('200');
  24. }
  25. private function getDownloadedFile() {
  26. $this->downloadedFile = '';
  27. /** @var StreamInterface */
  28. $body = $this->response->getBody();
  29. while (!$body->eof()) {
  30. $this->downloadedFile .= $body->read(8192);
  31. }
  32. $body->close();
  33. }
  34. /**
  35. * @Then the downloaded file is a zip file
  36. */
  37. public function theDownloadedFileIsAZipFile() {
  38. $this->getDownloadedFile();
  39. Assert::assertTrue(
  40. strpos($this->downloadedFile, "\x50\x4B\x01\x02") !== false,
  41. 'File does not contain the central directory file header'
  42. );
  43. }
  44. /**
  45. * @Then the downloaded zip file is a zip32 file
  46. */
  47. public function theDownloadedZipFileIsAZip32File() {
  48. $this->theDownloadedFileIsAZipFile();
  49. // assertNotContains is not used to prevent the whole file from being
  50. // printed in case of error.
  51. Assert::assertTrue(
  52. strpos($this->downloadedFile, "\x50\x4B\x06\x06") === false,
  53. 'File contains the zip64 end of central dir signature'
  54. );
  55. }
  56. /**
  57. * @Then the downloaded zip file is a zip64 file
  58. */
  59. public function theDownloadedZipFileIsAZip64File() {
  60. $this->theDownloadedFileIsAZipFile();
  61. // assertNotContains is not used to prevent the whole file from being
  62. // printed in case of error.
  63. Assert::assertTrue(
  64. strpos($this->downloadedFile, "\x50\x4B\x06\x06") !== false,
  65. 'File does not contain the zip64 end of central dir signature'
  66. );
  67. }
  68. /**
  69. * @Then the downloaded zip file contains a file named :fileName with the contents of :sourceFileName from :user data
  70. */
  71. public function theDownloadedZipFileContainsAFileNamedWithTheContentsOfFromData($fileName, $sourceFileName, $user) {
  72. $fileHeaderRegExp = '/';
  73. $fileHeaderRegExp .= "\x50\x4B\x03\x04"; // Local file header signature
  74. $fileHeaderRegExp .= '.{22,22}'; // Ignore from "version needed to extract" to "uncompressed size"
  75. $fileHeaderRegExp .= preg_quote(pack('v', strlen($fileName)), '/'); // File name length
  76. $fileHeaderRegExp .= '(.{2,2})'; // Get "extra field length"
  77. $fileHeaderRegExp .= preg_quote($fileName, '/'); // File name
  78. $fileHeaderRegExp .= '/s'; // PCRE_DOTALL, so all characters (including bytes that happen to be new line characters) match
  79. // assertRegExp is not used to prevent the whole file from being printed
  80. // in case of error and to be able to get the extra field length.
  81. Assert::assertEquals(
  82. 1, preg_match($fileHeaderRegExp, $this->downloadedFile, $matches),
  83. 'Local header for file did not appear once in zip file'
  84. );
  85. $extraFieldLength = unpack('vextraFieldLength', $matches[1])['extraFieldLength'];
  86. $expectedFileContents = file_get_contents($this->getDataDirectory() . "/$user/files" . $sourceFileName);
  87. $fileHeaderAndContentRegExp = '/';
  88. $fileHeaderAndContentRegExp .= "\x50\x4B\x03\x04"; // Local file header signature
  89. $fileHeaderAndContentRegExp .= '.{22,22}'; // Ignore from "version needed to extract" to "uncompressed size"
  90. $fileHeaderAndContentRegExp .= preg_quote(pack('v', strlen($fileName)), '/'); // File name length
  91. $fileHeaderAndContentRegExp .= '.{2,2}'; // Ignore "extra field length"
  92. $fileHeaderAndContentRegExp .= preg_quote($fileName, '/'); // File name
  93. $fileHeaderAndContentRegExp .= '.{' . $extraFieldLength . ',' . $extraFieldLength . '}'; // Ignore "extra field"
  94. $fileHeaderAndContentRegExp .= preg_quote($expectedFileContents, '/'); // File contents
  95. $fileHeaderAndContentRegExp .= '/s'; // PCRE_DOTALL, so all characters (including bytes that happen to be new line characters) match
  96. // assertRegExp is not used to prevent the whole file from being printed
  97. // in case of error.
  98. Assert::assertEquals(
  99. 1, preg_match($fileHeaderAndContentRegExp, $this->downloadedFile),
  100. 'Local header and contents for file did not appear once in zip file'
  101. );
  102. }
  103. /**
  104. * @Then the downloaded zip file contains a folder named :folderName
  105. */
  106. public function theDownloadedZipFileContainsAFolderNamed($folderName) {
  107. $folderHeaderRegExp = '/';
  108. $folderHeaderRegExp .= "\x50\x4B\x03\x04"; // Local file header signature
  109. $folderHeaderRegExp .= '.{22,22}'; // Ignore from "version needed to extract" to "uncompressed size"
  110. $folderHeaderRegExp .= preg_quote(pack('v', strlen($folderName)), '/'); // File name length
  111. $folderHeaderRegExp .= '.{2,2}'; // Ignore "extra field length"
  112. $folderHeaderRegExp .= preg_quote($folderName, '/'); // File name
  113. $folderHeaderRegExp .= '/s'; // PCRE_DOTALL, so all characters (including bytes that happen to be new line characters) match
  114. // assertRegExp is not used to prevent the whole file from being printed
  115. // in case of error.
  116. Assert::assertEquals(
  117. 1, preg_match($folderHeaderRegExp, $this->downloadedFile),
  118. 'Local header for folder did not appear once in zip file'
  119. );
  120. }
  121. /**
  122. * @Then the downloaded file has the content of :sourceFilename from :user data
  123. */
  124. public function theDownloadedFileHasContentOfUserFile($sourceFilename, $user) {
  125. $this->getDownloadedFile();
  126. $expectedFileContents = file_get_contents($this->getDataDirectory() . "/$user/files" . $sourceFilename);
  127. // prevent the whole file from being printed in case of error.
  128. Assert::assertEquals(
  129. 0, strcmp($expectedFileContents, $this->downloadedFile),
  130. 'Downloaded file content does not match local file content'
  131. );
  132. }
  133. }