the browser-facing portion of osu!
at master 3.0 kB view raw
1<?php 2 3// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the GNU Affero General Public License v3.0. 4// See the LICENCE file in the repository root for full licence text. 5 6declare(strict_types=1); 7 8namespace App\Libraries; 9 10use App\Exceptions\InvariantException; 11use App\Models\Model; 12use Illuminate\Http\File; 13use League\Flysystem\Local\LocalFilesystemAdapter; 14 15class Uploader 16{ 17 private const DEFAULT_MAX_FILESIZE = 10_000_000; 18 19 private ?string $filename; 20 21 public function __construct( 22 private string $baseDir, 23 public Model $model, 24 private string $attr, 25 private array $processors = [], 26 ) { 27 $this->filename = $this->model->{$this->attr}; 28 } 29 30 private static function process(string $name, ?array $options, string $srcPath): ?string 31 { 32 switch ($name) { 33 case 'image': 34 $processor = new ImageProcessor( 35 $srcPath, 36 $options['maxDimensions'], 37 $options['maxFilesize'] ?? static::DEFAULT_MAX_FILESIZE, 38 ); 39 $processor->process(); 40 41 return $processor->ext(); 42 } 43 44 throw new InvariantException('unknown process name'); 45 } 46 47 public function delete(): void 48 { 49 $this->setFilename(null); 50 \Storage::deleteDirectory($this->dir()); 51 } 52 53 public function get(): ?string 54 { 55 $path = $this->path(); 56 57 return $path === null ? null : \Storage::get($path); 58 } 59 60 public function store(string $srcPath, string $ext = ''): void 61 { 62 foreach ($this->processors as $processName => $processOptions) { 63 $newExt = static::process($processName, $processOptions, $srcPath); 64 if ($newExt !== null) { 65 $ext = $newExt; 66 } 67 } 68 69 $this->delete(); 70 $filename = hash_file('sha256', $srcPath); 71 if (present($ext)) { 72 $filename .= ".{$ext}"; 73 } 74 $this->setFilename($filename); 75 $storage = \Storage::disk(); 76 77 if ($storage->getAdapter() instanceof LocalFilesystemAdapter) { 78 $options = [ 79 'visibility' => 'public', 80 'directory_visibility' => 'public', 81 ]; 82 } 83 84 $storage->putFileAs( 85 $this->dir(), 86 new File($srcPath), 87 $this->filename, 88 $options ?? [], 89 ); 90 } 91 92 public function url(): ?string 93 { 94 $path = $this->path(); 95 96 return $path === null ? null : StorageUrl::make(null, $path); 97 } 98 99 private function dir(): string 100 { 101 return "{$this->baseDir}/{$this->model->getKey()}"; 102 } 103 104 private function path(): ?string 105 { 106 return $this->filename === null ? null : "{$this->dir()}/{$this->filename}"; 107 } 108 109 private function setFilename(?string $filename): void 110 { 111 $this->filename = $filename; 112 $this->model->{$this->attr} = $filename; 113 } 114}