Get image from blob Laravel vue - laravel

First of all, this is the start of where I am at as a similar post
Store blob as a file in S3 with Laravel
I am sending a photo from VueJS to Laravel. It is coming as multipart/form-data.
Vue Code:
export default {
emits: ['onClose'],
props: ['isOpen'],
data: function() {
return {
serverOptions: {
process: (fieldName, file, metadata, load, error) => {
const formData = new FormData();
formData.append(fieldName, file, file.name);
axios({
method: "POST",
url: '/chat/room/upload',
data: formData,
headers: {
"Content-Type": "multipart/form-data"
}
})
.then(() => {
load();
})
.catch(() => {
error();
});
}
},
files: [],
};
},
methods: {
handleFilePondInit: function () {
console.log('FilePond has initialized');
// example of instance method call on pond reference
this.$refs.pond.getFiles();
console.log(this.$refs.pond.getFiles());
},
},
Laravel Controller:
public function uploadImage(Request $request)
{
// This is what this is SUPPOSED to do. Grab the file from the frontend
// Bring it here. Store it in S3, return the path with the CDN URL
// Then store that URL into the DB as a message. Once that is done, then
// Broadcast the message to said room.
if ($request->has('upload')) {
$files = $request->get('photo');
$urls = [];
foreach ($files as $file) {
$filename = 'files/' . $file['name'];
// Upload File to s3
Storage::disk('digitalocean')->put($filename, $file['blob']);
Storage::disk('digitalocean')->setVisibility($filename, 'public');
$url = Storage::disk('digitalocean')->url($filename);
$urls[] = $url;
}
return response()->json(['urls' => $urls]);
}
// broadcast(new NewChatMessage($newMessage))->toOthers();
// return $newMessage;
}
First: I want to state that if there is something wrong with the current code, just know its because ive been playing around with this for 3 hours now and been trying anything. I am sure at one point I had it close but somehow screwed it up along the way so I am more looking for fresh eyes to show me my error.
That being said, the other part to take into account is in DevTools under Network I can clearly see the blob and can load it up, I can also see the "upload" item and under there the form data which shows the following
------WebKitFormBoundary7qD7xdmiQO9U1Ko0
Content-Disposition: form-data; name="photo"; filename="6A8B48B4-F546-438E-852E-C24340525C20_1_201_a.jpeg"
Content-Type: image/jpeg
------WebKitFormBoundary7qD7xdmiQO9U1Ko0--
it clearly also shows photo: (binary) so I am completely confused as to what I am doing wrong. The ULTIMATE goal here is to get the image, store it as public in S3/DigitalOcean then grab the public URL to the file and store in the DB.
Any help would be GREATLY appreciated!

Related

How to POST correctly a form that have data and files with VueJS, Axios and Laravel?

I am posting here as a beginner of VueJS and Laravel. I am stuck with a problem that I can't fix by myself after hours of search.
I would like to know how correctly send and get back the inputs of a form (complex data and files).
Here is the submit method of the form:
onSubmit: function () {
var formData = new FormData();
formData.append("data", this.model.data);
formData.append("partData", this.model.partData);
if (this.model.symbolFile != null) {
formData.append("symbolFile", this.model.symbolFile);
}
if (this.model.footprintFile != null) {
formData.append("footprintFile", this.model.footprintFile);
}
axios
.post("/api/updatecomponent", formData, {
headers: {
"Content-Type": "multipart/form-data",
},
})
.then((res) => {
// do something with res
// console.log(res);
})
.catch((err) => {
/* catch error*/
console.log(err);
});
},
The variable Data and PartData contains multiple string fields which will be stored in different tables in my database. Example :
Data
{
string Value,
string Tolerance,
string Power
}
Here is the method of the Controller in the server side:
public function updateComponent(Request $req)
{
$data = $req->input('data');
$partData = $req->input('partData');
$symbolFile = $req->file('symbolFile'); // is null if the user did not modify the symbol
$footprintFile = $req->file('symbolFile'); // is null if the user did not modify the footprint
// etc...
}
I am able to get the files, everything work for that and I can store and read them :)
But, the problem is that I am unable to get back properly my Data or PartDat.
When I do :
dd($partData);
I got as result in the console:
"[object Object]"
I am almost sure that I don't use correctly the FormData but after hours of search, I can't find the good way I should gave the Data and PartData to the FormData.
My code was working well for Data and PartData until I add FormData to support the file upload :(
Thank you for your help :)
Here my working code:
Client side:
var formData = new FormData(); // create FormData
formData.append("subcat", this.subcategory);// append simple type data
formData.append("data", JSON.stringify(this.model.data));// append complex type data
axios // send FormData
.post(url, formData, {
headers: {
"Content-Type": "multipart/form-data",
},
})
.then((res) => {
// do something with res
// console.log(res);
})
.catch((err) => {
/* catch error*/
console.log(err);
});
Server side:
public function createComponent(Request $req)
{
$subcategory = $req->input('subcat'); // get the input parameter named 'subcat' (selected subcategory)
$data = json_decode($req->input('data'), true); // get the input, decode the jason format, force to return the result as an array
}
I hope it will help other peoples :)
Simple solution
let data = new FormData();
data.append('image',file_name.value);
_.each(form_data, (value, key) => {
data.append(key, value)
})
console.log('form data',data);
Now you can get data in laravel controller like:
$request->title
$request->description
$request->file

