Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 310 and 311] [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403] [Versions 39 and 310]

   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  
  18  /**
  19   * PHPunit tests for external files API.
  20   *
  21   * @package    core_files
  22   * @category   external
  23   * @copyright  2013 Ankit Agarwal
  24   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  25   * @since Moodle 2.6
  26   */
  27  defined('MOODLE_INTERNAL') || die();
  28  
  29  global $CFG;
  30  
  31  require_once($CFG->dirroot . '/webservice/tests/helpers.php');
  32  require_once($CFG->dirroot . '/files/externallib.php');
  33  
  34  class core_files_externallib_testcase extends advanced_testcase {
  35  
  36      /*
  37       * Test core_files_external::upload().
  38       */
  39  
  40      public function test_upload() {
  41          global $USER;
  42  
  43          $this->resetAfterTest();
  44          $this->setAdminUser();
  45          $context = context_user::instance($USER->id);
  46          $contextid = $context->id;
  47          $component = "user";
  48          $filearea = "draft";
  49          $itemid = 0;
  50          $filepath = "/";
  51          $filename = "Simple.txt";
  52          $filecontent = base64_encode("Let us create a nice simple file");
  53          $contextlevel = null;
  54          $instanceid = null;
  55          $browser = get_file_browser();
  56  
  57          // Make sure no file exists.
  58          $file = $browser->get_file_info($context, $component, $filearea, $itemid, $filepath, $filename);
  59          $this->assertEmpty($file);
  60  
  61          // Call the api to create a file.
  62          $fileinfo = core_files_external::upload($contextid, $component, $filearea, $itemid, $filepath,
  63                  $filename, $filecontent, $contextlevel, $instanceid);
  64          $fileinfo = external_api::clean_returnvalue(core_files_external::upload_returns(), $fileinfo);
  65          // Get the created draft item id.
  66          $itemid = $fileinfo['itemid'];
  67  
  68          // Make sure the file was created.
  69          $file = $browser->get_file_info($context, $component, $filearea, $itemid, $filepath, $filename);
  70          $this->assertNotEmpty($file);
  71  
  72          // Make sure no file exists.
  73          $filename = "Simple2.txt";
  74          $file = $browser->get_file_info($context, $component, $filearea, $itemid, $filepath, $filename);
  75          $this->assertEmpty($file);
  76  
  77          // Call the api to create a file.
  78          $fileinfo = core_files_external::upload($contextid, $component, $filearea, $itemid,
  79                  $filepath, $filename, $filecontent, $contextlevel, $instanceid);
  80          $fileinfo = external_api::clean_returnvalue(core_files_external::upload_returns(), $fileinfo);
  81          $file = $browser->get_file_info($context, $component, $filearea, $itemid, $filepath, $filename);
  82          $this->assertNotEmpty($file);
  83  
  84          // Let us try creating a file using contextlevel and instance id.
  85          $filename = "Simple5.txt";
  86          $contextid = 0;
  87          $contextlevel = "user";
  88          $instanceid = $USER->id;
  89          $file = $browser->get_file_info($context, $component, $filearea, $itemid, $filepath, $filename);
  90          $this->assertEmpty($file);
  91          $fileinfo = core_files_external::upload($contextid, $component, $filearea, $itemid, $filepath,
  92                  $filename, $filecontent, $contextlevel, $instanceid);
  93          $fileinfo = external_api::clean_returnvalue(core_files_external::upload_returns(), $fileinfo);
  94          $file = $browser->get_file_info($context, $component, $filearea, $itemid, $filepath, $filename);
  95          $this->assertNotEmpty($file);
  96  
  97          // Make sure the same file cannot be created again.
  98          $this->expectException("moodle_exception");
  99          core_files_external::upload($contextid, $component, $filearea, $itemid, $filepath,
 100                  $filename, $filecontent, $contextlevel, $instanceid);
 101      }
 102  
 103      /*
 104       * Make sure only user component is allowed in  core_files_external::upload().
 105       */
 106      public function test_upload_param_component() {
 107          global $USER;
 108  
 109          $this->resetAfterTest();
 110          $this->setAdminUser();
 111          $context = context_user::instance($USER->id);
 112          $contextid = $context->id;
 113          $component = "backup";
 114          $filearea = "draft";
 115          $itemid = 0;
 116          $filepath = "/";
 117          $filename = "Simple3.txt";
 118          $filecontent = base64_encode("Let us create a nice simple file");
 119          $contextlevel = null;
 120          $instanceid = null;
 121  
 122          // Make sure exception is thrown.
 123          $this->expectException("coding_exception");
 124          core_files_external::upload($contextid, $component, $filearea, $itemid,
 125                  $filepath, $filename, $filecontent, $contextlevel, $instanceid);
 126      }
 127  
 128      /*
 129       * Make sure only draft areas are allowed in  core_files_external::upload().
 130       */
 131      public function test_upload_param_area() {
 132          global $USER;
 133  
 134          $this->resetAfterTest();
 135          $this->setAdminUser();
 136          $context = context_user::instance($USER->id);
 137          $contextid = $context->id;
 138          $component = "user";
 139          $filearea = "draft";
 140          $itemid = file_get_unused_draft_itemid();
 141          $filepath = "/";
 142          $filename = "Simple4.txt";
 143          $filecontent = base64_encode("Let us create a nice simple file");
 144          $contextlevel = null;
 145          $instanceid = null;
 146  
 147          // Make sure the file is created.
 148          $fileinfo = core_files_external::upload($contextid, $component, $filearea, $itemid, $filepath, $filename, $filecontent,
 149              'user', $USER->id);
 150          $fileinfo = external_api::clean_returnvalue(core_files_external::upload_returns(), $fileinfo);
 151          $browser = get_file_browser();
 152          $file = $browser->get_file_info($context, $component, $filearea, $itemid, $filepath, $filename);
 153          $this->assertNotEmpty($file);
 154      }
 155  
 156      /**
 157       * Test getting a list of files with and without a context ID.
 158       */
 159      public function test_get_files() {
 160          global $USER, $DB;
 161  
 162          $this->resetAfterTest();
 163  
 164          // Set the current user to be the administrator.
 165          $this->setAdminUser();
 166          $USER->email = 'test@example.com';
 167  
 168          // Create a course.
 169          $course = $this->getDataGenerator()->create_course();
 170          $record = new stdClass();
 171          $record->course = $course->id;
 172          $record->name = "Mod data upload test";
 173          $record->intro = "Some intro of some sort";
 174  
 175          // Create a database module.
 176          $module = $this->getDataGenerator()->create_module('data', $record);
 177  
 178          // Create a new field in the database activity.
 179          $field = data_get_field_new('file', $module);
 180          // Add more detail about the field.
 181          $fielddetail = new stdClass();
 182          $fielddetail->d = $module->id;
 183          $fielddetail->mode = 'add';
 184          $fielddetail->type = 'file';
 185          $fielddetail->sesskey = sesskey();
 186          $fielddetail->name = 'Upload file';
 187          $fielddetail->description = 'Some description';
 188          $fielddetail->param3 = '0';
 189  
 190          $field->define_field($fielddetail);
 191          $field->insert_field();
 192          $recordid = data_add_record($module);
 193  
 194          // File information for the database module record.
 195          $datacontent = array();
 196          $datacontent['fieldid'] = $field->field->id;
 197          $datacontent['recordid'] = $recordid;
 198          $datacontent['content'] = 'Simple4.txt';
 199  
 200          // Insert the information about the file.
 201          $contentid = $DB->insert_record('data_content', $datacontent);
 202          // Required information for uploading a file.
 203          $context = context_module::instance($module->cmid);
 204          $usercontext = context_user::instance($USER->id);
 205          $component = 'mod_data';
 206          $filearea = 'content';
 207          $itemid = $contentid;
 208          $filename = $datacontent['content'];
 209          $filecontent = base64_encode("Let us create a nice simple file.");
 210  
 211          $filerecord = array();
 212          $filerecord['contextid'] = $context->id;
 213          $filerecord['component'] = $component;
 214          $filerecord['filearea'] = $filearea;
 215          $filerecord['itemid'] = $itemid;
 216          $filerecord['filepath'] = '/';
 217          $filerecord['filename'] = $filename;
 218  
 219          // Create an area to upload the file.
 220          $fs = get_file_storage();
 221          // Create a file from the string that we made earlier.
 222          $file = $fs->create_file_from_string($filerecord, $filecontent);
 223          $timemodified = $file->get_timemodified();
 224          $timecreated = $file->get_timemodified();
 225          $filesize = $file->get_filesize();
 226  
 227          // Use the web service function to return the information about the file that we just uploaded.
 228          // The first time is with a valid context ID.
 229          $filename = '';
 230          $testfilelisting = core_files_external::get_files($context->id, $component, $filearea, $itemid, '/', $filename);
 231          $testfilelisting = external_api::clean_returnvalue(core_files_external::get_files_returns(), $testfilelisting);
 232  
 233          // With the information that we have provided we should get an object exactly like the one below.
 234          $coursecontext = context_course::instance($course->id);
 235          $testdata = array();
 236          $testdata['parents'] = array();
 237          $testdata['parents']['0'] = array('contextid' => 1,
 238                                            'component' => null,
 239                                            'filearea' => null,
 240                                            'itemid' => null,
 241                                            'filepath' => null,
 242                                            'filename' => 'System');
 243          $testdata['parents']['1'] = array('contextid' => 3,
 244                                            'component' => null,
 245                                            'filearea' => null,
 246                                            'itemid' => null,
 247                                            'filepath' => null,
 248                                            'filename' => 'Miscellaneous');
 249          $testdata['parents']['2'] = array('contextid' => $coursecontext->id,
 250                                            'component' => null,
 251                                            'filearea' => null,
 252                                            'itemid' => null,
 253                                            'filepath' => null,
 254                                            'filename' => 'Test course 1');
 255          $testdata['parents']['3'] = array('contextid' => $context->id,
 256                                            'component' => null,
 257                                            'filearea' => null,
 258                                            'itemid' => null,
 259                                            'filepath' => null,
 260                                            'filename' => 'Mod data upload test (Database)');
 261          $testdata['parents']['4'] = array('contextid' => $context->id,
 262                                            'component' => 'mod_data',
 263                                            'filearea' => 'content',
 264                                            'itemid' => null,
 265                                            'filepath' => null,
 266                                            'filename' => 'Fields');
 267          $testdata['files'] = array();
 268          $testdata['files']['0'] = array('contextid' => $context->id,
 269                                          'component' => 'mod_data',
 270                                          'filearea' => 'content',
 271                                          'itemid' => $itemid,
 272                                          'filepath' => '/',
 273                                          'filename' => 'Simple4.txt',
 274                                          'url' => 'https://www.example.com/moodle/pluginfile.php/'.$context->id.'/mod_data/content/'.$itemid.'/Simple4.txt',
 275                                          'isdir' => false,
 276                                          'timemodified' => $timemodified,
 277                                          'timecreated' => $timecreated,
 278                                          'filesize' => $filesize,
 279                                          'author' => null,
 280                                          'license' => null
 281                                          );
 282          // Make sure that they are the same.
 283          $this->assertEquals($testdata, $testfilelisting);
 284  
 285          // Try again but without the context. Minus one signals the function to use other variables to obtain the context.
 286          $nocontext = -1;
 287          $modified = 0;
 288          // Context level and instance ID are used to determine what the context is.
 289          $contextlevel = 'module';
 290          $instanceid = $module->cmid;
 291          $testfilelisting = core_files_external::get_files($nocontext, $component, $filearea, $itemid, '/', $filename, $modified, $contextlevel, $instanceid);
 292          $testfilelisting = external_api::clean_returnvalue(core_files_external::get_files_returns(), $testfilelisting);
 293  
 294          $this->assertEquals($testfilelisting, $testdata);
 295      }
 296  
 297      /**
 298       * Test delete draft files
 299       */
 300      public function test_delete_draft_files() {
 301          global $USER;
 302  
 303          $this->resetAfterTest();
 304          $this->setAdminUser();
 305  
 306          // Add files to user draft area.
 307          $draftitemid = file_get_unused_draft_itemid();
 308          $context = context_user::instance($USER->id);
 309          $filerecordinline = array(
 310              'contextid' => $context->id,
 311              'component' => 'user',
 312              'filearea'  => 'draft',
 313              'itemid'    => $draftitemid,
 314              'filepath'  => '/',
 315              'filename'  => 'faketxt.txt',
 316          );
 317          $fs = get_file_storage();
 318          $fs->create_file_from_string($filerecordinline, 'fake txt contents 1.');
 319  
 320          // Now create a folder with a file inside.
 321          $fs->create_directory($context->id, 'user', 'draft', $draftitemid, '/fakefolder/');
 322          $filerecordinline['filepath'] = '/fakefolder/';
 323          $filerecordinline['filename'] = 'fakeimage.png';
 324          $fs->create_file_from_string($filerecordinline, 'img...');
 325  
 326          // Check two files were created (one file and one directory).
 327          $files = core_files_external::get_files($context->id, 'user', 'draft', $draftitemid, '/', '');
 328          $files = external_api::clean_returnvalue(core_files_external::get_files_returns(), $files);
 329          $this->assertCount(2, $files['files']);
 330  
 331          // Check the folder has one file.
 332          $files = core_files_external::get_files($context->id, 'user', 'draft', $draftitemid, '/fakefolder/', '');
 333          $files = external_api::clean_returnvalue(core_files_external::get_files_returns(), $files);
 334          $this->assertCount(1, $files['files']);
 335  
 336          // Delete a file and a folder.
 337          $filestodelete = [
 338              ['filepath' => '/', 'filename' => 'faketxt.txt'],
 339              ['filepath' => '/fakefolder/', 'filename' => ''],
 340          ];
 341          $paths = core_files\external\delete\draft::execute($draftitemid, $filestodelete);
 342          $paths = external_api::clean_returnvalue(core_files\external\delete\draft::execute_returns(), $paths);
 343  
 344          // Check everything was deleted.
 345          $files = core_files_external::get_files($context->id, 'user', 'draft', $draftitemid, '/', '');
 346          $files = external_api::clean_returnvalue(core_files_external::get_files_returns(), $files);
 347          $this->assertCount(0, $files['files']);
 348      }
 349  }