diff --git a/app/Http/Controllers/User/ImageController.php b/app/Http/Controllers/User/ImageController.php index 7180a566..d7acdde8 100644 --- a/app/Http/Controllers/User/ImageController.php +++ b/app/Http/Controllers/User/ImageController.php @@ -14,6 +14,7 @@ use Illuminate\Http\Response; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\DB; use Illuminate\View\View; +use League\Flysystem\FilesystemException; class ImageController extends Controller { @@ -84,6 +85,20 @@ class ImageController extends Controller return $this->success('success', compact('image')); } + public function output(Request $request) + { + /** @var Image $image */ + $image = Image::query()->where('key', $request->route('key'))->firstOr(fn() => abort(404)); + try { + $stream = $image->filesystem()->readStream($image->pathname); + } catch (FilesystemException $e) { + abort(404); + } + $img = \Intervention\Image\Facades\Image::make($stream); + // ... + return $img->response(quality: 100); + } + public function permission(Request $request): Response { /** @var User $user */ diff --git a/app/Models/Group.php b/app/Models/Group.php index a495d246..31a07aef 100644 --- a/app/Models/Group.php +++ b/app/Models/Group.php @@ -50,7 +50,7 @@ class Group extends Model GroupConfigKey::LimitPerDay => 300, GroupConfigKey::LimitPerWeek => 600, GroupConfigKey::LimitPerMonth => 999, - GroupConfigKey::AcceptedFileSuffixes => ['jpg', 'jpeg', 'gif', 'png', 'apng', 'bmp', 'ico', 'svg'], + GroupConfigKey::AcceptedFileSuffixes => ['jpg', 'jpeg', 'gif', 'png', 'apng', 'bmp', 'ico'], GroupConfigKey::PathNamingRule => '{Y}/{m}/{d}', GroupConfigKey::FileNamingRule => '{uniqid}', ]); diff --git a/app/Models/Image.php b/app/Models/Image.php index 02f876fd..b507b079 100644 --- a/app/Models/Image.php +++ b/app/Models/Image.php @@ -4,7 +4,6 @@ namespace App\Models; use App\Enums\Strategy\LocalOption; use App\Service\ImageService; -use App\Utils; use Carbon\Carbon; use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Factories\HasFactory; @@ -12,6 +11,7 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Support\Collection; use Illuminate\Support\Facades\Storage; +use Illuminate\Support\Str; use League\Flysystem\Filesystem; /** @@ -19,6 +19,7 @@ use League\Flysystem\Filesystem; * @property int $user_id * @property int $album_id * @property int $strategy_id + * @property string $key * @property string $path * @property string $name * @property string $pathname @@ -48,6 +49,7 @@ class Image extends Model use HasFactory; protected $fillable = [ + 'key', 'path', 'name', 'origin_name', @@ -81,6 +83,10 @@ class Image extends Model protected static function booted() { + static::creating(function (self $image) { + $image->key = $image->generateKey(); + }); + static::deleting(function (self $image) { // TODO 检测是否启用了队列,放置队列中异步删除 // 在当前图片所属的策略中是否存在其他相同 md5 和 sha1 的记录,没有则可以删除物理文件 @@ -91,8 +97,7 @@ class Image extends Model ->where('sha1', $image->sha1) ->exists() ) { - $adapter = (new ImageService())->getAdapter($image->strategy->key, $image->strategy->configs); - (new Filesystem($adapter))->delete($image->pathname); + $image->filesystem()->delete($image->pathname); } }); } @@ -117,7 +122,8 @@ class Image extends Model if ($this->strategy->configs->get(LocalOption::IsEnableOriginUrl)) { return rtrim($this->strategy->configs->get(LocalOption::Domain), '/').'/'.$this->pathname; } else { - return asset($this->pathname); + // 原图保护 + return asset("{$this->key}.{$this->extension}"); } }); } @@ -133,6 +139,11 @@ class Image extends Model ])); } + public function filesystem(): Filesystem + { + return new Filesystem((new ImageService())->getAdapter($this->strategy->key, $this->strategy->configs)); + } + public function user(): BelongsTo { return $this->belongsTo(User::class, 'user_id', 'id'); @@ -147,4 +158,13 @@ class Image extends Model { return $this->belongsTo(Strategy::class, 'strategy_id', 'id'); } + + private function generateKey($length = 6): string + { + $key = Str::random($length); + if (self::query()->where('key', $key)->exists()) { + return $this->generateKey(++$length); + } + return $key; + } } diff --git a/app/Models/Strategy.php b/app/Models/Strategy.php index aeb73b12..c85c17a3 100644 --- a/app/Models/Strategy.php +++ b/app/Models/Strategy.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Enums\Strategy\LocalOption; use Carbon\Carbon; use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Factories\HasFactory; @@ -45,6 +46,16 @@ class Strategy extends Model 'configs' => 'collection', ]; + protected static function booted() + { + static::creating(function (self $strategy) { + $strategy->configs = collect([ + LocalOption::Domain => env('APP_URL'), + LocalOption::IsEnableOriginUrl => true, + ]); + }); + } + public function group(): BelongsTo { return $this->belongsTo(Group::class, 'group_id', 'id'); diff --git a/database/migrations/2021_12_11_191158_create_images_table.php b/database/migrations/2021_12_11_191158_create_images_table.php index 6ceb0af9..0f50aedd 100644 --- a/database/migrations/2021_12_11_191158_create_images_table.php +++ b/database/migrations/2021_12_11_191158_create_images_table.php @@ -22,6 +22,7 @@ class CreateImagesTable extends Migration $table->foreignId('user_id')->nullable()->comment('用户')->constrained('users')->onDelete('set null'); $table->foreignId('album_id')->nullable()->comment('相册')->constrained('albums')->onDelete('set null'); $table->foreignId('strategy_id')->nullable()->comment('策略')->constrained('strategies')->onDelete('set null'); + $table->string('key')->unique()->comment('key'); $table->string('path')->comment('保存路径'); $table->string('name')->comment('保存名称'); $table->string('origin_name')->default('')->comment('原始名称'); diff --git a/routes/web.php b/routes/web.php index 30541dc5..aada8366 100644 --- a/routes/web.php +++ b/routes/web.php @@ -37,4 +37,8 @@ Route::group(['middleware' => ['auth']], function () { }); }); +Route::any('{key}.{extension}', [ImageController::class, 'output'])->where('extension', implode('|', [ + 'jpg', 'jpeg', 'gif', 'png', 'apng', 'bmp', 'ico', +])); + require __DIR__.'/auth.php';