diff options
| author | Philipp Schüttlöffel <schuettloeffel@zqs.uni-hannover.de> | 2024-09-24 10:53:31 +0200 |
|---|---|---|
| committer | Philipp Schüttlöffel <schuettloeffel@zqs.uni-hannover.de> | 2024-09-24 10:53:31 +0200 |
| commit | 4459dd7917f4d1c34f40bb68f0e991e9c3d53e4c (patch) | |
| tree | 5c07151ae61276d334e88f6309c30d439a85c12e /lib/filesystem/FileArchiveManager.class.php | |
| parent | da0022e5c1abbf9825ae76debaabdff7e8623bb4 (diff) | |
| parent | 97a188592c679890a25c37ab78463add76a52ff7 (diff) | |
Merge branch 'main' into issue-3911issue-3911
Diffstat (limited to 'lib/filesystem/FileArchiveManager.class.php')
| -rw-r--r-- | lib/filesystem/FileArchiveManager.class.php | 998 |
1 files changed, 0 insertions, 998 deletions
diff --git a/lib/filesystem/FileArchiveManager.class.php b/lib/filesystem/FileArchiveManager.class.php deleted file mode 100644 index 704bb44..0000000 --- a/lib/filesystem/FileArchiveManager.class.php +++ /dev/null @@ -1,998 +0,0 @@ -<?php -/** - * FileArchiveManager.class.php - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * @author Moritz Strohm <strohm@data-quest.de> - * @copyright 2016 data-quest - * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2 - * @category Stud.IP - */ - - -/** - * The FileArchiveManager class gives programmers a simple way to handle - * file archives by providing different methods for packing and unpacking - * file archives in a simple manner. - */ -class FileArchiveManager -{ - - //ARCHIVE HELPER METHODS - - - /** - * Adds a file to an archive using its FileType object. - * - * @param ZipArchive $archive The Zip archive where the FileRef shall be added to. - * @param FileType $file_type The FileType which shall be added to the zip archive. - * @param string $user_id The user who wishes to add the FileRef to the archive. - * @param string $archive_fs_path The path of the file inside the archive's file system. - * @param bool $do_user_permission_checks Set to true if reading/downloading permissions - * shall be checked. False otherwise. Default is true. - * @param bool $ignore_user Set to true, if a file - * which has no download restrictions shall be included - * and the user-specific download condition check shall be ignored. - * If this parameter is set to true, the user_id parameter is irrelevant. - * The default for this parameter is false. - * @return bool True on success, false on failure. - * - * @throws Exception|FileArchiveManagerException If an error occurs a general exception or a more - * special exception is thrown. - */ - public static function addFileTypeToArchive( - ZipArchive $archive, - FileType $file_type, - $user_id = null, - $archive_fs_path = '', - $do_user_permission_checks = true, - $ignore_user = false, - &$file_list = null - ) - { - $archive_max_size = Config::get()->ZIP_DOWNLOAD_MAX_SIZE * 1024 * 1024; - //For FileRef objects we first have to do permission checks - //using the FileRef's folder object. - $adding_allowed = false; - - if ($do_user_permission_checks) { - $folder = $file_type->getFolderType(); - if (!$folder) { - return false; - } - - if ($folder->isReadable($user_id) && $file_type->isDownloadable($user_id)) { - //FileRef is readable and downloadable for the user (identified by $user_id). - $adding_allowed = true; - } - } elseif ($ignore_user) { - //we have to check the download condition by looking at the - //terms of use object of the FileType: - $terms_of_use = $file_type->getTermsOfUse(); - if ($terms_of_use && $terms_of_use->download_condition == 0) { - $adding_allowed = true; - } - } else { - //Totally skip permission checks: - $adding_allowed = true; - } - - if ($adding_allowed) { - //Adding the FileType is allowed: - $file_contains_link = false; - if ($file_type instanceof LibraryFile) { - $file_contains_link = !$file_type->hasFileAttached(); - } else { - $file_contains_link = $file_type instanceof URLFile; - } - - // Increase download counter - if ($file_type instanceof StandardFile) { - $file_ref = $file_type->getFileRef(); - $file_ref->incrementDownloadCounter(); - } - - if ($file_contains_link) { - //The FileType references a link: - //Put the URL into a file ending with .url: - $url = $file_type->getDownloadURL(); - if ($url) { - //The URL has been fetched and we can put it - //in a file in the archive: - $archive->addFromString( - $archive_fs_path . FileManager::cleanFileName($file_type->getFilename()) . '.url', - "[InternetShortcut]\nURL={$url}\n" - ); - //Check the file size of the archive: - if (file_exists($archive->filename) && filesize($archive->filename) > $archive_max_size) { - throw new FileArchiveManagerException( - sprintf( - _('Das ZIP-Archiv ist zu groß! Die maximal erlaubte Größe ist %s!'), - relsize($archive_max_size) - ) - ); - } - if (is_array($file_list)) { - $user = $file_type->getUser(); - $file_list[] = [ - 'name' => FileManager::cleanFileName($file_type->getFilename()), - 'size' => $file_type->getSize(), - 'first_name' => ($user instanceof User) ? $user->vorname : '', - 'last_name' => ($user instanceof User) ? $user->nachname : '', - 'downloads' => $file_type->getDownloads(), - 'mkdate' => date('d.m.Y H:i', $file_type->getMakeDate()), - 'path' => ($archive_fs_path . $file_type->getFilename()) - ]; - } - return true; - } - } else { - if (!($file_type instanceof StandardFile)) { - $file_type = $file_type->convertToStandardFile(); - } - if (!($file_type instanceof StandardFile)) { - //The file type could not be converted to a standard file. - //We cannot continue. - return false; - } - //Get the file's path (if the file exists) and add the file to the archive: - $path = $file_type->getPath(); - if ($path) { - //It is a file in the file system: - if (file_exists($path)) { - $archive->addFile($path, $archive_fs_path . FileManager::cleanFileName($file_type->getFilename())); - //Check the file size of the archive: - if (file_exists($archive->filename) && filesize($archive->filename) > $archive_max_size) { - throw new FileArchiveManagerException( - sprintf( - _('Das ZIP-Archiv ist zu groß! Die maximal erlaubte Größe ist %s!'), - relsize($archive_max_size) - ) - ); - } - //Add the file to the file list (if available): - if (is_array($file_list)) { - $archive_max_num_files = Config::get()->ZIP_DOWNLOAD_MAX_FILES; - $archive_max_size = Config::get()->ZIP_DOWNLOAD_MAX_SIZE * 1024 * 1024; //1048576 bytes = 1 Mebibyte - $user = $file_type->getUser(); - $file_list[] = [ - 'name' => FileManager::cleanFileName($file_type->getFilename()), - 'size' => $file_type->getSize(), - 'first_name' => ($user instanceof User) ? $user->vorname : '', - 'last_name' => ($user instanceof User) ? $user->nachname : '', - 'downloads' => $file_type->getDownloads(), - 'mkdate' => date('d.m.Y H:i', $file_type->getMakeDate()), - 'path' => ($archive_fs_path . FileManager::cleanFileName($file_type->getFilename())) - ]; - if (count($file_list) > $archive_max_num_files) { - $archive->unchangeAll(); - unlink($archive->filename); - throw new FileArchiveManagerException( - sprintf( - _('Das Archiv beinhaltet zu viele Dateibereich-Objekte! Die Obergrenze liegt bei %d Objekten!'), - $archive_max_num_files - ) - ); - } - if (array_sum(array_column($file_list, 'size')) > $archive_max_size) { - $archive->unchangeAll(); - unlink($archive->filename); - throw new FileArchiveManagerException( - sprintf( - _('Das ZIP-Archiv ist zu groß! Die maximal erlaubte Größe ist %s!'), - relsize($archive_max_size) - ) - ); - } - } - } - } - } - } - - //Something must have gone wrong: - return false; - } - - - /** - * Adds a FileRef to a Zip archive. - * This is only a wrapper to addFileTypeToArchive that exists only - * for compatibility reasons. - * - * @see addFileTypeToArchive - */ - public static function addFileRefToArchive( - ZipArchive $archive, - FileRef $file_ref, - $user_id = null, - $archive_fs_path = '', - $do_user_permission_checks = true, - $ignore_user = false, - &$file_list = null - ) - { - $file_type = $file_ref->getFileType(); - if ($file_type instanceof FileType) { - return self::addFileTypeToArchive( - $archive, - $file_type, - $user_id, - $archive_fs_path, - $do_user_permission_checks, - $ignore_user, - $file_list - ); - } - //The file type variable does not contain a FileType object. - return false; - } - - - /** - * Adds a FolderType instance to a Zip archive. - * - * @param ZipArchive $archive The Zip archive where the FileRef shall be added to. - * @param FileRef $file_ref The FileRef which shall be added to the zip archive. - * @param string $user_id The user who wishes to add the FileRef to the archive. - * @param string $archive_fs_path The path of the folder inside the archive's file system. - * @param bool $do_user_permission_checks Set to true if reading/downloading permissions - * shall be checked. False otherwise. Default is true. - * @param bool $keep_hierarchy True, if the folder hierarchy shall be kept. - * False, if the folder hierarchy shall be flattened. - * @param bool $ignore_user Set to true, if a folder - * of type StandardFolder shall be included without checking - * if the user (identified by user_id) can read it. - * @return bool True on success, false on failure. - * - * @throws Exception|FileArchiveManagerException If an error occurs a general exception or a more - * special exception is thrown. - */ - public static function addFolderToArchive( - ZipArchive $archive, - FolderType $folder, - $user_id = null, - $archive_fs_path = '', - $do_user_permission_checks = true, - $keep_hierarchy = true, - $ignore_user = false, - &$file_list = null - ) { - - if ($do_user_permission_checks) { - //Check if the folder is readable for the user (identified by $user_id): - if (!$folder->isReadable($user_id)) { - //Folder is not readable: - return false; - } - } elseif ($ignore_user - && !($folder instanceof StandardFolder) - && in_array($folder->range_type, ['course', 'institute'])) - { - //If user permissions shall be skipped the folder must be - //an instance of StandardFolder and the folder's range type - //must be course or institute since we can only be sure - //that StandardFolder instances in courses or institutes - //are readable by everyone. - return false; - } - - $folder_zip_path = $archive_fs_path; - if ($keep_hierarchy) { - $folder_zip_path .= FileManager::cleanFileName($folder->name); - $archive->addEmptyDir($folder_zip_path); - } - foreach ($folder->getFiles() as $file) { - - /*if (!$file_ref instanceof FileRef) { TODO: OwnCloudPlugin is this ready? - $plugin = PluginManager::getInstance()->getPlugin($folder->range_id); - if (!$plugin) { - $plugin = PluginManager::getInstance()->getPlugin($folder->range_type);; - } - if ($plugin) { - $file_ref = $plugin->getPreparedFile($file_ref->id, true); - } - }*/ - - self::addFileTypeToArchive( - $archive, - $file, - $user_id, - //keep hierarchy in zip file (files and subdirectories) - $keep_hierarchy ? $folder_zip_path . '/' : '', - $do_user_permission_checks, - $ignore_user, - $file_list - ); - } - - foreach ($folder->getSubfolders() as $subfolder) { - self::addFolderToArchive( - $archive, - $subfolder, - $user_id, - //keep hierarchy in zip file (files and subdirectories) - $keep_hierarchy ? $folder_zip_path . '/' : '', - $do_user_permission_checks, - $keep_hierarchy, - $ignore_user, - $file_list - ); - } - - return true; - } - - - //ARCHIVE CREATION METHODS - - - /** - * General method for creating file archives. - * - * This method is a generalisation for all archive creation methods. - * For easier archive creation you may use the other archive creation - * methods which work with less arguments. - * - * @param Array $file_area_objects Array of FileRef, FileURL, Folder or FolderType objects. - * $file_area_objects may contain a mix between those object types. - * @param string $user_id The user who wishes to pack files. - * @param string $archive_file_path The path for the archive file. - * @param bool $do_user_permission_checks Set to true if individual - * reading/downloading permissions shall be checked. False otherwise. - * Default is true. - * @param bool $keep_hierarchy True, if the folder hierarchy shall be kept. - * False, if the folder hierarchy shall be flattened. Default is true. - * @param bool $ignore_user Set to true, if all files - * which have no download restrictions and all folders which are of type - * StandardFolder shall be included and the user-specific - * download condition check shall be ignored. - * If this parameter is set to true, the user_id parameter is irrelevant. - * The default for this parameter is false. - * @param string $zip_encoding encoding for filenames in zip - * @param bool $add_filelist_to_archive If this is set to true a file list - * in the CSV format will be added to the archive. Its name is hardcoded - * to archive_filelist.csv. The default value of $add_filelist_to_archive - * is false which means no file list is added. - * - * @return bool True, if the archive file was created and saved successfully - * at $archive_file_path, false otherwise. - * - * @throws Exception|FileArchiveManagerException If an error occurs a general exception or a more - * special exception is thrown. - */ - public static function createArchive( - $file_area_objects = [], - $user_id = null, - $archive_file_path = '', - $do_user_permission_checks = true, - $keep_hierarchy = true, - $ignore_user = false, - $zip_encoding = 'UTF-8', - $add_filelist_to_archive = false - ) - { - - // check if archive path is set: - if (!$archive_file_path) { - throw new FileArchiveManagerException( - _('Der Zielpfad für das Archiv wurde nicht angegeben!') - ); - } - - // $file_area_objects must be a non-empty array! - // Otherwise we would return an empty Zip archive. - if (!is_array($file_area_objects) || empty($file_area_objects)) { - throw new FileArchiveManagerException( - _('Es wurden keine Dateien ausgewählt!') - ); - } - - // We can create the Zip archive now since its path exists in the file system - // and furthermore there are file area objects available. - $archive = new Studip\ZipArchive(); - if (!$archive->open($archive_file_path, ZipArchive::CREATE | ZipArchive::OVERWRITE)) { - throw new FileArchiveManagerException('Error opening new ZIP archive!'); - } - $archive->setOutputEncoding($zip_encoding); - - //If $file_list is not an array - //then no files are added to the file list. - $file_list = null; - if ($add_filelist_to_archive) { - $file_list = []; - } - - foreach ($file_area_objects as $file_area_object) { - if ($file_area_object instanceof FileRef) { - self::addFileRefToArchive( - $archive, - $file_area_object, - $user_id, - '', - $do_user_permission_checks, - $ignore_user, - $file_list - ); - } elseif ($file_area_object instanceof FileType) { - self::addFileTypeToArchive( - $archive, - $file_area_object, - $user_id, - '', - $do_user_permission_checks, - $ignore_user, - $file_list - ); - } elseif ($file_area_object instanceof Folder || $file_area_object instanceof FolderType) { - $folder = $file_area_object; - if ($folder instanceof Folder) { - //We use FolderType instances here. - $folder = $folder->getTypedFolder(); - } - - self::addFolderToArchive( - $archive, - $folder, - $user_id, - '', - $do_user_permission_checks, - $keep_hierarchy, - $ignore_user, - $file_list - ); - } - } - - if ($archive->numFiles > 0) { - //At least one file is in the archive. - - if ($add_filelist_to_archive) { - //If a file list shall be included in the ZIP archive - //we must now make a CSV file out of file_list: - - $csv_data = array_merge( - [ - [ - _('Name'), - _('Größe'), - _('Vorname'), - _('Nachname'), - _('Downloads'), - _('Datum'), - _('Pfad') - ] - ], - $file_list - ); - - //The CSV file has been generated. - //Now we must add it to the archive: - $archive->addFromString('archive_filelist.csv', array_to_csv($csv_data)); - } - - //Now the ZIP file is really finished: - return $archive->close(); - } - - //empty archive - throw new FileArchiveManagerException( - _('Das ZIP Archiv enthält keine Dateien!') - ); - } - - /** - * Puts files (identified by their file refs) into one file archive. - * - * @param FileRef[] $file_refs Array of FileRef objects. - * @param User $user The user who wishes to pack files. - * @param string $archive_file_path The path for the archive file. - * @param bool $do_user_permission_checks Set to true if reading/downloading - * permissions shall be checked. False otherwise. Default is true. - * - * @return bool True, if the archive file was created and saved successfully - * at $archive_file_path, false otherwise. - * - * @throws Exception|FileArchiveManagerException If an error occurs - * a general exception or a more special exception is thrown. - */ - public static function createArchiveFromFileRefs( - $file_refs, - User $user, - $archive_file_path = '', - $do_user_permission_checks = true - ) - { - if (!$archive_file_path) { - throw new FileArchiveManagerException( - _('Der Zielpfad für das Archiv wurde nicht angegeben!') - ); - } - - //We must now collect all the files from these FileRefs and copy them - //into the new archive file. - - return self::createArchive( - $file_refs, - $user->id, - $archive_file_path, - $do_user_permission_checks, - false //do not keep the file hierarchy - ); - } - - /** - * Returns all children of a folder type. - * - * @param FolderType $folder - * @return array - */ - private static function getFolderChildren(FolderType $folder) - { - $children = []; - foreach ($folder->subfolders as $folder) { - $children[] = $folder; - } - foreach ($folder->file_refs as $ref) { - $children[] = $ref; - } - return $children; - } - - /** - * Creates an archive that contains all files of a course the given user - * is allowed to download. - * - * @param FolderType $folder The folder whose files shall be put inside an archive. - * @param string $user_id The ID of the user who wishes to put the course's files into an archive - * @param string $archive_file_path The path for the archive file. - * @param bool $do_user_permission_checks Set to true if reading/downloading permissions - * shall be checked. False otherwise. Default is true. - * @param bool $keep_hierarchy True, if the file hierarchy shall be kept inside the archive. - * If $keep_hierarchy is set to false you will get an archive that contains only files - * and no subdirectories. - * - * @return bool True, if the archive file was created and saved successfully - * at $archive_file_path, false otherwise. - * - * @throws Exception|FileArchiveManagerException If an error occurs - * a general exception or a more special exception is thrown. - */ - public static function createArchiveFromFolder( - FolderType $folder, - $user_id = null, - $archive_file_path = '', - $do_user_permission_checks = true, - $keep_hierarchy = true - ) - { - return self::createArchive( - self::getFolderChildren($folder), - $user_id, - $archive_file_path, - $do_user_permission_checks, - $keep_hierarchy - ); - } - - /** - * Creates an archive that contains all files of a course the given user - * is allowed to download. - * - * @param string $course_id The ID of the course whose files shall be put inside an archive. - * @param string $user_id The ID of the user who wishes to put the course's files into an archive - * @param string $archive_file_path The path for the archive file. - * @param bool $do_user_permission_checks Set to true if reading/downloading permissions - * shall be checked. False otherwise. Default is true. - * @param bool $keep_hierarchy True, if the file hierarchy shall be kept inside the archive. - * If $keep_hierarchy is set to false you will get an archive that contains only files - * and no subdirectories. - * - * @return bool True, if the archive file was created and saved successfully - * at $archive_file_path, false otherwise. - * - * @throws Exception|FileArchiveManagerException If an error occurs - * a general exception or a more special exception is thrown. - */ - public static function createArchiveFromCourse( - $course_id, - $user_id = null, - $archive_file_path = '', - $do_user_permission_checks = true, - $keep_hierarchy = true - ) - { - $folder = Folder::findTopFolder($course_id); - if (!$folder) { - return null; - } - - $folder = $folder->getTypedFolder(); - if (!$folder) { - return null; - } - - return self::createArchive( - self::getFolderChildren($folder), - $user_id, - $archive_file_path, - $do_user_permission_checks, - $keep_hierarchy - ); - } - - - /** - * Creates an archive that contains all files of an institute the given user - * is allowed to download. - * - * @param string $institute_id The ID of the institute whose files shall be put inside an archive. - * @param string $user_id The ID of the user who wishes to put the institute's files into an archive - * @param string $archive_file_path The path for the archive file. - * @param bool $do_user_permission_checks Set to true if reading/downloading permissions - * shall be checked. False otherwise. Default is true. - * @param bool $keep_hierarchy True, if the file hierarchy shall be kept inside the archive. - * If $keep_hierarchy is set to false you will get an archive that contains only files - * and no subdirectories. - * - * @return bool True, if the archive file was created and saved successfully - * at $archive_file_path, false otherwise. - * - * @throws Exception|FileArchiveManagerException If an error occurs - * a general exception or a more special exception is thrown. - */ - public static function createArchiveFromInstitute( - $institute_id, - $user_id = null, - $archive_file_path = '', - $do_user_permission_checks = true, - $keep_hierarchy = true) - { - $folder = Folder::findTopFolder($institute_id); - if(!$folder) { - return null; - } - - $folder = $folder->getTypedFolder(); - if(!$folder) { - return null; - } - - return self::createArchive( - self::getFolderChildren($folder), - $archive_file_path, - $do_user_permission_checks, - $keep_hierarchy - ); - } - - /** - * Creates an archive that contains all files of a user, if the current - * user has root permissions to do this. - * - * @param string $user_id The ID of the user whose files shall be put inside an archive. - * @param string $archive_file_path The path for the archive file. - * @param bool $do_user_permission_checks Set to true if reading/downloading permissions - * shall be checked. False otherwise. Default is true. - * @param bool $keep_hierarchy True, if the file hierarchy shall be kept inside the archive. - * If $keep_hierarchy is set to false you will get an archive that contains only files - * and no subdirectories. - * - * @return bool True, if the archive file was created and saved successfully - * at $archive_file_path, false otherwise. - * - * @throws Exception|FileArchiveManagerException If an error occurs - * a general exception or a more special exception is thrown. - */ - public static function createArchiveFromUser( - $user_id, - $archive_file_path = '', - $do_user_permission_checks = true, - $keep_hierarchy = true - ) - { - $folder = Folder::findTopFolder($user_id); - if (!$folder) { - return null; - } - - $folder = $folder->getTypedFolder(); - if (!$folder) { - return null; - } - - return self::createArchive( - self::getFolderChildren($folder), - $archive_file_path, - $do_user_permission_checks, - $keep_hierarchy - ); - } - - - /** - * This method creates an archive with the content of a physical folder - * (A folder inside the operating system's file system). - * - * @param string $folder_path The path to the physical folder - * which content shall be added to a file archive. - * @param string $archive_file_path The path to the archive file which - * shall be created. - * - * @return True, if all files were added successfully, false otherwise. - * - * @throws Exception|FileArchiveManagerException If an error occurs - * a general exception or a more special exception is thrown. - */ - public static function createArchiveFromPhysicalFolder($folder_path, $archive_file_path) - { - if (!$folder_path || !$archive_file_path) { - //we can't work with empty paths! - return false; - } - - if (!file_exists($folder_path)) { - //path to physical folder does not exist! - throw new FileArchiveManagerException( - _('Der Ordner wurde im Dateisystem des Servers nicht gefunden!') - ); - } - - //Put all the content of the folder inside an archive: - $archive = Studip\ZipArchive::create($archive_file_path, true); - $result = $archive->addFromPath($folder_path); - $archive->close(); - return $result; - } - - //ARCHIVE EXTRACTION METHODS - - /** - * This is a helper method that builds a subfolder hierarchy inside - * a folder by looking at a string representing a file system path. - * - * The variable $path contains a hierarchy of subfolders that shall be created - * inside the given folder. If $path contains "folder1/folder2/folder3" then - * the given folder will get a subfolder named "folder1". The folder - * "folder1" itself will get a subfolder named "folder2" and so on. - * - * @param FolderType $folder The folder where a subfolder path shall be created. - * @param User $user The user who wishes to create the path. - * @param string $path The path which shall be created inside $folder. - * - * @return FolderType[] An array with FolderType objects representing - * each element of $path. - */ - public static function createFolderPath(FolderType $folder, User $user, $path = '') - { - if (!$path) { - return []; - } - - // now we strip leading and trailing slashes, whitespaces and other characters: - // then we convert path into an array of strings: - $path = trim($path, ' /'); - $path = explode('/', $path); - - //now we loop through path and build subfolders: - $folder_path = []; - - $current_folder = $folder; - foreach ($path as $new_folder_name) { - //first we check if the folder already exists: - foreach ($current_folder->getSubfolders() as $subfolder) { - if ($subfolder->name === $new_folder_name) { - //We have found a folder that has the name $new_folder_name: - //No need to create a new folder, we can use that folder - //and continue with it: - $current_folder = $subfolder; - $folder_path[] = $subfolder; - - //start next iteration of the outer foreach loop: - continue 2; - } - } - - //If code execution has reached this point we have looped - //throug all subfolders of the current folder and couldn't find - //any subfolder that matches the name given in $new_folder_name. - //Therefore we must create a new folder here, if possible: - - //Check the user's permissions first: - if ($current_folder->isSubfolderAllowed($user->id)) { - //Create a subfolder: - $result = FileManager::createSubFolder( - $current_folder, - $user, - get_class($current_folder) === RootFolder::class ? StandardFolder::class : get_class($current_folder), - $new_folder_name - ); - - if ($result instanceof FolderType) { - $folder_path[] = $result; - } - } - } - return $folder_path; - } - - /** - * Extracts one file from an opened archive and stores it in a folder. - * - * @param ZipArchive $archive The archive from which a file shall be extracted. - * @param string $archive_path The path of the file in the archive. - * @param FolderType $target_folder The folder where the file shall be stored. - * @param User $user The user who wishes to extract the file from the archive. - * - * @return FileType|null FileType instance on success, null otherwise. - */ - public static function extractFileFromArchive( - Studip\ZipArchive $archive, - $archive_path, - FolderType $target_folder, - User $user - ) - { - $file_resource = $archive->getStream($archive_path); - $file_info = $archive->statName($archive_path); - - if (!$file_resource) { - return null; - } - - $studip_file = new File(); - $studip_file->user_id = $user->id; - $studip_file->name = $archive->convertArchiveFilename(basename($archive_path)); - $studip_file->mime_type = get_mime_type($studip_file->name); - $studip_file->size = $file_info['size']; - $studip_file->id = $studip_file->getNewId(); - //$file->store(); - - // Ok, we have a file object in the database. Now we must connect - // it with the data file by extracting the data file into - // the place, where the file's content has to be placed. - $file_dir = pathinfo($studip_file->getPath(), PATHINFO_DIRNAME); - $file_path = $file_dir . '/' . $studip_file->id; - - // Create the directory for the file, if necessary: - if (!is_dir($file_dir)) { - mkdir($file_dir); - } - - // Ok, now we read all data from $file_resource and put it into - // the file's path: - if (file_put_contents($file_path, $file_resource) === false) { - //Something went wrong: abort and clean up! - //$file->delete(); - return null; - } - - // Ok, we now must create a File: - $file_ref = new FileRef(); - $file_ref->file_id = $studip_file->id; - $file_ref->folder_id = $target_folder->getId(); - $file_ref->user_id = $user->id; - $file_ref->name = $studip_file->name; - $file_ref->file = $studip_file; - $file = new StandardFile($file_ref); - if ($saved_file = $target_folder->addFile($file, $user->id)) { - return $saved_file; - } - - //Something went wrong: - return null; - } - - /** - * Extracts an archive into a folder inside the Stud.IP file area. - * - * @param FileType $archive_file The archive file which shall be extracted. - * @param FolderType $folder The folder where the archive shall be extracted. - * @param string $user_id The ID of the user who wants to extract the archive. - * - * @return FileType[] Array with extracted files, represented as FileRef objects. - */ - public static function extractArchiveFileToFolder( - FileType $archive_file, - FolderType $folder, - $user_id = null - ) - { - $user = $user_id ? User::find($user_id) : User::findCurrent(); - if (!$user) { - return []; - } - - // Determine, if the folder is writable for the user identified by $user_id: - if (!$folder->isWritable($user->id)) { - return []; - } - - // Determine if we can keep the zip archive's folder hierarchy: - $keep_hierarchy = $folder->isSubfolderAllowed($user->id); - - $archive = new Studip\ZipArchive(); - $standard_archive_file = $archive_file->convertToStandardFile(); - if (!($standard_archive_file instanceof StandardFile)) { - //Error converting the archive file. - return []; - } - $archive->open($standard_archive_file->getPath()); - - // loop over all entries in the zip archive and put each entry - // in the current folder or one of its subfolders: - $files = []; - - for ($i = 0; $i < $archive->numFiles; $i++) { - $entry_info = $archive->statIndex($i); - $entry_info_name = $archive->convertArchiveFilename($entry_info['name']); - // split the entry's path into its path and its name component: - $entry_path = ltrim(pathinfo($entry_info_name, PATHINFO_DIRNAME), '.'); - $entry_name = pathinfo($entry_info_name, PATHINFO_BASENAME); - - // check if $entry_info['name'] ends with a slash: - // In that case it is a directory entry: - $entry_is_directory = preg_match('/\/$/', $entry_info_name); - - //The folder where the extracted file/folder shall be inserted: - $extracted_entry_destination_folder = $folder; - - if ($keep_hierarchy) { - //Keep the archive's folder hierarchy: - //We may have to create subfolders. - if (basename($entry_path)) { - //The file/folder doesn't lie in the "top folder" of the archive: - //Pass the path to createFolderPath and let it generate - //a folder path before extracting the file: - $folder_path = self::createFolderPath( - $folder, - $user, - $entry_path - ); - - //Get the last element of $folder_path: - $last_folder_path_element = array_pop($folder_path); - - //Compare $extracted_entry_destination_folder's name with the name of the - //last path item in $file_archive_path. Only if they are equal - //we can use that folder to store the file. Otherwise - //we must continue with the next file entry in the archive: - if ($last_folder_path_element - && $last_folder_path_element->name === basename($entry_path)) - { - $extracted_entry_destination_folder = $last_folder_path_element; - } - } - } - - if ($entry_is_directory) { - //We have to create a subfolder if it doesn't exist yet: - self::createFolderPath( - $extracted_entry_destination_folder, - $user, - $entry_name - ); - } else { - //we extract one file: - //$entry_info['name'] is necessary because we need the full path - //to the entry inside the archive. - $file = self::extractFileFromArchive( - $archive, - $entry_info['name'], - $extracted_entry_destination_folder, - $user - ); - - if ($file instanceof FileType) { - $files[] = $file; - } - } - } - - return $files; - } -} |