how to upload image in register API in strapi?

In defaut registration API, I need to uplaod the image of user in registration API. So how could I manage it ? I'm sending in a formData and it works fine. I can see (binary) in network.
I tried to add image field and it works in admin panel but from API side I tried to send the file in key names like files, profileImage.
I didn't get the error in res. I got success in res.
Issue: When I reload the admin panel, I didn't get user's profile image.
Try this way. I used in react and it works fine for me.
signUpHandler = () => {
console.log("SignUp data ::: ", this.state);
let data = {
username: this.state.signUpForm.username.value,
phone: this.state.signUpForm.phone.value,
email: this.state.signUpForm.email.value,
password: this.state.signUpForm.password.value
}
axios.post('http://0.0.0.0:1337/auth/local/register', data)
.then(res => {
console.log(res);
return res.data.user.id;
})
.then(refId =>{
const data = new FormData();
data.append('files', this.state.selectedFile);
data.append('refId', refId);
data.append('ref', 'user');
data.append('source', 'users-permissions');
data.append('field', 'profileImage');
return axios.post('http://0.0.0.0:1337/upload', data)
})
.then(res =>{
console.log(res);
alert("You registered successfully...");
this.props.history.push('/login');
})
.catch(error =>{
console.log(error);
})
}
First, you will have to customize your user-permission
To do so, you will have to understand this concept: https://strapi.io/documentation/3.0.0-beta.x/concepts/customization.html
Then you will have to find the function you want to update - in your case, the register function.
And tada here it is https://github.com/strapi/strapi/blob/master/packages/strapi-plugin-users-permissions/controllers/Auth.js#L383.
So you will have to create ./extensions/users-permissions/controllers/Auth.js with the same content as the original file.
Then you will have to add
const { parseMultipartData, sanitizeEntity } = require('strapi-utils');
const uploadFiles = require('strapi/lib/core-api/utils/upload-files');
on the top of your file.
And in your function use this
const { data, files } = parseMultipartData(ctx); to parse data and files.
Then you will have to replace ctx.request.body by data to make sure to use the correct data.
After that you will have to add this after the user creation line
https://github.com/strapi/strapi/blob/master/packages/strapi-plugin-users-permissions/controllers/Auth.js#L510
if (files) {
// automatically uploads the files based on the entry and the model
await uploadFiles(user, files, { model: strapi.plugins['users-permissions'].models.user })
}
Solution for Strapi v4:
var myHeaders = new Headers();
myHeaders.append("Authorization", "Bearer XXXX");
var formdata = new FormData();
formdata.append("files", fileInput.files[0], "XXX.png");
formdata.append("refId", "46");
formdata.append("field", "image");
formdata.append("ref", "plugin::users-permissions.user");
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: formdata,
redirect: 'follow'
};
fetch("http://localhost:1337/api/upload", requestOptions)
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log('error', error));

Unable to read filelist object in Laravel controller from vue

I'm creating an application where user is filing up a form with possibility to send multiple files along
In vue.js I'm creating formData with an array of files and with an object with the rest of inputs fields. I'm posting that with Axios.
In request in Laravel controller I can't access my filelist-object.
I can see the
$request->My_Array,
but I can read the data store inside
I have tried to use loops also I have try :
$request->all();
$request->file('files');
My input
<input class="browse" V-on::change="onImageChange" type="file">
My vue.js component
onImageChange(event) {
this.files.push(event.target.files);
},
submit(e) {
e.preventDefault();
let currentObj = this;
const fd = new FormData();
for (let i = 0; i < this.files.length; i++) {
fd.append('IoFiles[]', this.files[i]);
}
console.log(this.files);
fd.append('IoFiles', this.files);
fd.append('fields', JSON.stringify(this.fields));
axios.post('/io',
fd,
{headers: {'Content-Type': 'multipart/form-data'}})
.then(function (response) {
currentObj.output = response.data;
})
.catch(function (error) {
currentObj.output = error;
});
},
My Laravel controller
public function store(Request $request)
{
if ($request->IoFiles) {
$medias = $request->IoFiles;
foreach ($medias as $image) {
return $image->getClientOriginalName();//That give me an error
}
}
}
There are a couple of issues with your code.
Firstly, V-on::change="onImageChange" should be:
v-on:change="onImageChange"
Please note:
the lowercase v for v-on
the single :
Alternatively, you could write #change="onImageChange".
Secondly, event.target.files returns a FileList not a single file so you need to change your onImageChange code to the following be able to get the file itself:
onImageChange(event) {
this.files.push(event.target.files[0]); //Note the [0] after files
},

