Cannot upload image to laravel from react-native - laravel

I'm trying to let the user upload an image through react-native, but apparently, laravel is not being able to read any value from the request. This is what I'm trying to do with axios:
const data = new FormData()
data.append('subject_id', this.props.navigation.getParam('id'))
data.append('name', this.state.title)
// I don't think the path is enough, it will probably just send the path as a string instead of the image. You need to load the actual file and append that
data.append('image', {
uri: this.state.image,
type: 'image/jpeg',
name: 'image'
});
data.append('progress', this.state.progress * 100)
data.append('description', this.state.description)
data.append('date', this.state.date)
axios.post('https://example.com/api/auth/storeTask', data, {
headers: {
'Authorization': access,
"Content-Type": "multipart/form-data"
},
}).then(result => { })
.catch(err => console.warn)
The image is not found when I try to access the resource.

You should use a FormData object:
const data = new FormData()
data.append('subject_id', this.props.navigation.getParam('id'))
data.append('name', this.state.title)
// I don't think the path is enough, it will probably just send the path as a string instead of the image. You need to load the actual file and append that
data.append('image', this.state.image)
data.append('progress', this.state.progress * 100)
data.append('description', this.state.description)
data.append('date', this.state.date)
axios.post('https://example.com/api/auth/storeTask', data, {
headers: {
'Authorization': access,
"Content-Type": "multipart/form-data"
},
}).then(result => {})
.catch(err => console.warn)

You didn't send complete info like responses and logs, by the way,
Please check this instruction:
make sure your CSRF in verifyCSRFtoken is allowed
use FormData to upload your file
your code coulde be like this:
import axios, { post } from 'axios';
const url = '/uploadPic';
const formData = new FormData();
formData.append("image", {
name: this.state.photo.fileName,
type: this.state.photo.type,
uri: this.state.photo.uri,
});
const config = {
headers: {
'content-type': 'multipart/form-data'
}
}
const config = {
headers: {
'content-type': 'multipart/form-data'
}
}
return post(url, formData,config)
for react native:
if you are in production and using react-native bare, you should add
<application
...
android:usesCleartextTraffic="true"
...
to your android file.

Related

How to post/send an image to an API using Axios?

I am trying to post/send an image to an API through axios.
Here is my frontend code (ReactJS):
const handleImage = (e) => {
const myImg = e.target.files[0];
const config = {
headers: {
"Content-Type": "multipart/form-data"
}
};
if (myImg !== undefined) {
let form = new FormData();
form.append("file", myImg);
axios.post("/upload", form, config)
.then(res => console.log(res))
.catch(err => console.log(err));
}
}
Here is my backend code (NodeJS & ExpressJS):
app.post("/upload", (req, res) => {
console.log(req.body);
res.send(req.body);
});
console.log(req.body) printing an empty object i.e. {} on console window.
So, in short, my doubt is why its printing an empty object? Is there something that I am missing in my code?
This is probably because your backend is not ready to receive files upload.
You can use a library called Multer which will make easier setting up your backend for supporting files upload.
There is a lot of content explaining how to use Multer. You can check this one out

Get image from blob Laravel vue

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!

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));

Saving blob image in laravel's controller

