protected function setUp() { $this->resetAfterTest(); // Create tempfile. $tempfolder = make_request_directory(false); $this->tempfile = $tempfolder . '/' . rand(); touch($this->tempfile); }
protected function setUp() { global $CFG; // Use our special testable fixture plugin. $CFG->antiviruses = 'testable'; $this->resetAfterTest(); // Create tempfile. $tempfolder = make_request_directory(false); $this->tempfile = $tempfolder . '/' . rand(); touch($this->tempfile); }
/** * @dataProvider rewrite_step_backup_file_for_legacy_freeze_provider * @param string $source The source file to test * @param string $expected The expected result of the transformation */ public function test_rewrite_step_backup_file_for_legacy_freeze($source, $expected) { $restore = $this->getMockBuilder('\\restore_gradebook_structure_step')->setMethods(null)->disableOriginalConstructor()->getMock(); // Copy the file somewhere as the rewrite_step_backup_file_for_legacy_freeze will write the file. $dir = make_request_directory(true); $filepath = $dir . DIRECTORY_SEPARATOR . 'file.xml'; copy($source, $filepath); $rc = new \ReflectionClass('\\restore_gradebook_structure_step'); $rcm = $rc->getMethod('rewrite_step_backup_file_for_legacy_freeze'); $rcm->setAccessible(true); $rcm->invoke($restore, $filepath); // Check the result. $this->assertFileEquals($expected, $filepath); }
/** * Tests extracting files returning only a boolean state with failure. */ public function test_extract_to_pathname_returnvalue_failure() { $packer = get_file_packer('application/x-gzip'); // Create sample files. $archivefile = make_request_directory() . DIRECTORY_SEPARATOR . 'test.tgz'; file_put_contents($archivefile, ''); // Extract same files. $outdir = make_request_directory(); $result = $packer->extract_to_pathname($archivefile, $outdir, null, null, true); $this->assertFalse($result); }
public function test_make_request_directory() { // Every request directory should be unique. $firstdir = make_request_directory(); $seconddir = make_request_directory(); $thirddir = make_request_directory(); $fourthdir = make_request_directory(); $this->assertNotEquals($firstdir, $seconddir); $this->assertNotEquals($firstdir, $thirddir); $this->assertNotEquals($firstdir, $fourthdir); $this->assertNotEquals($seconddir, $thirddir); $this->assertNotEquals($seconddir, $fourthdir); $this->assertNotEquals($thirddir, $fourthdir); // They should also all be within the request storage directory. $requestdir = get_request_storage_directory(); $this->assertEquals(0, strpos($firstdir, $requestdir)); $this->assertEquals(0, strpos($seconddir, $requestdir)); $this->assertEquals(0, strpos($thirddir, $requestdir)); $this->assertEquals(0, strpos($fourthdir, $requestdir)); // Removing the requestdir should mean that new request directories are still created successfully. remove_dir($requestdir); $this->assertFalse(file_exists($requestdir)); $this->assertFalse(is_dir($requestdir)); $fifthdir = make_request_directory(); $this->assertNotEquals($firstdir, $fifthdir); $this->assertNotEquals($seconddir, $fifthdir); $this->assertNotEquals($thirddir, $fifthdir); $this->assertNotEquals($fourthdir, $fifthdir); $this->assertTrue(is_dir($fifthdir)); $this->assertFalse(strpos($fifthdir, $requestdir)); // And it should be within the new request directory. $newrequestdir = get_request_storage_directory(); $this->assertEquals(0, strpos($fifthdir, $newrequestdir)); }
/** * @dataProvider usezipbackups_provider */ public function test_extract_to_pathname_returnvalue_failure($usezipbackups) { global $CFG; $this->resetAfterTest(); $packer = get_file_packer('application/vnd.moodle.backup'); // Create 2 archives (each with one file in) in zip mode. $CFG->usezipbackups = $usezipbackups; $mbzfile = make_request_directory() . '/file.mbz'; file_put_contents($mbzfile, 'Content'); $target = make_request_directory(); $result = $packer->extract_to_pathname($mbzfile, $target, null, null, true); $this->assertDebuggingCalledCount(1); $this->assertFalse($result); }
/** * Archive the current plugin on-disk version. * * @param string $folderpath full path to the plugin folder * @param string $component * @param int $version * @param bool $overwrite overwrite existing archive if found * @return bool */ public function archive_plugin_version($folderpath, $component, $version, $overwrite = false) { if ($component !== clean_param($component, PARAM_SAFEDIR)) { // This should never happen, but just in case. throw new moodle_exception('unexpected_plugin_component_format', 'core_plugin', '', null, $component); } if ((string) $version !== clean_param((string) $version, PARAM_FILE)) { // Prevent some nasty injections via $plugin->version tricks. throw new moodle_exception('unexpected_plugin_version_format', 'core_plugin', '', null, $version); } if (empty($component) or empty($version)) { return false; } if (!is_dir($folderpath)) { return false; } $archzip = $this->temproot . '/archive/' . $component . '/' . $version . '.zip'; if (file_exists($archzip) and !$overwrite) { return true; } $tmpzip = make_request_directory() . '/' . $version . '.zip'; $zipped = $this->zip_plugin_folder($folderpath, $tmpzip); if (!$zipped) { return false; } // Assert that the file looks like a valid one. list($expectedtype, $expectedname) = core_component::normalize_component($component); $actualname = $this->get_plugin_zip_root_dir($tmpzip); if ($actualname !== $expectedname) { // This should not happen. throw new moodle_exception('unexpected_archive_structure', 'core_plugin'); } make_writable_directory(dirname($archzip)); return rename($tmpzip, $archzip); }
/** * Fetch the file ocntnet for the ODS. * * @return string */ public function get_file_content() { $dir = make_request_directory(); $filename = $dir . '/result.ods'; $files = ['mimetype' => [$this->get_ods_mimetype()], 'content.xml' => [$this->get_ods_content($this->worksheets)], 'meta.xml' => [$this->get_ods_meta()], 'styles.xml' => [$this->get_ods_styles()], 'settings.xml' => [$this->get_ods_settings()], 'META-INF/manifest.xml' => [$this->get_ods_manifest()]]; $packer = get_file_packer('application/zip'); $packer->archive_to_pathname($files, $filename); $contents = file_get_contents($filename); remove_dir($dir); return $contents; }
* @package mod_folder * @copyright 2015 Andrew Hancox <*****@*****.**> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ require_once __DIR__ . "/../../config.php"; $id = required_param('id', PARAM_INT); // Course module ID. $cm = get_coursemodule_from_id('folder', $id, 0, true, MUST_EXIST); $course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST); require_course_login($course, true, $cm); $context = context_module::instance($cm->id); require_capability('mod/folder:view', $context); $folder = $DB->get_record('folder', array('id' => $cm->instance), '*', MUST_EXIST); $downloadable = folder_archive_available($folder, $cm); if (!$downloadable) { print_error('cannotdownloaddir', 'repository'); } folder_downloaded($folder, $course, $cm, $context); $fs = get_file_storage(); $file = $fs->get_file($context->id, 'mod_folder', 'content', 0, '/', '.'); if (!$file) { print_error('cannotdownloaddir', 'repository'); } $zipper = get_file_packer('application/zip'); $filename = clean_filename($folder->name . "-" . date("Ymd")) . ".zip"; $temppath = make_request_directory() . $filename; if ($zipper->archive_to_pathname(array('/' => $file), $temppath)) { send_temp_file($temppath, $filename); } else { print_error('cannotdownloaddir', 'repository'); }
/** * Get a unique file path in which to save the file. * * The filename returned will be removed at the end of the request and * should not be relied upon to exist in subsequent requests. * * @param string $filename file name * @return file path */ public function prepare_file($filename) { if (empty($filename)) { $filename = 'file'; } return sprintf('%s/%s', make_request_directory(), $filename); }
/** * @depends test_archive_to_storage */ public function test_extract_to_pathname_returnvalue_failure() { global $CFG; $this->resetAfterTest(false); $packer = get_file_packer('application/zip'); $target = make_request_directory(); $archive = "{$CFG->tempdir}/noarchive.zip"; $result = $packer->extract_to_pathname($archive, $target, null, null, true); $this->assertFalse($result); }
/** * Rewrite step definition to handle the legacy freeze attribute. * * In previous backups the calculations_freeze property was stored as an attribute of the * top level node <gradebook>. The backup API, however, do not process grandparent nodes. * It only processes definitive children, and their parent attributes. * * We had: * * <gradebook calculations_freeze="20160511"> * <grade_categories> * <grade_category id="10"> * <depth>1</depth> * ... * </grade_category> * </grade_categories> * ... * </gradebook> * * And this method will convert it to: * * <gradebook > * <attributes> * <calculations_freeze>20160511</calculations_freeze> * </attributes> * <grade_categories> * <grade_category id="10"> * <depth>1</depth> * ... * </grade_category> * </grade_categories> * ... * </gradebook> * * Note that we cannot just load the XML file in memory as it could potentially be huge. * We can also completely ignore if the node <attributes> is already in the backup * file as it never existed before. * * @param string $filepath The absolute path to the XML file. * @return void */ protected function rewrite_step_backup_file_for_legacy_freeze($filepath) { $foundnode = false; $newfile = make_request_directory(true) . DIRECTORY_SEPARATOR . 'file.xml'; $fr = fopen($filepath, 'r'); $fw = fopen($newfile, 'w'); if ($fr && $fw) { while (($line = fgets($fr, 4096)) !== false) { if (!$foundnode && strpos($line, '<gradebook ') === 0) { $foundnode = true; $matches = array(); $pattern = '@calculations_freeze=.([0-9]+).@'; if (preg_match($pattern, $line, $matches)) { $freeze = $matches[1]; $line = preg_replace($pattern, '', $line); $line .= " <attributes>\n <calculations_freeze>{$freeze}</calculations_freeze>\n </attributes>\n"; } } fputs($fw, $line); } if (!feof($fr)) { throw new restore_step_exception('Error while attempting to rewrite the gradebook step file.'); } fclose($fr); fclose($fw); if (!rename($newfile, $filepath)) { throw new restore_step_exception('Error while attempting to rename the gradebook step file.'); } } else { if ($fr) { fclose($fr); } if ($fw) { fclose($fw); } } }
public function test_zip_plugin_folder() { $fixtures = __DIR__ . '/fixtures/update_validator/plugindir'; $storage = make_request_directory(); $codeman = new \core\update\testable_code_manager(); $codeman->zip_plugin_folder($fixtures . '/foobar', $storage . '/foobar.zip'); $this->assertTrue(file_exists($storage . '/foobar.zip')); $fp = get_file_packer('application/zip'); $zipfiles = $fp->list_files($storage . '/foobar.zip'); $this->assertNotEmpty($zipfiles); foreach ($zipfiles as $zipfile) { if ($zipfile->is_directory) { $this->assertTrue(is_dir($fixtures . '/' . $zipfile->pathname)); } else { $this->assertTrue(file_exists($fixtures . '/' . $zipfile->pathname)); } } }
/** * Get a unique file path in which to save the file. * * The filename returned will be removed at the end of the request and * should not be relied upon to exist in subsequent requests. * * @param string $filename file name * @return file path */ public function prepare_file($filename) { return sprintf('%s/%s', make_request_directory(), $filename); }
/** * Detect the given plugin's component name * * Only plugins that declare valid $plugin->component value in the version.php * are supported. * * @param string $zipfilepath full path to the saved ZIP file * @return string|bool declared component name or false if unable to detect */ public function detect_plugin_component($zipfilepath) { $workdir = make_request_directory(); $versionphp = $this->extract_versionphp_file($zipfilepath, $workdir); if (empty($versionphp)) { return false; } return $this->detect_plugin_component_from_versionphp(file_get_contents($workdir . '/' . $versionphp)); }
/** * Perform a file format conversion on the specified document. * * @param stored_file $file the file we want to preview * @param string $format The desired format - e.g. 'pdf'. Formats are specified by file extension. * @return stored_file|bool false if unable to create the conversion, stored file otherwise */ protected function create_converted_document(stored_file $file, $format) { global $CFG; if (empty($CFG->pathtounoconv) || !file_is_executable(trim($CFG->pathtounoconv))) { // No conversions are possible, sorry. return false; } $fileextension = core_text::strtolower(pathinfo($file->get_filename(), PATHINFO_EXTENSION)); if (!self::is_format_supported_by_unoconv($fileextension)) { return false; } if (!self::is_format_supported_by_unoconv($format)) { return false; } // Copy the file to the local tmp dir. $tmp = make_request_directory(); $localfilename = $file->get_filename(); // Safety. $localfilename = clean_param($localfilename, PARAM_FILE); $filename = $tmp . '/' . $localfilename; $file->copy_content_to($filename); $newtmpfile = pathinfo($filename, PATHINFO_FILENAME) . '.' . $format; // Safety. $newtmpfile = $tmp . '/' . clean_param($newtmpfile, PARAM_FILE); $cmd = escapeshellcmd(trim($CFG->pathtounoconv)) . ' ' . escapeshellarg('-f') . ' ' . escapeshellarg($format) . ' ' . escapeshellarg('-o') . ' ' . escapeshellarg($newtmpfile) . ' ' . escapeshellarg($filename); $e = file_exists($filename); $output = null; $currentdir = getcwd(); chdir($tmp); $result = exec($cmd, $output); chdir($currentdir); if (!file_exists($newtmpfile)) { return false; } $context = context_system::instance(); $record = array('contextid' => $context->id, 'component' => 'core', 'filearea' => 'documentconversion', 'itemid' => 0, 'filepath' => '/' . $format . '/', 'filename' => $file->get_contenthash()); return $this->create_file_from_pathname($record, $newtmpfile); }
/** * Perform the installation of plugins. * * If used for installation of remote plugins from the Moodle Plugins * directory, the $plugins must be list of {@link \core\update\remote_info} * object that represent installable remote plugins. The caller can use * {@link self::filter_installable()} to prepare the list. * * If used for installation of plugins from locally available ZIP files, * the $plugins should be list of objects with properties ->component and * ->zipfilepath. * * The method uses {@link mtrace()} to produce direct output and can be * used in both web and cli interfaces. * * @param array $plugins list of plugins * @param bool $confirmed should the files be really deployed into the dirroot? * @param bool $silent perform without output * @return bool true on success */ public function install_plugins(array $plugins, $confirmed, $silent) { global $CFG, $OUTPUT; if (!empty($CFG->disableupdateautodeploy)) { return false; } if (empty($plugins)) { return false; } $ok = get_string('ok', 'core'); // Let admins know they can expect more verbose output. $silent or $this->mtrace(get_string('packagesdebug', 'core_plugin'), PHP_EOL, DEBUG_NORMAL); // Download all ZIP packages if we do not have them yet. $zips = array(); foreach ($plugins as $plugin) { if ($plugin instanceof \core\update\remote_info) { $zips[$plugin->component] = $this->get_remote_plugin_zip($plugin->version->downloadurl, $plugin->version->downloadmd5); $silent or $this->mtrace(get_string('packagesdownloading', 'core_plugin', $plugin->component), ' ... '); $silent or $this->mtrace(PHP_EOL . ' <- ' . $plugin->version->downloadurl, '', DEBUG_DEVELOPER); $silent or $this->mtrace(PHP_EOL . ' -> ' . $zips[$plugin->component], ' ... ', DEBUG_DEVELOPER); if (!$zips[$plugin->component]) { $silent or $this->mtrace(get_string('error')); return false; } $silent or $this->mtrace($ok); } else { if (empty($plugin->zipfilepath)) { throw new coding_exception('Unexpected data structure provided'); } $zips[$plugin->component] = $plugin->zipfilepath; $silent or $this->mtrace('ZIP ' . $plugin->zipfilepath, PHP_EOL, DEBUG_DEVELOPER); } } // Validate all downloaded packages. foreach ($plugins as $plugin) { $zipfile = $zips[$plugin->component]; $silent or $this->mtrace(get_string('packagesvalidating', 'core_plugin', $plugin->component), ' ... '); list($plugintype, $pluginname) = core_component::normalize_component($plugin->component); $tmp = make_request_directory(); $zipcontents = $this->unzip_plugin_file($zipfile, $tmp, $pluginname); if (empty($zipcontents)) { $silent or $this->mtrace(get_string('error')); $silent or $this->mtrace('Unable to unzip ' . $zipfile, PHP_EOL, DEBUG_DEVELOPER); return false; } $validator = \core\update\validator::instance($tmp, $zipcontents); $validator->assert_plugin_type($plugintype); $validator->assert_moodle_version($CFG->version); // TODO Check for missing dependencies during validation. $result = $validator->execute(); if (!$silent) { $result ? $this->mtrace($ok) : $this->mtrace(get_string('error')); foreach ($validator->get_messages() as $message) { if ($message->level === $validator::INFO) { // Display [OK] validation messages only if debugging mode is DEBUG_NORMAL. $level = DEBUG_NORMAL; } else { if ($message->level === $validator::DEBUG) { // Display [Debug] validation messages only if debugging mode is DEBUG_ALL. $level = DEBUG_ALL; } else { // Display [Warning] and [Error] always. $level = null; } } if ($message->level === $validator::WARNING and !CLI_SCRIPT) { $this->mtrace(' <strong>[' . $validator->message_level_name($message->level) . ']</strong>', ' ', $level); } else { $this->mtrace(' [' . $validator->message_level_name($message->level) . ']', ' ', $level); } $this->mtrace($validator->message_code_name($message->msgcode), ' ', $level); $info = $validator->message_code_info($message->msgcode, $message->addinfo); if ($info) { $this->mtrace('[' . s($info) . ']', ' ', $level); } else { if (is_string($message->addinfo)) { $this->mtrace('[' . s($message->addinfo, true) . ']', ' ', $level); } else { $this->mtrace('[' . s(json_encode($message->addinfo, true)) . ']', ' ', $level); } } if ($icon = $validator->message_help_icon($message->msgcode)) { if (CLI_SCRIPT) { $this->mtrace(PHP_EOL . ' ^^^ ' . get_string('help') . ': ' . get_string($icon->identifier . '_help', $icon->component), '', $level); } else { $this->mtrace($OUTPUT->render($icon), ' ', $level); } } $this->mtrace(PHP_EOL, '', $level); } } if (!$result) { $silent or $this->mtrace(get_string('packagesvalidatingfailed', 'core_plugin')); return false; } } $silent or $this->mtrace(PHP_EOL . get_string('packagesvalidatingok', 'core_plugin')); if (!$confirmed) { return true; } // Extract all ZIP packs do the dirroot. foreach ($plugins as $plugin) { $silent or $this->mtrace(get_string('packagesextracting', 'core_plugin', $plugin->component), ' ... '); $zipfile = $zips[$plugin->component]; list($plugintype, $pluginname) = core_component::normalize_component($plugin->component); $target = $this->get_plugintype_root($plugintype); if (file_exists($target . '/' . $pluginname)) { $this->remove_plugin_folder($this->get_plugin_info($plugin->component)); } if (!$this->unzip_plugin_file($zipfile, $target, $pluginname)) { $silent or $this->mtrace(get_string('error')); $silent or $this->mtrace('Unable to unzip ' . $zipfile, PHP_EOL, DEBUG_DEVELOPER); if (function_exists('opcache_reset')) { opcache_reset(); } return false; } $silent or $this->mtrace($ok); } if (function_exists('opcache_reset')) { opcache_reset(); } return true; }
/** * Output file headers to initialise the download of the file. */ public function send_http_headers() { $this->writer = \Box\Spout\Writer\WriterFactory::create($this->spouttype); if (method_exists($this->writer, 'setTempFolder')) { $this->writer->setTempFolder(make_request_directory()); } $filename = $this->filename . $this->get_extension(); $this->writer->openToBrowser($filename); if ($this->sheettitle && $this->writer instanceof \Box\Spout\Writer\AbstractMultiSheetsWriter) { $sheet = $this->writer->getCurrentSheet(); $sheet->setName($this->sheettitle); } }