From 7303302c322e105b5095bf412e8d154971088282 Mon Sep 17 00:00:00 2001 From: Khaled Lela Date: Wed, 23 Feb 2022 16:13:24 +0200 Subject: handle read scorm archive from uri, in case have two differet storage for package archive and unzipped package for serve. --- src/Manager/ScormDisk.php | 90 ++++++++++++++++++++++++++------------------ src/Manager/ScormManager.php | 74 ++++++++++++++++++++---------------- 2 files changed, 96 insertions(+), 68 deletions(-) (limited to 'src/Manager') diff --git a/src/Manager/ScormDisk.php b/src/Manager/ScormDisk.php index 9417ef3..cb09db5 100644 --- a/src/Manager/ScormDisk.php +++ b/src/Manager/ScormDisk.php @@ -3,59 +3,56 @@ namespace Peopleaps\Scorm\Manager; use Illuminate\Filesystem\FilesystemAdapter; +use Illuminate\Http\UploadedFile; use Illuminate\Support\Facades\Storage; -use Peopleaps\Scorm\Entity\Scorm; use Peopleaps\Scorm\Exception\StorageNotFoundException; -use ZipArchive; -use ZipStream\ZipStream; class ScormDisk { /** * Extract zip file into destination directory. * - * @param string $path Destination directory - * @param string $zipFilePath The path to the zip file. + * @param UploadedFile|string $file zip source + * @param string $path The path to the destination. * - * @return bool True on success, false on failure. + * @return bool true on success, false on failure. */ - public function unzip($file, $path) + function unzipper($file, $target_dir) { - $path = $this->cleanPath($path); - - $zipArchive = new ZipArchive(); - if ($zipArchive->open($file) !== true) { - return false; - } - - /** @var FilesystemAdapter $disk */ - $disk = $this->getDisk(); - - for ($i = 0; $i < $zipArchive->numFiles; ++$i) { - $zipEntryName = $zipArchive->getNameIndex($i); - $destination = $path . DIRECTORY_SEPARATOR . $this->cleanPath($zipEntryName); - if ($this->isDirectory($zipEntryName)) { - $disk->createDir($destination); - continue; + $target_dir = $this->cleanPath($target_dir); + $unzipper = resolve(\ZipArchive::class); + if ($unzipper->open($file)) { + /** @var FilesystemAdapter $disk */ + $disk = $this->getDisk(); + for ($i = 0; $i < $unzipper->numFiles; ++$i) { + $zipEntryName = $unzipper->getNameIndex($i); + $destination = $this->join($target_dir, $this->cleanPath($zipEntryName)); + if ($this->isDirectory($zipEntryName)) { + $disk->createDir($destination); + continue; + } + $disk->putStream($destination, $unzipper->getStream($zipEntryName)); } - $disk->putStream($destination, $zipArchive->getStream($zipEntryName)); + return true; } - return true; + return false; } - public function download(Scorm $scorm) + /** + * @param string $file SCORM archive uri on storage. + * @param callable $fn function run user stuff before unlink + */ + public function readScormArchive($file, callable $fn) { - return response()->stream(function () use ($scorm) { - // enable output of HTTP headers - // $options = new ZipStream\Option\Archive(); - // $options->setSendHttpHeaders(true); - $zip = new ZipStream($scorm->title . ".zip"); - /** @var FilesystemAdapter $disk */ - $disk = $this->getDisk(); - $zip->addFileFromStream($scorm->title, $disk->readStream($scorm->uuid)); - $zip->finish(); - }); + if (Storage::exists($file)) { + Storage::delete($file); + } + Storage::writeStream($file, $this->getArchiveDisk()->readStream($file)); + $path = Storage::path($file); + call_user_func($fn, $path); + unlink($path); // delete temp package + Storage::deleteDirectory(dirname($file)); // delete temp dir } /** @@ -67,6 +64,16 @@ class ScormDisk return $this->getDisk()->deleteDirectory($folderHashedName); } + /** + * + * @param array $paths + * @return string joined path + */ + private function join(...$paths) + { + return implode(DIRECTORY_SEPARATOR, $paths); + } + private function isDirectory($zipEntryName) { return substr($zipEntryName, -1) === '/'; @@ -87,4 +94,15 @@ class ScormDisk } return Storage::disk(config('scorm.disk')); } + + /** + * @return FilesystemAdapter $disk + */ + private function getArchiveDisk() + { + if (!config()->has('filesystems.disks.' . config('scorm.archive'))) { + throw new StorageNotFoundException('scorm_archive_disk_not_define'); + } + return Storage::disk(config('scorm.archive')); + } } diff --git a/src/Manager/ScormManager.php b/src/Manager/ScormManager.php index aedfae3..9de1439 100644 --- a/src/Manager/ScormManager.php +++ b/src/Manager/ScormManager.php @@ -17,7 +17,6 @@ use Peopleaps\Scorm\Model\ScormScoModel; use Peopleaps\Scorm\Model\ScormScoTrackingModel; use Illuminate\Support\Str; use Peopleaps\Scorm\Entity\Sco; -use ZipArchive; class ScormManager { @@ -38,28 +37,53 @@ class ScormManager $this->scormDisk = new ScormDisk(); } + public function uploadScormFromUri($file) + { + $scorm = null; + $this->scormDisk->readScormArchive($file, function ($path) use (&$scorm, $file) { + $this->validatePackage($path); + $uuid = dirname($file); + $filename = basename($file); + $scorm = $this->saveScorm($path, $uuid, $filename); + }); + return $scorm; + } + public function uploadScormArchive(UploadedFile $file) { - // Checks if it is a valid scorm archive - $scormData = null; - $zip = new ZipArchive(); - $openValue = $zip->open($file); + $this->validatePackage($file); + return $this->saveScorm($file, Str::uuid(), $file->getClientOriginalName()); + } + /** + * Checks if it is a valid scorm archive + * + * @param string|UploadedFile $file zip. + */ + private function validatePackage($file) + { + $zip = new \ZipArchive(); + $openValue = $zip->open($file); $isScormArchive = (true === $openValue) && $zip->getStream('imsmanifest.xml'); $zip->close(); - if (!$isScormArchive) { throw new InvalidScormArchiveException('invalid_scorm_archive_message'); - } else { - $scormData = $this->generateScorm($file); } + } + /** + * Save scom data + * + * @param string|UploadedFile $file zip. + */ + private function saveScorm($file, $uuid, $filename) + { + $scormData = $this->generateScorm($file, $uuid); // save to db if (is_null($scormData) || !is_array($scormData)) { throw new InvalidScormArchiveException('invalid_scorm_data'); } - /** * ScormModel::whereOriginFile Query Builder style equals ScormModel::where('origin_file',$value) * @@ -70,18 +94,7 @@ class ScormManager * Examples: * * $admin = DB::table('users')->whereId(1)->first(); - * - * $john = DB::table('users') - * ->whereIdAndEmail(2, 'john@doe.com') - * ->first(); - * - * $jane = DB::table('users') - * ->whereNameOrAge('Jane', 22) - * ->first(); - * - * * From laravel framework https://github.com/laravel/framework/blob/9.x/src/Illuminate/Database/Query/Builder.php' - * * Handle dynamic method calls into the method. * return $this->dynamicWhere($method, $parameters); **/ @@ -93,12 +106,12 @@ class ScormManager $scorm = $scorm->first(); $this->deleteScormData($scorm); } - $scorm->uuid = $scormData['uuid']; $scorm->title = $scormData['title']; $scorm->version = $scormData['version']; $scorm->entry_url = $scormData['entryUrl']; - $scorm->origin_file = $scormData['identifier']; + $scorm->identifier = $scormData['identifier']; + $scorm->origin_file = $filename; $scorm->save(); if (!empty($scormData['scos']) && is_array($scormData['scos'])) { @@ -145,7 +158,10 @@ class ScormManager return $sco; } - private function parseScormArchive(UploadedFile $file) + /** + * @param string|UploadedFile $file zip. + */ + private function parseScormArchive($file) { $data = []; $contents = ''; @@ -238,20 +254,19 @@ class ScormManager } /** - * @param UploadedFile $file + * @param string|UploadedFile $file zip. * @return array * @throws InvalidScormArchiveException */ - private function generateScorm(UploadedFile $file) + private function generateScorm($file, $uuid) { - $uuid = Str::uuid(); $scormData = $this->parseScormArchive($file); /** * Unzip a given ZIP file into the web resources directory. * * @param string $hashName name of the destination directory */ - $this->scormDisk->unzip($file, $uuid); + $this->scormDisk->unzipper($file, $uuid); return [ 'identifier' => $scormData['identifier'], @@ -667,9 +682,4 @@ class ScormManager return $formattedValue; } - - - public function download(Scorm $scorm){ - return $this->scormDisk->download($scorm); - } } -- cgit v1.2.3