Laravel / vue-froala-wysiwyg integration

I'll like to implemente the image upload system within my Laravel/VueJS project but I can't find a right way to do so. How can I set up my Controller function in order to handle this upload?
Edit:
This is my Editor configuration:
config: {
imageUploadParam: 'imageFile',
imageUploadURL: '/froala/upload/image',
imageUploadMethod: 'POST',
imageMaxSize: 5 * 1024 * 1024,
imageAllowedTypes: ['jpeg', 'jpg', 'png'],
}
And this is the function that handles the request:
public function uploadImage(Request $request)
{
$file = $request['imageFile'];
$name = $file->getClientOriginalName();
$name = strtolower(str_replace(' ', '', $name));
$path = $file->hashName();
$image = Image::make($file);
Storage::put("/threads/{$path}", (string) $image->encode());
$multimedia = Multimedia::create([
'name' => $name,
'path' => $path
]);
return ['link' => $multimedia->path];
}
I am using the Intervention Image library to handle the image upload.
Edit 2:
I'm getting an 419 error related with the csrf token. So, how can i pass it to the function? I know how to get it but using the imageUploadParams configuration of the editor is not working:
imageUploadParams: {
csrf: this.csrf
}
csrf: document.querySelector('meta[name="csrf-token"]').getAttribute('content'),
You need to pass the correct X-CSRF-TOKEN value to avoid the 419 error.
First check that you have the token defined the in the meta header with something like:
<meta name="csrf-token" content="{{ csrf_token() }}">
Early in your VueJS add:
var csrf_token = $('meta[name="csrf-token"]').attr('content');
Then add the following to your Froala config section:
config: {
requestHeaders: {
'X-CSRF-TOKEN': csrf_token
},
Media files should now pass through to your media upload function in Laravel.
From the documentation :
When an image is inserted into the WYSIWYG HTML editor, a HTTP request is automatically done to the server.
The specific URL that the request will be made to can be specified using the imageUploadURL config option.
Setup your routes.php file to properly direct the request to your controller of choice :
Route::post('/upload', 'FilesController#store');
Then, in your controller you can handle the image upload like you would normally. The important part is that you return the path to the file after you've saved it.
The returned JSON needs to look like: { "link": "path/to/image.jpg" }
Here is an example of what that could look like :
public function store(){
$filepath = request()->file('file')->store('images', 'public');
return ['link' => $filepath];
}
Of course, feel free to do any kind of validation or processing that you need.
instand of
imageUploadParams: {
csrf: this.csrf
}
use this
imageUploadParams: {
_token: this.csrf
}
Check this out From Documentation

Angularjs multiple ajax requests optimization

I am still learning Angular JS and have this controller which is making two ajax requests to the lastfm api using different parameters. I want to know when each request has been finished, so that I can display a loading indicator for both requests. I have researched it and read about promises and the $q service but cant get my head around how to incorporate it into this. Is there a better way to set this up? and how can I know when each request is done. Thanks.
angular.module('lastfm')
.controller('ProfileCtrl', function ($scope, ajaxData, usersSharedInformation, $routeParams) {
var username = $routeParams.user;
//Get Recent tracks
ajaxData.get({
method: 'user.getrecenttracks',
api_key: 'key would go here',
limit: 20,
user: username,
format: 'json'
})
.then(function (response) {
//Check reponse for error message
if (response.data.message) {
$scope.error = response.data.message;
} else {
$scope.songs = response.data.recenttracks.track;
}
});
//Get user info
ajaxData.get({
method: 'user.getInfo',
api_key: 'key would go here',
limit: 20,
user: username,
format: 'json'
})
.then(function (response) {
//Check reponse for error message
if (response.data.message) {
$scope.error = response.data.message;
} else {
$scope.user = response.data.user;
}
});
});
I have this factory which handles all the requests
angular.module('lastfm')
.factory('ajaxData', function ($http, $q) {
return {
get: function (params) {
return $http.get('http://ws.audioscrobbler.com/2.0/', {
params : params
});
}
}
});
Quite easy using $q.all(). $http itself returns a promise and $q.all() won't resolve until an array of promises are resolved
var ajax1=ajaxData.get(....).then(....);
var ajax2=ajaxData.get(....).then(....);
$q.all([ajax1,ajax2]).then(function(){
/* all done, hide loader*/
})

Resources