In my Laravel 5/vuejs 2.6 I upload an image with the vue-upload-component and am sending a requested image blob
I try to save it with the controller code like :
if ( !empty($requestData['avatar_filename']) and !empty($requestData['avatar_blob']) ) {
$dest_image = 'public/' . Customer::getUserAvatarPath($newCustomer->id, $requestData['avatar_filename']);
$requestData['avatar_blob']= str_replace('blob:','',$requestData['avatar_blob']);
Storage::disk('local')->put($dest_image, file_get_contents($requestData['avatar_blob']));
ImageOptimizer::optimize( storage_path().'/app/'.$dest_image, null );
} // if ( !empty($page_content_image) ) {
As result, I have an image uploaded, but it is not readable.
The source file has 5 Kib, the resulting file has 5.8 Kib and in the browser's console I see the blobs path as
avatar_blob: "blob:http://local-hostels2.com/91a18493-36a7-4023-8ced-f5ea4a3c58af"
Have do I convert my blob to save it correctly?
MODIFIED :
a bit more detailed :
In vue file I send request using axios :
let customerRegisterArray =
{
username: this.previewCustomerRegister.username,
email: this.previewCustomerRegister.email,
first_name: this.previewCustomerRegister.first_name,
last_name: this.previewCustomerRegister.last_name,
account_type: this.previewCustomerRegister.account_type,
phone: this.previewCustomerRegister.phone,
website: this.previewCustomerRegister.website,
notes: this.previewCustomerRegister.notes,
avatar_filename: this.previewCustomerRegister.avatarFile.name,
avatar_blob: this.previewCustomerRegister.avatarFile.blob,
};
console.log("customerRegisterArray::")
console.log(customerRegisterArray)
axios({
method: ('post'),
url: window.API_VERSION_LINK + '/customer_register_store',
data: customerRegisterArray,
}).then((response) => {
this.showPopupMessage("Customer Register", 'Customer added successfully ! Check entered email for activation link !', 'success');
alert( "SAVED!!::"+var_dump() )
}).catch((error) => {
});
and this.previewCustomerRegister.avatarFile.blob has value: "blob:http://local-hostels2.com/91a18493-36a7-4023-8ced-f5ea4a3c58af"
where http://local-hostels2.com is my hosting...
I set this value to preview image defined as :
<img
class="img-preview-wrapper"
:src="previewCustomerRegister.avatarFile.blob"
alt="Your avatar"
v-show="previewCustomerRegister.avatarFile.blob"
width="256"
height="auto"
id="preview_avatar_file"
>
and when previewCustomerRegister.avatarFile.blob is assigned with uploaded file I see it in preview image.
I show control with saving function in first topic but when I tried to opened my generated file with kate, I found that it
has content of my container file resources/views/index.blade.php...
What I did wrong and which is the valid way ?
MODIFIED BLOCK #2 :
I added 'Content-Type' in request
axios({
method: ('post'),
url: window.API_VERSION_LINK + '/customer_register_store',
data: customerRegisterArray,
headers: {
'Content-Type': 'multipart/form-data'
}
but with it I got validation errors in my control, as I define control action with request:
public function store(CustomerRegisterRequest $request)
{
and in app/Http/Requests/CustomerRegisterRequest.php :
<?php
namespace App\Http\Requests;
use App\Http\Traits\funcsTrait;
use Illuminate\Foundation\Http\FormRequest;
use App\Customer;
class CustomerRegisterRequest extends FormRequest
{
use funcsTrait;
public function authorize()
{
return true;
}
public function rules()
{
$request= Request();
$requestData= $request->all();
$this->debToFile(print_r( $requestData,true),' getCustomerValidationRulesArray $requestData::');
/* My debugging method to write data to text file
and with Content-Type defined above I see that $requestData is always empty
and I got validations errors
*/
// Validations rules
$customerValidationRulesArray= Customer::getCustomerValidationRulesArray( $request->get('id'), ['status'] );
return $customerValidationRulesArray;
}
}
In routes/api.php defined :
Route::post('customer_register_store', 'CustomerRegisterController#store');
In the console of my bhrowser I see : https://imgur.com/a/0vsPIsa, https://imgur.com/a/wJEbBnP
I suppose that something is wrong in axios header ? without 'Content-Type' defined my validation rules work ok...
MODIFIED BLOCK #3
I managed to make fetch of blob with metod like :
var self = this;
fetch(this.previewCustomerRegister.avatarFile.blob) .then(function(response) {
console.log("fetch response::")
console.log( response )
if (response.ok) {
return response.blob().then(function(myBlob) {
var objectURL = URL.createObjectURL(myBlob);
// myImage.src = objectURL;
console.log("objectURL::")
console.log( objectURL )
console.log("self::")
console.log( self )
let customerRegisterArray =
{
username: self.previewCustomerRegister.username,
email: self.previewCustomerRegister.email,
first_name: self.previewCustomerRegister.first_name,
last_name: self.previewCustomerRegister.last_name,
account_type: self.previewCustomerRegister.account_type,
phone: self.previewCustomerRegister.phone,
website: self.previewCustomerRegister.website,
notes: self.previewCustomerRegister.notes,
avatar_filename: self.previewCustomerRegister.avatarFile.name,
avatar: objectURL,
};
console.log("customerRegisterArray::")
console.log(customerRegisterArray)
axios({
method: 'POST',
url: window.API_VERSION_LINK + '/customer_register_store',
data: customerRegisterArray,
// headers: {
// 'Content-Type': 'multipart/form-data' // multipart/form-data - as we need to upload with image
// }
}).then((response) => {
self.is_page_updating = false
self.message = ''
self.showPopupMessage("Customer Register", 'Customer added successfully ! Check entered email for activation link !', 'success');
alert( "SAVED!!::")
}).catch((error) => {
self.$setLaravelValidationErrorsFromResponse(error.response.data);
self.is_page_updating = false
self.showRunTimeError(error, this);
self.showPopupMessage("Customer Register", 'Error adding customer ! Check Details fields !', 'warn');
// window.grecaptcha.reset()
self.is_recaptcha_verified = false;
self.$refs.customer_register_wizard.changeTab(3,0)
});
});
} else {
return response.json().then(function(jsonError) {
// ...
});
}
}).catch(function(error) {
console.log('There has been a problem with your fetch operation: ', error.message);
});
In objectURL and self I see proper values : https://imgur.com/a/4YvhbFz
1) But checking data on server in laravel's control I see the same values I had at start of my attemps to upload image:
[avatar_filename] => patlongred.jpg
[avatar] => blob:http://local-hostels2.com/d9bf4b66-42b9-4990-9325-a72dc8c3a392
Have To manipulate with fetched bnlob in some other way ?
2) If I set :
headers: {
'Content-Type': 'multipart/form-data'
}
I got validation errors that my data were not correctly requested...
?
You're using request type as application/json hence you won't be able to save the image this way, for a file upload a request type should be multipart/form-data in this case you'll need to send request as
let customerRegisterArray = new FormData();
customerRegisterArray.put('username', this.previewCustomerRegister.username);
customerRegisterArray.put('email', this.previewCustomerRegister.email);
....
customerRegisterArray.put('avatar', this.previewCustomerRegister.avatarFile);
console.log("customerRegisterArray::")
console.log(customerRegisterArray)
axios({
method: ('post'),
url: window.API_VERSION_LINK + '/customer_register_store',
data: customerRegisterArray,
headers: {
'Content-Type': 'multipart/form-data'
}
}).then((response) => {
this.showPopupMessage("Customer Register", 'Customer added successfully !Check entered email for activation link !', 'success');
alert( "SAVED!!::"+var_dump() )
}).catch((error) => {});
Thank you for your help!
Valid decision was :
var self = this;
fetch(this.previewCustomerRegister.avatarFile.blob) .then(function(response) {
if (response.ok) {
return response.blob().then(function(myBlob) {
var objectURL = URL.createObjectURL(myBlob);
let data = new FormData()
data.append('username', self.previewCustomerRegister.username)
data.append('email', self.previewCustomerRegister.email)
data.append('first_name', self.previewCustomerRegister.first_name)
data.append('last_name', self.previewCustomerRegister.last_name)
data.append('account_type', self.previewCustomerRegister.account_type)
data.append('phone', self.previewCustomerRegister.phone)
data.append('website', self.previewCustomerRegister.website)
data.append('notes', self.previewCustomerRegister.notes)
data.append('avatar_filename', self.previewCustomerRegister.avatarFile.name)
data.append('avatar', myBlob)
axios({
method: 'POST',
url: window.API_VERSION_LINK + '/customer_register_store',
data: data,
headers: {
'Accept': 'application/json',
'Content-Type': 'multipart/form-data' // multipart/form-data - as we need to upload with image
}
}).then((response) => {
self.is_page_updating = false
self.message = ''
self.showPopupMessage("Customer Register", 'Customer added successfully ! Check entered email for activation link !', 'success');
alert( "SAVED!!::123")
// self.$router.push({path: '/'});
}).catch((error) => {
self.$setLaravelValidationErrorsFromResponse(error.response.data);
self.is_page_updating = false
self.showRunTimeError(error, this);
self.showPopupMessage("Customer Register", 'Error adding customer ! Check Details fields !', 'warn');
window.grecaptcha.reset()
self.is_recaptcha_verified = false;
self.$refs.customer_register_wizard.changeTab(3,0)
});
});
} else {
return response.json().then(function(jsonError) {
// ...
});
}
}).catch(function(error) {
console.log('There has been a problem with your fetch operation: ', error.message);
});
and common laravel's file uploading functionality :
$customerAvatarUploadedFile = $request->file('avatar');
...

Add custom headers to upload image

I'm currently trying to integrate the CKeditor 5 ReactComponent into my app.
I'm facing an issue with the upload image functionality... I use a Node/Express backend which uses a JWT auth middleware, so each request must have an Authorization header in order to pass.
I want to know if one of the following is possible:
a way to add a custom header to the component
a way to overwrite the upload handler and call a custom handler instead in which I can do what ever
Below is my code
<CKEditor
editor={ClassicEditor}
data="<p>Add product description here</p>"
onInit={(editor) => {
// You can store the "editor" and use when it is needed.
//console.log('Editor is ready to use!', editor);
}}
onChange={(event, editor) => {
const data = editor.getData();
this.handleData(data)
}}
config={{
ckfinder: {
uploadUrl: `${apiUrl}/upload/images/description`,
},
}}
/>
Thanks
try it with this code in property onInit
onInit={ editor => {
editor.plugins.get( 'FileRepository' ).createUploadAdapter = function( loader ) {
return new UploadAdapter( loader );
};
}}
after you must create the class UploadAdapter
class UploadAdapter {
constructor( loader ) {
// Save Loader instance to update upload progress.
this.loader = loader;
}
upload() {
const data = new FormData();
data.append('typeOption', 'upload_image');
data.append('file', this.loader.file);
return new Promise((resolve, reject) => {
axios({
url: `${API}forums`,
method: 'post',
data,
headers: {
'Authorization': tokenCopyPaste()
},
withCredentials: true
}).then(res => {
console.log(res)
var resData = res.data;
resData.default = resData.url;
resolve(resData);
}).catch(error => {
console.log(error)
reject(error)
});
});
}
abort() {
// Reject promise returned from upload() method.
}
}

Resources