File "StoreFile.php"
Full Path: /var/www/drive/foundation/src/Files/Actions/StoreFile.php
File size: 3.83 KB
MIME-type: text/x-php
Charset: utf-8
<?php
namespace Common\Files\Actions;
use Common\Files\FileEntryPayload;
use Illuminate\Contracts\Filesystem\Filesystem;
use Illuminate\Http\File;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\File as FileFacade;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use League\Flysystem\Local\LocalFilesystemAdapter;
use Symfony\Component\Mime\MimeTypes;
class StoreFile
{
protected Filesystem $disk;
protected array $diskOptions;
protected FileEntryPayload $payload;
public function execute(
FileEntryPayload $payload,
array $fileOptions,
): string|false {
$this->disk = $payload->public
? Storage::disk('public')
: Storage::disk('uploads');
$this->diskOptions = [
'mimetype' => $payload->clientMime,
'visibility' => $payload->visibility,
];
$this->payload = $payload;
if (
// prevent uploading .htaccess files
$payload->filename === '.htaccess' ||
// dont store php files in public disk
($payload->public && $this->isPhpFile($payload, $fileOptions)) ||
// prevent path traversal or storing at root in user specified folder
($payload->diskPrefix &&
(Str::contains($payload->diskPrefix, '..') ||
$payload->diskPrefix === '/'))
) {
abort(403);
}
if (isset($fileOptions['file'])) {
return $this->storeUploadedFile($fileOptions['file']);
} elseif (isset($fileOptions['contents'])) {
return $this->storeStringContents($fileOptions['contents']);
} elseif (isset($fileOptions['path'])) {
// if source and destination is local (and not temp dir) move file
// instead of copying or using streams, this will be a lot faster
if (
Arr::get($fileOptions, 'moveFile') === true &&
$this->disk->getAdapter() instanceof LocalFilesystemAdapter
) {
return $this->storeLocalFile($fileOptions['path']);
} else {
return $this->storeUploadedFile(new File($fileOptions['path']));
}
}
return false;
}
protected function storeUploadedFile(File|UploadedFile $file): string|false
{
return $this->disk->putFileAs(
$this->payload->diskPrefix,
$file,
$this->payload->filename,
$this->diskOptions,
);
}
protected function storeStringContents(string $contents): string|false
{
return $this->disk->put(
"{$this->payload->diskPrefix}/{$this->payload->filename}",
$contents,
$this->diskOptions,
);
}
protected function storeLocalFile(string $sourcePath): string|false
{
$dirPath = $this->disk->path($this->payload->diskPrefix);
FileFacade::ensureDirectoryExists($dirPath);
$stored = @rename($sourcePath, "$dirPath/{$this->payload->filename}");
if ($stored) {
return "{$this->payload->diskPrefix}/{$this->payload->filename}";
}
return false;
}
protected function isPhpFile(
FileEntryPayload $payload,
array $fileOptions,
): bool {
if (
Str::of($payload->clientExtension)
->lower()
->startsWith(['php', 'phtml'])
) {
return true;
}
$mimeType = null;
if (isset($fileOptions['file'])) {
$mimeType = $fileOptions['file']->getMimeType();
} elseif (isset($fileOptions['path'])) {
$mimeType = MimeTypes::getDefault()->guessMimeType(
$fileOptions['path'],
);
}
return $mimeType === 'application/x-php';
}
}