/** * Unzip file to given file path (real OS filesystem), existing files are overwritten. * * @todo MDL-31048 localise messages * @param string|stored_file $archivefile full pathname of zip file or stored_file instance * @param int $contextid context ID * @param string $component component * @param string $filearea file area * @param int $itemid item ID * @param string $pathbase file path * @param int $userid user ID * @param file_progress $progress Progress indicator callback or null if not required * @return array|bool list of processed files; false if error */ public function extract_to_storage($archivefile, $contextid, $component, $filearea, $itemid, $pathbase, $userid = NULL, file_progress $progress = null) { global $CFG; if (!is_string($archivefile)) { return $archivefile->extract_to_storage($this, $contextid, $component, $filearea, $itemid, $pathbase, $userid, $progress); } check_dir_exists($CFG->tempdir . '/zip'); $pathbase = trim($pathbase, '/'); $pathbase = $pathbase === '' ? '/' : '/' . $pathbase . '/'; $fs = get_file_storage(); $processed = array(); $ziparch = new zip_archive(); if (!$ziparch->open($archivefile, file_archive::OPEN)) { return false; } // Get the number of files (approx). if ($progress) { $approxmax = $ziparch->estimated_count(); $done = 0; } foreach ($ziparch as $info) { // Notify progress. if ($progress) { $progress->progress($done, $approxmax); $done++; } $size = $info->size; $name = $info->pathname; if ($name === '' or array_key_exists($name, $processed)) { //probably filename collisions caused by filename cleaning/conversion continue; } if ($info->is_directory) { $newfilepath = $pathbase . $name . '/'; $fs->create_directory($contextid, $component, $filearea, $itemid, $newfilepath, $userid); $processed[$name] = true; continue; } $parts = explode('/', trim($name, '/')); $filename = array_pop($parts); $filepath = $pathbase; if ($parts) { $filepath .= implode('/', $parts) . '/'; } if ($size < 2097151) { // Small file. if (!($fz = $ziparch->get_stream($info->index))) { $processed[$name] = 'Can not read file from zip archive'; // TODO: localise continue; } $content = ''; while (!feof($fz)) { $content .= fread($fz, 262143); } fclose($fz); if (strlen($content) !== $size) { $processed[$name] = 'Unknown error during zip extraction'; // TODO: localise // something went wrong :-( unset($content); continue; } if ($file = $fs->get_file($contextid, $component, $filearea, $itemid, $filepath, $filename)) { if (!$file->delete()) { $processed[$name] = 'Can not delete existing file'; // TODO: localise continue; } } $file_record = new stdClass(); $file_record->contextid = $contextid; $file_record->component = $component; $file_record->filearea = $filearea; $file_record->itemid = $itemid; $file_record->filepath = $filepath; $file_record->filename = $filename; $file_record->userid = $userid; if ($fs->create_file_from_string($file_record, $content)) { $processed[$name] = true; } else { $processed[$name] = 'Unknown error during zip extraction'; // TODO: localise } unset($content); continue; } else { // large file, would not fit into memory :-( $tmpfile = tempnam($CFG->tempdir . '/zip', 'unzip'); if (!($fp = fopen($tmpfile, 'wb'))) { @unlink($tmpfile); $processed[$name] = 'Can not write temp file'; // TODO: localise continue; } if (!($fz = $ziparch->get_stream($info->index))) { @unlink($tmpfile); $processed[$name] = 'Can not read file from zip archive'; // TODO: localise continue; } while (!feof($fz)) { $content = fread($fz, 262143); fwrite($fp, $content); } fclose($fz); fclose($fp); if (filesize($tmpfile) !== $size) { $processed[$name] = 'Unknown error during zip extraction'; // TODO: localise // something went wrong :-( @unlink($tmpfile); continue; } if ($file = $fs->get_file($contextid, $component, $filearea, $itemid, $filepath, $filename)) { if (!$file->delete()) { @unlink($tmpfile); $processed[$name] = 'Can not delete existing file'; // TODO: localise continue; } } $file_record = new stdClass(); $file_record->contextid = $contextid; $file_record->component = $component; $file_record->filearea = $filearea; $file_record->itemid = $itemid; $file_record->filepath = $filepath; $file_record->filename = $filename; $file_record->userid = $userid; if ($fs->create_file_from_pathname($file_record, $tmpfile)) { $processed[$name] = true; } else { $processed[$name] = 'Unknown error during zip extraction'; // TODO: localise } @unlink($tmpfile); continue; } } $ziparch->close(); return $processed; }