Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.
   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  namespace core_files\local\archive_writer;
  18  
  19  use advanced_testcase;
  20  use context_module;
  21  use core_files\archive_writer;
  22  use ZipArchive;
  23  
  24  /**
  25   * Unit tests for \core_files\local\archive_writer\zip_writer.
  26   *
  27   * @package core_files
  28   * @category test
  29   * @copyright 2020 Mark Nelson <mdjnelson@gmail.com>
  30   * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
  31   * @covers \core_files\local\archive_writer\zip_writer
  32   */
  33  class zip_writer_test extends advanced_testcase {
  34  
  35      /**
  36       * Test add_file_from_filepath().
  37       */
  38      public function test_add_file_from_filepath(): void {
  39          global $CFG;
  40  
  41          $pathtofileinzip = '/some/made/up/name.txt';
  42          $filetoadd = $CFG->dirroot . '/files/tests/fixtures/awesome_file.txt';
  43  
  44          $zipwriter = archive_writer::get_file_writer('test.zip', archive_writer::ZIP_WRITER);
  45          $zipwriter->add_file_from_filepath($pathtofileinzip, $filetoadd);
  46          $zipwriter->finish();
  47  
  48          $pathtozip = $zipwriter->get_path_to_zip();
  49          $zip = new ZipArchive();
  50          $opened = $zip->open($pathtozip);
  51          $this->assertTrue($opened);
  52  
  53          $pathtofileinzip = $zipwriter->sanitise_filepath($pathtofileinzip);
  54  
  55          $this->assertEquals("Hey, this is an awesome text file. Hello! :)", $zip->getFromName($pathtofileinzip));
  56      }
  57  
  58      /**
  59       * Test add_file_from_string().
  60       */
  61      public function test_add_file_from_string(): void {
  62          $pathtofileinzip = "/path/to/my/awesome/file.txt";
  63          $mycontent = "This is some real awesome content, ya dig?";
  64  
  65          $zipwriter = archive_writer::get_file_writer('test.zip', archive_writer::ZIP_WRITER);
  66          $zipwriter->add_file_from_string($pathtofileinzip, $mycontent);
  67          $zipwriter->finish();
  68  
  69          $pathtozip = $zipwriter->get_path_to_zip();
  70          $zip = new ZipArchive();
  71          $opened = $zip->open($pathtozip);
  72          $this->assertTrue($opened);
  73  
  74          $pathtofileinzip = $zipwriter->sanitise_filepath($pathtofileinzip);
  75  
  76          $this->assertEquals($mycontent, $zip->getFromName($pathtofileinzip));
  77      }
  78  
  79      /**
  80       * Test add_file_from_stream().
  81       */
  82      public function test_add_file_from_stream(): void {
  83          $this->resetAfterTest(true);
  84          $this->setAdminUser();
  85  
  86          $course = $this->getDataGenerator()->create_course();
  87          $assign = $this->getDataGenerator()->create_module('assign', ['course' => $course->id]);
  88  
  89          // Add a file to the intro.
  90          $filerecord = [
  91              'contextid' => context_module::instance($assign->cmid)->id,
  92              'component' => 'mod_assign',
  93              'filearea'  => 'intro',
  94              'itemid'    => 0,
  95              'filepath'  => '/',
  96              'filename'  => 'fileintro.txt',
  97          ];
  98          $fs = get_file_storage();
  99          $storedfile = $fs->create_file_from_string($filerecord, 'Contents for the assignment, yeow!');
 100  
 101          $pathtofileinzip = $storedfile->get_filepath() . $storedfile->get_filename();
 102  
 103          $zipwriter = archive_writer::get_file_writer('test.zip', archive_writer::ZIP_WRITER);
 104          $zipwriter->add_file_from_stream($pathtofileinzip, $storedfile->get_content_file_handle());
 105          $zipwriter->finish();
 106  
 107          $pathtozip = $zipwriter->get_path_to_zip();
 108          $zip = new ZipArchive();
 109          $opened = $zip->open($pathtozip);
 110          $this->assertTrue($opened);
 111  
 112          $pathtofileinzip = $zipwriter->sanitise_filepath($pathtofileinzip);
 113  
 114          $this->assertEquals($storedfile->get_content(), $zip->getFromName($pathtofileinzip));
 115      }
 116  
 117      /**
 118       * Test add_file_from_stored_file().
 119       */
 120      public function test_add_file_from_stored_file(): void {
 121          $this->resetAfterTest(true);
 122          $this->setAdminUser();
 123  
 124          $course = $this->getDataGenerator()->create_course();
 125          $assign = $this->getDataGenerator()->create_module('assign', ['course' => $course->id]);
 126  
 127          // Add a file to the intro.
 128          $filerecord = [
 129              'contextid' => context_module::instance($assign->cmid)->id,
 130              'component' => 'mod_assign',
 131              'filearea'  => 'intro',
 132              'itemid'    => 0,
 133              'filepath'  => '/',
 134              'filename'  => 'fileintro.txt',
 135          ];
 136          $fs = get_file_storage();
 137          $storedfile = $fs->create_file_from_string($filerecord, 'Contents for the assignment, yeow!');
 138  
 139          $pathtofileinzip = $storedfile->get_filepath() . $storedfile->get_filename();
 140  
 141          $zipwriter = archive_writer::get_file_writer('test.zip', archive_writer::ZIP_WRITER);
 142          $zipwriter->add_file_from_stored_file($pathtofileinzip, $storedfile);
 143          $zipwriter->finish();
 144  
 145          $pathtozip = $zipwriter->get_path_to_zip();
 146          $zip = new ZipArchive();
 147          $opened = $zip->open($pathtozip);
 148          $this->assertTrue($opened);
 149  
 150          $pathtofileinzip = $zipwriter->sanitise_filepath($pathtofileinzip);
 151  
 152          $this->assertEquals($storedfile->get_content(), $zip->getFromName($pathtofileinzip));
 153      }
 154  
 155      /**
 156       * Test sanitise_filepath().
 157       *
 158       * @param string $providedfilepath The provided file path.
 159       * @param string $expectedfilepath The expected file path.
 160       * @dataProvider sanitise_filepath_provider
 161       */
 162      public function test_sanitise_filepath(string $providedfilepath, string $expectedfilepath): void {
 163          $zipwriter = archive_writer::get_stream_writer('path/to/file.txt', archive_writer::ZIP_WRITER);
 164          $this->assertEquals($expectedfilepath, $zipwriter->sanitise_filepath($providedfilepath));
 165      }
 166  
 167      /**
 168       * Data provider for test_sanitise_filepath.
 169       *
 170       * @return array
 171       */
 172      public function sanitise_filepath_provider(): array {
 173          return [
 174              ['a../../file/path', 'a../file/path'],
 175              ['a./file/path', 'a./file/path'],
 176              ['../file/path', 'file/path'],
 177              ['foo/bar/', 'foo/bar/'],
 178              ['\\\\\\a\\\\\\file\\\\\\path', 'a/file/path'],
 179              ['//a//file/////path////', 'a/file/path/']
 180          ];
 181      }
 182  }