where('created_by', Auth::id()) // ensure matching user for access ->where('path', $folder) // ensure that the specified folder exists in the database ->firstOrFail(); // if none found, fail } else { // use root folder if $folder not passed in $folder = $this->getRoot(); } // get all files and folders created by current user $files = File::query()->where('created_by', Auth::id()) // that have not been deleted ->whereNull('deleted_at') // order by folders first ->orderByDesc('is_folder') // then order by creation date ->orderByDesc('created_at'); $search = $request->get('search'); if ($search) { $files->where('name', 'like', '%' . $search . '%'); } else { // return all files filtered by parent_id $files->where('parent_id', $folder->id); } $files = $files->get(); $files = FileResource::collection($files); $ancestors = FileResource::collection([...$folder->ancestors, $folder]); $folder = new FileResource($folder); return Inertia::render('UserFiles', compact('files', 'folder', 'ancestors')); } // render files shared with user public function sharedWithMe(Request $request, $folder = null) { // validate passed in $folder param if ($folder) { // get ancestors $firstQuery = File::query()->join('file_shares', 'file_shares.file_id', 'files.id') ->where('file_shares.user_id', Auth::id()) ->whereNull('files.deleted_at') ->find(intval($folder)); // ensure that the specified id exists in the database if ($firstQuery) { $ancestors = $firstQuery->ancestors; } // folder found in the shares db $folder = File::query()->join('file_shares', 'file_shares.file_id', 'files.id') ->where('file_shares.user_id', Auth::id()) ->whereNull('files.deleted_at') ->select('files.id as id', 'name', 'size', 'created_by', 'file_shares.created_at as created_at', 'file_shares.updated_at as updated_at', 'parent_id') ->find(intval($folder)); // ensure that the specified id exists in the database } // if still exists, if ($folder) { // files are those found in the shares db $files = File::query()->join('file_shares', 'file_shares.file_id', 'files.id') // that are shared with the current user ->where('file_shares.user_id', Auth::id()) // that have not been deleted ->whereNull('files.deleted_at') // order by folders first ->orderByDesc('files.is_folder') // then order by creation date ->orderByDesc('files.id') // then select to reference file_id ->select('files.id as id', 'name', 'size', 'created_by', 'file_shares.created_at as created_at', 'file_shares.updated_at as updated_at', 'mimetype', 'is_folder', 'parent_id'); $search = $request->get('search'); if ($search) { $files->where('name', 'like', '%' . $search . '%'); } else { // return all files filtered by $folder $files->where('parent_id', $folder->id); } $files = $files->get(); $files = FileResource::collection($files); // ancestors $ancestors = FileResource::collection($ancestors); $folder = new FileResource($folder); // pass everything into SharedWith return Inertia::render('SharedWith', compact('files', 'folder', 'ancestors')); } else { // no folder // files are those found in the shares db $files = File::query()->join('file_shares', 'file_shares.file_id', 'files.id') // that are shared with the current user ->where('file_shares.user_id', Auth::id()) // that have not been deleted ->whereNull('files.deleted_at') // order by folders first ->orderByDesc('files.is_folder') // then order by creation date ->orderByDesc('files.id') ->select('files.id as id', 'name', 'size', 'created_by', 'file_shares.created_at as created_at', 'file_shares.updated_at as updated_at', 'mimetype', 'is_folder', 'parent_id'); $search = $request->get('search'); if ($search) { $files->where('name', 'like', '%' . $search . '%'); } $files = $files->get(); // make into collection $files = FileResource::collection($files); $allIds = array(); // get $parentIds of each file foreach($files as $file) { array_push($allIds, intval($file->id)); } // run through and filter the $files array to not have any files which are children of the displayed files foreach($files as $key => $value) { foreach($allIds as $allId) { if ($value->parent_id == $allId) { unset($files[$key]); } } } // pass only files into SharedWith return Inertia::render('SharedWith', compact('files')); } } // render files shared by user public function sharedByMe(Request $request, $folder = null) { // validate passed in $folder param if ($folder) { // run a query just for ancestors $firstQuery = File::query()->join('file_shares', 'file_shares.file_id', 'files.id') ->where('files.created_by', Auth::id()) ->whereNull('files.deleted_at') ->find(intval($folder)); // ensure that the specified id exists in the database if ($firstQuery) { $ancestors = $firstQuery->ancestors; } // folder found in the shares db $folder = File::query()->join('file_shares', 'file_shares.file_id', 'files.id') ->where('files.created_by', Auth::id()) ->whereNull('files.deleted_at') ->select('files.id as id', 'name', 'size', 'created_by', 'file_shares.created_at as created_at', 'file_shares.updated_at as updated_at', 'parent_id') ->find(intval($folder)); // ensure that the specified id exists in the database } // if still exists, if ($folder) { // files are those found in the shares db $files = File::query()->join('file_shares', 'file_shares.file_id', 'files.id') // that are made by the current user ->where('files.created_by', Auth::id()) // that have not been deleted ->whereNull('files.deleted_at') // order by folders first ->orderByDesc('files.is_folder') // then order by creation date ->orderByDesc('files.id') // then select to reference file_id ->select('files.id as id', 'name', 'size', 'created_by', 'file_shares.created_at as created_at', 'file_shares.updated_at as updated_at', 'mimetype', 'is_folder', 'parent_id', 'file_shares.user_id as user_id'); $search = $request->get('search'); if ($search) { $files->where('name', 'like', '%' . $search . '%'); } else { // return all files filtered by $folder $files->where('parent_id', $folder->id); } $files = $files->get(); $files = FileResource::collection($files); // get shared_with name for each file foreach($files as $file) { $user = User::query()->where('id', $file->user_id)->first(); $file->shared_with = $user->name; } // ancestors $ancestors = FileResource::collection($ancestors); $folder = new FileResource($folder); // pass everything into SharedBy return Inertia::render('SharedBy', compact('files', 'folder', 'ancestors')); } else { // no folder // files are those found in the shares db $files = File::query()->join('file_shares', 'file_shares.file_id', 'files.id') // that are made by the current user ->where('files.created_by', Auth::id()) // that have not been deleted ->whereNull('files.deleted_at') // order by folders first ->orderByDesc('files.is_folder') // then order by creation date ->orderByDesc('files.id') ->select('files.id as id', 'name', 'size', 'created_by', 'file_shares.created_at as created_at', 'file_shares.updated_at as updated_at', 'mimetype', 'is_folder', 'parent_id', 'file_shares.user_id as user_id'); $search = $request->get('search'); if ($search) { $files->where('name', 'like', '%' . $search . '%'); } $files = $files->get(); // get shared_with name for each file foreach($files as $file) { $user = User::query()->where('id', $file->user_id)->first(); $file->shared_with = $user->name; } // make into collection $files = FileResource::collection($files); $allIds = array(); // get $parentIds of each file foreach($files as $file) { array_push($allIds, intval($file->id)); } // run through and filter the $files array to not have any files which are children of the displayed files foreach($files as $key => $value) { foreach($allIds as $allId) { if ($value->parent_id == $allId) { unset($files[$key]); } } } // pass only files into SharedBy return Inertia::render('SharedBy', compact('files')); } } // render recycle bin public function recycleBin(Request $request, $folder = null) { // validate passed in $folder param if ($folder) { // find folder $folder = File::onlyTrashed() // made by current user ->where('created_by', Auth::id()) ->find(intval($folder)); } // if still exists, if ($folder) { // files are those that are trashed $files = File::onlyTrashed() // made by current user ->where('created_by', Auth::id()) ->orderBy('is_folder', 'desc') ->orderBy('deleted_at', 'desc') ->orderBy('files.id', 'desc'); $search = $request->get('search'); if ($search) { $files->where('name', 'like', '%' . $search . '%'); } else { // return all files filtered by $folder $files->where('parent_id', $folder->id); } $files = $files->get(); $files = FileResource::collection($files); function recursiveAncestors($file, &$ancestors) { $parentFile = File::onlyTrashed() ->where('created_by', Auth::id()) ->find($file->parent_id); if ($parentFile) { array_unshift($ancestors, $parentFile); if ($parentFile->parent_id) { recursiveAncestors($parentFile, $ancestors); } } } $ancestors = []; recursiveAncestors($folder, $ancestors); // ancestors $ancestors = FileResource::collection([...$ancestors, $folder]); $folder = new FileResource($folder); // pass everything into RecycleBin return Inertia::render('RecycleBin', compact('files', 'folder', 'ancestors')); } else { // no folder // files are those that are trashed $files = File::onlyTrashed() // made by current user ->where('created_by', Auth::id()) ->orderBy('is_folder', 'desc') ->orderBy('deleted_at', 'desc') ->orderBy('files.id', 'desc'); $search = $request->get('search'); if ($search) { $files->where('name', 'like', '%' . $search . '%'); } $files = $files->get(); // make into collection $files = FileResource::collection($files); $allIds = array(); // get $parentIds of each file foreach($files as $file) { array_push($allIds, intval($file->id)); } // run through and filter the $files array to not have any files which are children of the displayed files foreach($files as $key => $value) { foreach($allIds as $allId) { if ($value->parent_id == $allId) { unset($files[$key]); } } } // pass only files into SharedBy return Inertia::render('RecycleBin', compact('files')); } } // create new folder based on passed in NewFolder request public function newFolder(NewFolder $request) { // get validated data $data = $request->validated(); // get parent folder from NewFolder request $parent = $request->parent; // make new folder object based on File() object $folder = new File(); $folder->is_folder = 1; $folder->name = $data['name']; $parent->appendNode($folder); } // upload files public function upload(UploadFiles $request) { // get validated data $data = $request->validated(); // get parent folder from UploadFiles request $parent = $request->parent; // get file tree structure from UploadFiles request $tree = $request->file_tree; // if the tree is empty, then files were uploaded without any folder structure - each file needs to be uploaded // otherwise, the entire folder structure needs to be uploaded empty($tree) ? $this->uploadFiles($data['files'], $parent) : $this->uploadTree($tree, $parent); } // get download link for selected files public function download(SelectedFiles $request) { $data = $request->validated(); // get parent folder from DeleteFiles request $parent = $request->parent; // get selected Id's otherwise empty array $Ids = $data['Ids'] ?? []; // if no files selected if (!$data['all'] == false && empty($Ids)) { return [ 'message' => 'No files selected!' ]; } // if all selected, download all if ($data['all']) { $downloadURL = $this->makeArchive($parent->children); // make filename for file $filename = $parent->name . ".zip"; } // else download the selected IDs else { // if there is only one ID selected if (count($Ids) === 1) { // get file $file = File::find($Ids[0]); // if file is a folder if ($file->is_folder) { // and folder is empty if($file->children->isEmpty()) { // return message return [ "message" => "This folder is empty" ]; } // else folder is populated $files = $file->children; $downloadURL = $this->makeArchive($files); $filename = $file->name . ".zip"; } // otherwise else { // create a new path $path = pathinfo($file->stored_at, PATHINFO_BASENAME); // if file has been uploaded to S3, if ($file->s3 == 1) { // pull the file off S3 $s3file = Storage::get($file->stored_at); // put it on the public drive for use Storage::disk('public')->put($path, $s3file); } else { // modify path $path = 'public/' . $path; // get local file $localFile = Storage::disk('local')->get($file->stored_at); // put it on the public drive for use Storage::disk('public')->put($path, $localFile); } // define download path as being the file on the public drive $downloadURL = asset(Storage::disk('public')->url($path)); // define filename $filename = $file->name; } } // otherwise there are many IDs selected else { $files = File::query()->whereIn('id', $Ids)->get(); $downloadURL = $this->makeArchive($files); $filename = $parent->name . ".zip"; } } // return URL and filename return [ 'url' => $downloadURL, 'filename' => $filename, ]; } // get download link for files that are shared with user public function downloadSharedWith(SharedFiles $request) { $data = $request->validated(); // get parent folder from DeleteFiles request $parent = $request->parent; // get selected Id's otherwise empty array $Ids = $data['Ids'] ?? []; // if no files selected if (!$data['all'] == false && empty($Ids)) { return [ 'message' => 'No files selected!' ]; } if ($parent) { // if all selected, download all if ($data['all']) { $downloadURL = $this->makeArchive($parent->children); // make filename for file $filename = $parent->name . ".zip"; } // else download the selected IDs else { // if there is only one ID selected if (count($Ids) === 1) { // get file $file = File::find($Ids[0]); // if file is a folder if ($file->is_folder) { // and folder is empty if ($file->children->isEmpty()) { // return message return [ "message" => "This folder is empty" ]; } // else folder is populated $files = $file->children; $downloadURL = $this->makeArchive($files); $filename = $file->name . ".zip"; } // otherwise else { // create a new path $path = pathinfo($file->stored_at, PATHINFO_BASENAME); // if file has been uploaded to S3, if ($file->s3 == 1) { // pull the file off S3 $s3file = Storage::get($file->stored_at); // put it on the public drive for use Storage::disk('public')->put($path, $s3file); } else { // modify path $path = 'public/' . $path; // get local file $localFile = Storage::disk('local')->get($file->stored_at); // put it on the public drive for use Storage::disk('public')->put($path, $localFile); } // define download path as being the file on the public drive $downloadURL = asset(Storage::disk('public')->url($path)); // define filename $filename = $file->name; } } // otherwise there are many IDs selected else { $files = File::query()->whereIn('id', $Ids)->get(); $downloadURL = $this->makeArchive($files); $filename = $parent->name . ".zip"; } } } // else there is no $parent else { // if all selected, download all if ($data['all']) { // files are those found in the shares db $files = File::query()->join('file_shares', 'file_shares.file_id', 'files.id') // that are shared with the current user ->where('file_shares.user_id', Auth::id()) // that have not been deleted ->whereNull('files.deleted_at') // order by folders first ->orderByDesc('files.is_folder') // then order by creation date ->orderByDesc('files.id') ->get(); $downloadURL = $this->makeArchive($files); // make filename for file $filename = "shared-" . Str::random(10) . ".zip"; } // else download the selected IDs else { // if there is only one ID selected if (count($Ids) === 1) { // get file $file = File::find($Ids[0]); // if file is a folder if ($file->is_folder) { // and folder is empty if ($file->children->isEmpty()) { // return message return [ "message" => "This folder is empty" ]; } // else folder is populated $files = $file->children; $downloadURL = $this->makeArchive($files); $filename = $file->name . ".zip"; } // otherwise else { // create a new path off $path = pathinfo($file->stored_at, PATHINFO_BASENAME); // if file has been uploaded to S3, if ($file->s3 == 1) { // pull the file off S3 $s3file = Storage::get($file->stored_at); // put it on the public drive for use Storage::disk('public')->put($path, $s3file); } else { // modify path $path = 'public/' . $path; // get local file $localFile = Storage::disk('local')->get($file->stored_at); // put it on the public drive for use Storage::disk('public')->put($path, $localFile); } // define download path as being the file on the public drive $downloadURL = asset(Storage::disk('public')->url($path)); // define filename $filename = $file->name; } } // otherwise there are many IDs selected else { $files = File::query()->whereIn('id', $Ids)->get(); $downloadURL = $this->makeArchive($files); $filename = "shared-" . Str::random(10) . ".zip"; } } } // return URL and filename return [ 'url' => $downloadURL, 'filename' => $filename, ]; } // get download link for files that are shared by user public function downloadSharedBy(SharedFiles $request) { $data = $request->validated(); // get parent folder from DeleteFiles request $parent = $request->parent; // get selected Id's otherwise empty array $Ids = $data['Ids'] ?? []; // if no files selected if (!$data['all'] == false && empty($Ids)) { return [ 'message' => 'No files selected!' ]; } if ($parent) { // if all selected, download all if ($data['all']) { $downloadURL = $this->makeArchive($parent->children); // make filename for file $filename = $parent->name . ".zip"; } // else download the selected IDs else { // if there is only one ID selected if (count($Ids) === 1) { // get file $file = File::find($Ids[0]); // if file is a folder if ($file->is_folder) { // and folder is empty if ($file->children->isEmpty()) { // return message return [ "message" => "This folder is empty" ]; } // else folder is populated $files = $file->children; $downloadURL = $this->makeArchive($files); $filename = $file->name . ".zip"; } // otherwise else { // create a new path $path = pathinfo($file->stored_at, PATHINFO_BASENAME); // if file has been uploaded to S3, if ($file->s3 == 1) { // pull the file off S3 $s3file = Storage::get($file->stored_at); // put it on the public drive for use Storage::disk('public')->put($path, $s3file); } else { // modify path $path = 'public/' . $path; // get local file $localFile = Storage::disk('local')->get($file->stored_at); // put it on the public drive for use Storage::disk('public')->put($path, $localFile); } // define download path as being the file on the public drive $downloadURL = asset(Storage::disk('public')->url($path)); // define filename $filename = $file->name; } } // otherwise there are many IDs selected else { $files = File::query()->whereIn('id', $Ids)->get(); $downloadURL = $this->makeArchive($files); $filename = $parent->name . ".zip"; } } } // else there is no $parent else { // if all selected, download all if ($data['all']) { // files are those found in the shares db $files = File::query()->join('file_shares', 'file_shares.file_id', 'files.id') // that are created by the current user ->where('files.created_by', Auth::id()) // that have not been deleted ->whereNull('files.deleted_at') // order by folders first ->orderByDesc('files.is_folder') // then order by creation date ->orderByDesc('files.id') ->get(); $downloadURL = $this->makeArchive($files); // make filename for file $filename = "shared-" . Str::random(10) . ".zip"; } // else download the selected IDs else { // if there is only one ID selected if (count($Ids) === 1) { // get file $file = File::find($Ids[0]); // if file is a folder if ($file->is_folder) { // and folder is empty if ($file->children->isEmpty()) { // return message return [ "message" => "This folder is empty" ]; } // else folder is populated $files = $file->children; $downloadURL = $this->makeArchive($files); $filename = $file->name . ".zip"; } // otherwise else { // create a new path off "public/" $path = pathinfo($file->stored_at, PATHINFO_BASENAME); // if file has been uploaded to S3, if ($file->s3 == 1) { // pull the file off S3 $s3file = Storage::get($file->stored_at); // put it on the public drive for use Storage::disk('public')->put($path, $s3file); } else { // modify path $path = 'public/' . $path; // get local file $localFile = Storage::disk('local')->get($file->stored_at); // put it on the public drive for use Storage::disk('public')->put($path, $localFile); } // define download path as being the file on the public drive $downloadURL = asset(Storage::disk('public')->url($path)); // define filename $filename = $file->name; } } // otherwise there are many IDs selected else { $files = File::query()->whereIn('id', $Ids)->get(); $downloadURL = $this->makeArchive($files); $filename = "shared-" . Str::random(10) . ".zip"; } } } // return URL and filename return [ 'url' => $downloadURL, 'filename' => $filename, ]; } // recycle selected files public function recycle(SelectedFiles $request) { // get validated data $data = $request->validated(); // get parent folder from DeleteFiles request $parent = $request->parent; // if all files were selected if ($data['all']) { foreach ($parent->children as $file) { $file->delete(); } } // otherwise specific IDs were selected else { foreach($data['Ids'] ?? [] as $fileId) { $targetFile = File::find($fileId); if ($targetFile) $targetFile->delete(); } } return redirect()->route('userFiles', [ 'folder' => $parent->path ]); } // restores selected files public function restore(RecycledFiles $request) { // get validated data $data = $request->validated(); // if all files were selected if ($data['all']) { $files = File::onlyTrashed()->get(); foreach ($files as $file) { $file->restore(); } } // otherwise specific IDs were selected else { // get Id's unless empty $Ids = $data['Ids'] ?? []; // get files $files = File::onlyTrashed() ->whereIn('id', $Ids) ->get(); foreach ($files as $file) { $file->restore(); } } return redirect()->route('recycleBin'); } // deletes selected files (permanent delete) public function delete(RecycledFiles $request) { // get validated data $data = $request->validated(); // if all files were selected if ($data['all']) { $files = File::onlyTrashed()->get(); foreach ($files as $file) { $file->shred(); } } // otherwise specific IDs were selected else { // get Id's unless empty $Ids = $data['Ids'] ?? []; // get files $files = File::onlyTrashed() ->whereIn('id', $Ids) ->get(); foreach ($files as $file) { $file->shred(); } } return redirect()->route('recycleBin'); } // shares selected files public function share(ShareFiles $request) { // get data $data = $request->validated(); // get parent folder $parent = $request->parent; // get selected Id's otherwise empty array $Ids = $data['Ids'] ?? []; // get user by email $user = User::query()->where('email', $data['email'])->first(); // if no files selected if (!$data['all'] == false && empty($Ids)) { return [ 'message' => 'No files selected!' ]; } // if user doesn't exist if (!$user->id) { return [ 'message' => 'Email does not belong to user!' ]; } // otherwise, if all is passed, get current children. else find files by passed Id's $files = $data['all'] ? $parent->children : File::find($Ids); // define recursive function to add files to share function recursiveShare($queued, $recipient) { // get children of parent and determine whether recursive function needs to be called foreach ($queued as $file) { // check if file already exists in shared DB $exists = FileShare::query()->where('file_id', $file->id)->where('user_id', $recipient->id)->first(); if ($exists) { continue; } // else // create new entry $entry = [ 'file_id' => $file->id, 'user_id' => $recipient->id, 'created_at' => $file->created_at, 'updated_at' => Carbon::now(), ]; FileShare::insert($entry); // recurse on children, if any if ($file->children) { recursiveShare($file->children, $recipient); } } } // begin recursion on files recursiveShare($files, $user); // send email to recipient Mail::to($user)->send(new ShareFilesNotification($user, Auth::user(), $files)); return redirect()->back(); } // unshares selected files public function unshare(SharedFiles $request) { // get data $data = $request->validated(); // get parent folder $parent = $request->parent; // get selected Id's otherwise empty array $Ids = $data['Ids'] ?? []; // if no files selected if (!$data['all'] == false && empty($Ids)) { return [ 'message' => 'No files selected!' ]; } // if parent exists if ($parent) { // if all is passed, get current children. else find files by passed Id's $files = $data['all'] ? $parent->children : File::find($Ids); } // else else { // find all files that are created by current user and shared with others $all = File::query()->join('file_shares', 'file_shares.file_id', 'files.id') ->where('files.created_by', Auth::id()) ->whereNull('files.deleted_at') ->get(); $files = $data['all'] ? $all : File::find($Ids); } // define recursive function to remove files to share function recursiveUnshare($queued) { // get children of parent and determine whether recursive function needs to be called foreach ($queued as $file) { // check if file already exists in shared DB $dbRecord = FileShare::query()->where('file_id', $file->id)->first(); if ($dbRecord) { // get regular db file $file = File::query()->where('created_by', Auth::id())->find($file->id); $dbRecord->forceDelete(); // recurse on children, if any if ($file->children) { recursiveUnshare($file->children); } } } } // begin recursion on files recursiveUnshare($files); return redirect()->back(); } // gets user's root folder - called from userFiles private function getRoot() { return File::query()->whereIsRoot()->where('created_by', Auth::id())->firstOrFail(); } // upload files - called from upload private function uploadFiles($files, $parent) { // loop over files, make and upload each one foreach ($files as $userFile) { $file = new File(); $file->stored_at = $userFile->store('/files/' . Auth::id(), 's3'); $file->is_folder = false; $file->name = $userFile->getClientOriginalName(); $file->mimetype = $userFile->getMimeType(); $file->size = $userFile->getSize(); $file->s3 = 1; // file has NOT been uploaded to s3 $parent->appendNode($file); } } // upload tree - called from upload private function uploadTree($tree, $parent) { // loop over files in file tree foreach($tree as $name => $file) { // if current node in $tree is an array (that means, a folder) if (is_array($file)) { // make folder $folder = new File(); $folder->is_folder = 1; $folder->name = $name; // append folder to parent $parent->appendNode($folder); // call function recursively until if condition is false // each call has the newly-created $folder as $parent $this->uploadTree($file, $folder); } // otherwise the node is a file; use uploadFiles() with file else { $this->uploadFiles([$file], $parent); } } } // makes archive - called from download private function makeArchive(Collection $files): string { // make name for archive $archiveName = 'archive/' . Str::random() . ".zip"; // create directory if none exists if (!Storage::disk('public')->has(dirname($archiveName))) { Storage::disk('public')->makeDirectory(dirname($archiveName)); } // get path of $archiveName $path = Storage::disk('public')->path($archiveName); // create new ZipArchive $archive = new ZipArchive(); // see if a archive can be created or overwritten at $path $res = $archive->open($path, ZipArchive::CREATE | ZipArchive::OVERWRITE); // if so if ($res === true) { // define recursive function to add files to archive function recursiveAdd($queued, $archive, $parent = "") { // get children of parent and determine whether recursive function needs to be called foreach ($queued as $file) { // if there are no children, add file to archive if ($file->children->isEmpty()) { // set $internalPath to reflect file $internalPath = $parent . $file->name; // default file path is stored on local storage $filePath = Storage::disk('local')->path($file->stored_at); // if the file is uploaded to S3 if ($file->s3 == 1) { // create a new path $filePath = pathinfo($file->stored_at, PATHINFO_BASENAME); // pull the file off S3 $s3file = Storage::get($file->stored_at); // put it on the public drive for use Storage::disk('public')->put($filePath, $s3file); // reassign $filePath to the actual file path $filePath = Storage::disk('public')->path($filePath); } // add file to archive $archive->addFile($filePath, $internalPath); // continue loop continue; } // else // set $internalPath to reflect a directory $internalPath = $parent . $file->name . "/"; // recurse recursiveAdd($file->children, $archive, $internalPath); } } // add all $files to $archive recursiveAdd($files, $archive); } // close archive $archive->close(); // return archive return asset(Storage::disk('public')->url($archiveName)); } }