upload file on s3 with quasar vue (frontend) and laravel 9 (backend) - laravel

I'm building a platform and I need to upload resources (pdf, images etc) on amazon s3 bucket.
Frontend is made with quasar vue, backend with Laravel 9. The idea is to send file from frontend to backend and upload file on s3 with laravel.
The problem is that nothing happens, my s3 bucket remains empty with no errors or exceptions.
I'm not sure if the problem is sending file from frontend to backend or on the upload from laravel to s3 bucket.
I use q-uploader (but I think is not too different with quasar file-picker). Here's frontend code
<template>
<q-page class="q-pa-sm">
<q-uploader :factory="uploadFile"/>
</q-page>
</template>
<script>
import { api } from 'src/boot/axios';
export default {
methods: {
uploadFile(f){
var fileModel = f[0]
const fileData = new FormData()
fileData.append('file', fileModel)
api.post('/api/resources/file', fileData, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
.then(res=>{
console.log(res)
})
}
}
}
</script>
I made my API on api.php (and I'm sure middleware is not the problem)
Route::prefix('resources')->group(function(){
/*
* other APIs
*/
Route::post('/file',[ResourceController::class, 'postResourceFile'])->middleware('roles:1|2|3');
});
In laravel I've got a controller called ResourceController.php with this function
public function postResourceFile(Request $request){
if($request->hasFile('file')){
$file = $request->file('file');
$name=time().$file->getClientOriginalName();
$filePath = 'resources/' . $name;
Storage::disk('s3')->put($filePath, file_get_contents($file));
$response = [
'file' => $file,
];
} else {
$response = [
'message' => 'no file'
];
}
return response($response, 200);
}
In Laravel filesystems.php I didn't change original configuration
's3' => [
'driver' => 's3',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION'),
'bucket' => env('AWS_BUCKET'),
'url' => env('AWS_URL'),
'endpoint' => env('AWS_ENDPOINT'),
'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false),
],
And here's my .env AWS configuration.
AWS_ACCESS_KEY_ID=myID
AWS_SECRET_ACCESS_KEY=myKey
AWS_DEFAULT_REGION=eu-central-1
AWS_BUCKET=myBucket
AWS_USE_PATH_STYLE_ENDPOINT=false
AWS_URL=http://s3.eu-central-1.amazonaws.com/myBucket
Backend response is
file:{}
but I'm not sure if $file is empty or it'is just a browser problem, because file should be something like blob.
Can someone helps me?
Thanks in advance

File is a blob and cannot be converted to Json easily.
I'm almost sure your code works.
to check that, you can log the file:
Log::debug('file received => ', ['file' => $request->file('file')]);
Double check if laravel is putting the file into s3. I think the way you're doing maybe it's incorrect. The way i do is:
// on the top:
use Illuminate\Http\File;
use Illuminate\Http\Request;
// on the function:
$file = new File($request->file('file'));
$path = Storage::disk('s3')->putFile('resources', $file);
return response()->json(
[
'status' => 'success',
"url" => Storage::url($path),
'size' => Storage::size($path),
'type' => $file->extension()
],
200
);

Related

how to show images stored in local disk storage in lravel

I want to show the image that uploaded to local disk storage.
the file located at: storage/user/ directory.
$url = Storage::url('users/file.jpg');
$image="<img src='$url' />;
and return it to ajax and append it in the blade page.
return response()->json(["response"=>$image]);
You can do it like this. I would like to change the JSON response first.
return response()->json(['data' => $image, 'status' => 'success', 'code' => 200]);
In Ajax, once your file uploaded
$.ajax({
.
.
.
success : function (res) {
if (res.code == 200) {
$('#image').text(res.data);
}
});
Add one tag <p id="image"></p> in blade file.
can change your file path in the filesystems.php file under the config folder.
'local' => [ 'driver' => 'local', 'root' => storage_path('__FOLDER_PATH__'), ],
'public' => ['driver' => 'local',
'root' => storage_path('__FOLDER_PATH__'),
'url' => env('APP_URL').'/storage',
'visibility' => 'public',],```
I have found how to show image that Stored in local disk of Storage in laravel:
Routes:
Route::post('/clientarea/form/{id}/responses/individual', [ResponsesController::class,'individual']);
Route::get('/image/show/users/{userId}/{formId}/{fileName}',[ResponsesController::class,'showImage']);
ResponsesController::class,'individual' :
$answer is the path of image in local storage(local disk, not public disk)
$response.= "<img alt='image' title='image' class='answersImage' src='/image/show/$answer'>";
return $response;
return respose and append it in the blade by jquery:
success: function(data, textStatus, jQxhr ){
$('#respContainer').html(response);
};
ResponsesController::class,'showImage'] :
$path='users/'.$userId.'/'.$formId.'/'.$filename;
$file = Storage::get($path);
$response = response()->make($file, 200);
$response->header('Content-Type', 'image/jpg');
return $response;
and It will show the image that Stored in local disk.

Trying to get a S3 image URL inside a bucket folder

I'm trying to get a proper link to be consumed from an API request. I stored an image in a S3 bucket. Here's the steps:
A user fills a form and upload an image.
Image uploaded into S3 bucket within a folder (let's say: images/mynewimage.png)
The user open a new page which contains the image
The problem is, the image URL I get from Laravel is different from the S3 bucket itself.
From S3 bucket, the url looks like this :
https://prismahrbucket.s3-ap-southeast-1.amazonaws.com/reimburses/Screen+Shot+2020-03-17+at+14.21.38.png
But from Laravel, the given URL is wrong. Like this:
https://prismahrbucket.s3-ap-southeast-1.amazonaws.com/Screen+Shot+2020-03-17+at+14.21.38.png
Please have a look at my scripts:
ReimburseController.php
/**
* Store a newly created resource in storage.
*
* #param \App\Http\Requests\RequestReimburse $request
* #return \Illuminate\Http\Response
*/
public function store(RequestReimburse $request)
{
$validated = collect($request->validated())
->except(['images'])
->toArray();
if ($request->images) {
$images = json_decode($request->images);
$paths = [];
foreach ($images as $image) {
array_push($paths, $this->handleUploads($image, $validated));
}
$validated = array_add($validated, 'images', json_encode($paths));
}
$reimburse = Reimburse::create($validated);
return response()->json([
'created' => true,
'data' => $reimburse,
], 201);
}
protected function handleUploads($image, $validated)
{
$imageName = time() . str_random(10) . '.png';
Storage::disk('s3')
->put("reimburses/{$imageName}", base64_decode($image), 'public');
$path = Storage::disk('s3')->url($imageName);
return $path;
}
filesystem.php
's3' => [
'driver' => 's3',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION'),
'bucket' => env('AWS_BUCKET'),
'url' => env('AWS_URL'),
'visibility' => 'public' // Make s3 files public
],
How can I solve it?
I've just found a solution. Instead of using only $imageName, I specified the folder name at the beginning.
I mean, I changed this:
$path = Storage::disk('s3')->url($imageName);
To this: $path = Storage::disk('s3')->url("images/$imageName");

Database record not being created when large file is uploaded

I have a decoupled VueJS frontend and a Laravel API backend.
When I upload a large file (3GB for instance) there's a Eloquent create() method that doesn't get executed. However, when I upload smaller files (a few hundred MB) it executes without problem.
My code:
public function store(Request $request){
if(count($request->file('files'))){
$shareId = substr(md5(rand()), 0, 7);
try{
$user = User::where('name', 'Anon')->first(); //save file anonymously
$upload = $user->uploads()->create(['share_id' => $shareId, 'visibility' => 'public']);
foreach($request->file('files') as $file){
\Log::info('before file store');
$disk = Storage::disk('files');
$disk->put($file->getClientOriginalName(), fopen($file, 'r+'));
\Log::info('after file
\Log::info('before db create');
//the below code and everything after it doesn't execute
$upload->files()->create(['name' => 'testname',
'originalName' => $file->getClientOriginalName(),
'size' => $file->getClientSize(),
'path' => 'test', 'visibility' => 'public',
'type' => $file->getClientOriginalExtension()]);
\Log::info('after db create');
}
return response()->json([
"success" => $shareId
]);
}
catch(\Exception $e){
return response()->json([
"error" => $e
]);
}
}
}
I log some text to see what executes and only the below logs are shown:
[2019-09-27 14:15:52] local.INFO: before file store
[2019-09-27 14:15:52] local.INFO: after file store
[2019-09-27 14:15:52] local.INFO: before db create
What is causing this? My PHP server is configured to allow files of up to 5GB to be uploaded. I've also set my max_execution_time to 10mins to test and the problem persists. I've omitted the Vue code as I believe this is a backend issue.

Wrong path when downloading in Backpack CRUD view

i added an upload field in my CRUD Controller.
Upload works fine and file gets loaded in my /storage/private directory.
Here is filesystems.php file:
'private' => [
'driver' => 'local',
'root' => storage_path('private')
],
Here are my custom functions in the File.php Model:
public static function boot()
{
parent::boot();
static::deleting(function($file) {
\Storage::disk('private')->delete($file->file);
});
}
public function setFileAttribute($value)
{
$attribute_name = "file";
$disk = "private";
$destination_path = "";
// Cifratura del file
file_put_contents($value->getRealPath(), file_get_contents($value->getRealPath()));
$this->uploadFileToDisk($value, $attribute_name, $disk, $destination_path);
}
And here is my FileCRUDController.php code:
$this->crud->addField(
[ // Upload
'name' => 'file',
'label' => 'File to upload',
'type' => 'upload',
'upload' => true,
'disk' => 'private'
]);
When i try to download the file, however, it tries to fetch it from http://localhost:8000/storage/myfile.png instead of http://localhost:8000/storage/private/myfile.png
What i'm doing wrong? Thank you very much.
I would also like to know if there is a way to hook a custom function instead downloading the file directly from the CRUD view. My files are encrypted and i need a controller that cares about decrypting before sending the files to the user.
Method url() is still not usable for the files are placed in subdirectories.
You may also use the storage_path function to generate a fully qualified path to a given file relative to the storage directory:
$app_path = storage_path('app');
$file_path = storage_path('app/file.txt');
In reference to Issue #13610
The following works for version 5.3:
'my-disk' => [
'driver' => 'local',
'root' => storage_path(),
'url' => '/storage'
],
\Storage::disk('my-disk')->url('private/myfile.png')
this should return "/storage/private/myfile.png"

Laravel download not working

In my application I have the need to:
upload a file
store information in the db
store the file in a local or remote filesystem
listing all the db rows with a link to download the file
remove the file from the db and from the filesystem
I am trying to develop the 4th but the solutions found here and here don't work for me.
My filesystem.php is:
'local' => [
'driver' => 'local',
'root' => storage_path('app'),
],
'public' => [
'driver' => 'local',
'root' => storage_path('app/public'),
'visibility' => 'public',
],
'myftpsite' => [
'driver' => 'ftp',
'host' => 'myhost',
'username' => 'ftpuser,
'password' => 'ftppwd',
// Optional FTP Settings...
// 'port' => 21,
'root' => '/WRK/FILE/TEST',
// 'passive' => true,
// 'ssl' => true,
// 'timeout' => 30,
],
In the Controller I store the file with:
... validation here ...
$path = $request->uploadfile->storeAs('', $request->uploadfile->getClientOriginalName(), self::STORAGEDISK);
$file = new TESTFile;
... db code here ...
$file->save();
At this point I would like to retrive the variable to pass to the download methods (url or path of my file). I found 2 ways
Storage::url($pspfile->filename) *return* **/storage/** accept.png
Storage::disk(self::STORAGEDISK)->getDriver()->getAdapter()->applyPathPrefix($pspfile->filename) *return* C:\xampp\htdocs\myLaravel\ **storage** \app\accept.png
Any help or suggestion to do it in a better way will be very appreciated.
EDIT
For the moment I separete local/public from FTP.
The download is working if in the Controller I modify
$path = $request->uploadfile->storeAs('',
$request->uploadfile->getClientOriginalName()
,self::STORAGEDISK);
$file->fullpath = $path;
with
$file->fullpath = storage_path('app\\') . $path;
where 'app\' is the storage_path configured as root in filesystem.php
Moreover I can avoid to hardcode and use
$file->fullpath = Storage::disk(self::STORAGEDISK)
->getDriver()
->getAdapter()
->getPathPrefix() . $path;
In this way the download method can use
return response()->download($pspfile->fullpath);
I am still looking for a way to retrive a valid scr attribute for an img tag.
In addition I would like the same with remote stored files (maybe with local temp dir and file?)
I made something similar some time ago. Maybe this example code helps you.
class FileController extends Controller
{
// ... other functions ...
public function download(File $file)
{
if (Storage::disk('public')->exists($file->path)) {
return response()->download(public_path('storage/' . $file->path), $file->name);
} else {
return back();
}
}
public function upload()
{
$this->validate(request(), [
'file-upload' => 'required|file',
]);
$path = request()->file('file-upload')->store('uploads', 'public');
$file = new File;
$file->name = request()->file('file-upload')->getClientOriginalName();
$file->path = $path;
$file->save();
return back();
}
}

Resources