178 lines
6.3 KiB
PHP
178 lines
6.3 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Api\Assets;
|
|
|
|
use App\Events\AssetWasCreated;
|
|
use App\Exceptions\BodyTooLargeException;
|
|
use App\Exceptions\StoreResourceFailedException;
|
|
use App\Http\Controllers\Controller;
|
|
use App\Models\Asset;
|
|
use App\Transformers\Assets\AssetTransformer;
|
|
use GuzzleHttp\Client;
|
|
use GuzzleHttp\Exception\TransferException;
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Storage;
|
|
use Illuminate\Support\Str;
|
|
use Psr\Http\Message\ResponseInterface;
|
|
|
|
class UploadFileController extends Controller {
|
|
protected array $validMimes = [
|
|
'image/jpeg' => [
|
|
'type' => 'image',
|
|
'extension' => 'jpeg',
|
|
],
|
|
'image/jpg' => [
|
|
'type' => 'image',
|
|
'extension' => 'jpg',
|
|
],
|
|
'image/png' => [
|
|
'type' => 'image',
|
|
'extension' => 'png',
|
|
],
|
|
/*
|
|
'image/svg+xml' => [
|
|
'type' => 'image',
|
|
'extension' => 'svg'
|
|
],
|
|
*/
|
|
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => [
|
|
'type' => 'document',
|
|
'extension' => 'xlsx'
|
|
],
|
|
'application/vnd.ms-excel' => [
|
|
'type' => 'document',
|
|
'extension' => 'xls'
|
|
],
|
|
'application/vnd.openxmlformats-officedocument.wordprocessingml.document' => [
|
|
'type' => 'document',
|
|
'extension' => 'docx'
|
|
],
|
|
'application/msword' => [
|
|
'type' => 'document',
|
|
'extension' => 'doc'
|
|
],
|
|
'application/pdf' => [
|
|
'type' => 'document',
|
|
'extension' => 'pdf'
|
|
],
|
|
'application/vnd.openxmlformats-officedocument.presentationml.presentation' => [
|
|
'type' => 'document',
|
|
'extension' => 'pptx'
|
|
]
|
|
];
|
|
|
|
protected Client $client;
|
|
protected Asset $model;
|
|
|
|
public function __construct(Client $client, Asset $model) {
|
|
$this->client = $client;
|
|
$this->model = $model;
|
|
}
|
|
|
|
public function store(Request $request): JsonResponse {
|
|
if ($request->isJson()) {
|
|
$asset = $this->uploadFromUrl([
|
|
'url' => $request->get('url'),
|
|
'user' => $request->user(),
|
|
]);
|
|
} elseif ($request->hasFile('file')) {
|
|
$file = $request->file('file')->getRealPath();
|
|
$asset = $this->uploadFromDirectFile([
|
|
'mime' => $request->file('file')->getClientMimeType(),
|
|
'name' => $request->get('name') ?? $request->file('file')->getClientOriginalName(),
|
|
'filename' => $request->file('file')->getClientOriginalName(),
|
|
'extension' => $request->file('file')->getClientOriginalExtension(),
|
|
'content' => file_get_contents($file),
|
|
'Content-Length' => $request->header('Content-Length'),
|
|
'user' => $request->user(),
|
|
'latitude' => $request->get('latitude'),
|
|
'longitude' => $request->get('longitude'),
|
|
'accuracy' => $request->get('accuracy')
|
|
]);
|
|
} else {
|
|
$body = !(base64_decode($request->getContent())) ? $request->getContent() : base64_decode($request->getContent());
|
|
$asset = $this->uploadFromDirectFile([
|
|
'mime' => $request->header('Content-Type'),
|
|
'content' => $body,
|
|
'Content-Length' => $request->header('Content-Length'),
|
|
'user' => $request->user(),
|
|
'latitude' => $request->get('latitude'),
|
|
'longitude' => $request->get('longitude')
|
|
]);
|
|
}
|
|
|
|
event(new AssetWasCreated($asset));
|
|
|
|
return fractal($asset, new AssetTransformer())->respond(201);
|
|
}
|
|
|
|
protected function uploadFromDirectFile($attributes = []) {
|
|
$this->validateMime($attributes['mime']);
|
|
$this->validateBodySize($attributes['Content-Length'], $attributes['content']);
|
|
$path = $this->storeInFileSystem($attributes);
|
|
|
|
return $this->storeInDatabase($attributes, $path);
|
|
}
|
|
|
|
protected function uploadFromUrl($attributes = []) {
|
|
$response = $this->callFileUrl($attributes['url']);
|
|
$attributes['mime'] = $response->getHeader('content-type')[0];
|
|
$attributes['filename'] = pathinfo($attributes['url'], PATHINFO_BASENAME);
|
|
$attributes['extension'] = pathinfo($attributes['url'], PATHINFO_EXTENSION);
|
|
$this->validateMime($attributes['mime']);
|
|
$attributes['content'] = $response->getBody();
|
|
$path = $this->storeInFileSystem($attributes);
|
|
|
|
return $this->storeInDatabase($attributes, $path);
|
|
}
|
|
|
|
protected function storeInDatabase(array $attributes, $path) {
|
|
$file = $this->model->create([
|
|
'type' => $this->validMimes[$attributes['mime']]['type'],
|
|
'path' => $path,
|
|
'mime' => $attributes['mime'],
|
|
'name' => $attributes['name'] ?? null,
|
|
'filename' => $attributes['filename'] ?? null,
|
|
'extension' => $attributes['extension'] ?? null,
|
|
'user_id' => ! empty($attributes['user']) ? $attributes['user']->id : null,
|
|
'latitude' => $attributes['latitude'],
|
|
'longitude' => $attributes['longitude'],
|
|
'accuracy' => $attributes['accuracy']
|
|
]);
|
|
|
|
return $file;
|
|
}
|
|
|
|
protected function storeInFileSystem(array $attributes): string {
|
|
$filename = md5(Str::random(16).date('U'));
|
|
$path = "public/upload/{$filename[0]}/$filename.{$this->validMimes[$attributes['mime']]['extension']}";
|
|
Storage::put($path, $attributes['content']);
|
|
return $path;
|
|
}
|
|
|
|
protected function callFileUrl($url): ResponseInterface {
|
|
try {
|
|
return $this->client->get($url);
|
|
} catch (TransferException $e) {
|
|
throw new StoreResourceFailedException('Validation Error', [
|
|
'url' => 'The url seems to be unreachable: '.$e->getCode(),
|
|
]);
|
|
}
|
|
}
|
|
|
|
protected function validateMime($mime) {
|
|
if (!array_key_exists($mime, $this->validMimes)) {
|
|
throw new StoreResourceFailedException('Validation Error', [
|
|
'Content-Type' => 'The Content Type sent is not valid',
|
|
]);
|
|
}
|
|
}
|
|
|
|
protected function validateBodySize($contentLength, $content) {
|
|
if ($contentLength > config('files.maxsize', 1000000) || mb_strlen($content) > config('files.maxsize', 1000000)) {
|
|
throw new BodyTooLargeException();
|
|
}
|
|
}
|
|
}
|