Sindbad~EG File Manager

Current Path : /home/copmadinaarea/drive.copmadinaarea.org/common/Files/Controllers/
Upload File :
Current File : /home/copmadinaarea/drive.copmadinaarea.org/common/Files/Controllers/DownloadFileController.php

<?php namespace Common\Files\Controllers;

use Carbon\Carbon;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Http\Request;
use Common\Core\Controller;
use Common\Files\FileEntry;
use Storage;
use ZipArchive;

class DownloadFileController extends Controller
{
    /**
     * @var Request
     */
    private $request;

    /**
     * @var FileEntry
     */
    private $fileEntry;

    /**
     * DownloadFileController constructor.
     * @param Request $request
     * @param FileEntry $fileEntry
     */
    public function __construct(Request $request, FileEntry $fileEntry)
    {
        $this->request = $request;
        $this->fileEntry = $fileEntry;
    }

    public function download()
    {
        // TODO: limit to N records or chunk

        $hashes = explode(',', $this->request->get('hashes'));
        $ids = array_map(function($hash) {
            return $this->fileEntry->decodeHash($hash);
        }, $hashes);

        $entries = $this->fileEntry->whereIn('id', $ids)->get();

        // TODO: refactor file entry policy to accent multiple IDs
        $entries->each(function($entry) {
            $this->authorize('show', [FileEntry::class, $entry]);
        });

        if ($entries->count() === 1 && $entries->first()->type !== 'folder') {
            $entry = $entries->first();

            $disk = $entry->getDisk();
            $stream = $disk->readStream($entry->getStoragePath());

            return response()->stream(function() use($stream) {
                fpassthru($stream);
            }, 200, [
                "Content-Type" => $entry->mime,
                "Content-Length" => $disk->size($entry->getStoragePath()),
                "Content-disposition" => "attachment; filename=\"" . $entry->name . "\"",
            ]);
        } else {
            $path = $this->createZip($entries);
            $timestamp = Carbon::now()->getTimestamp();
            return response()->download($path, "download-$timestamp.zip");
        }
    }

    /**
     * Create a zip archive for download.
     *
     * @param Collection $entries
     * @return string
     */
    private function createZip(Collection $entries) {
        $random = str_random();
        $path = storage_path("app/temp/zips/$random.zip");
        $zip = new ZipArchive();

        $zip->open($path, ZIPARCHIVE::CREATE);

        $this->fillZip($zip, $entries);

        $zip->close();

        return $path;
    }

    /**
     * @param ZipArchive $zip
     * @param Collection $entries
     */
    private function fillZip(ZipArchive $zip, Collection $entries) {
        $entries->each(function(FileEntry $entry) use($zip) {
            if ($entry->type === 'folder') {
                $children = $entry->findChildren();
                $children->filter(function(FileEntry $childEntry) {
                    return $childEntry->type !== 'folder';
                })->each(function(FileEntry $childEntry) use($zip, $entry, $children) {
                    $zip->addFromString($this->transformPath($childEntry, $entry, $children), $this->getFileContents($childEntry));
                });
            } else {
                $zip->addFromString($entry->getNameWithExtension(), $this->getFileContents($entry));
            }
        });
    }

    /**
     * Replace entry IDs with names inside "path" property.
     *
     * @param FileEntry $entry
     * @param FileEntry $parent
     * @param Collection $folders
     * @return string
     */
    private function transformPath(FileEntry $entry, FileEntry $parent, Collection $folders)
    {
        if ( ! $entry->path) return $entry->getNameWithExtension();

        // '56/55/54 => [56,55,54]
        $path = array_filter(explode('/', $entry->path));
        $path = array_map(function($id) {
            return (int) $id;
        }, $path);

        //only generate path until specified parent and not root
        $path = array_slice($path, array_search($parent->id, $path));

        // last value will be id of the file itself, remove it
        array_pop($path);

        //map parent folder IDs to names
        $path = array_map(function($id) use($folders) {
            return $folders->find($id)->name;
        }, $path);

        return implode('/', $path) . '/' . $entry->getNameWithExtension();
    }

    private function getFileContents(FileEntry $entry) {
        return $entry->getDisk()->get($entry->getStoragePath());
    }
}

Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists