How to store file in laravel PHP - php

Language used : js with react - redux-toolkit and php with laravel
I'm trying to save my file in my mongodb database
first of all, here my input file and axios function to post from client (react) to server(laravel) . (it's working, i received the data in php)
import React from 'react';
export const Attach = ({ register, setValue }) => {
const handleFile = (e) => {
setValue('Attachment', e.target.files[0]);
};
return (
<div >
<label >Insert a file </label>
<input type="file" name="file" onChange={(e) => handleFile(e)} />
</div>
);
};
and my axios post function
export const postOffers = (data) => (dispatch) => {
axios({
method: 'post',
url: `${process.env.REACT_APP_API_URL}offer`,
data: {
Type: Type,
UserName: data.UserName,
Object: data.Object,
Address: data.Address,
Comment: data.Comment,
Attachment: data.Attachment,
},
}).then((res) => {
if (!res.data) {
console.log('error form');
} else {
console.log(data.Attachment);
}
});
};
-> console.log(data.Attachment);
then in my php controller :
public function createOffers(Request $request)
{
if ($request) {
//what i have tried
//upload file
$bucket = InternOffer::getMongoDB()->selectGridFSBucket();
$file = $request->file('Attachment');
$resource = fopen($file, "a+");
$file_id = $bucket->uploadFromStream($file, $resource);
$InternOffer = InternOffer::create([
'Type' => $request->get('Type'),
"UserName" => $request->get('UserName'),
'Object' => $request->get('Object'),
'Address' => $request->get('Address'),
'Comment' => $request->get('Comment'),
// 'Attachment' => $file_id, (working if i don't pass the attachment)
]);
if ($InternOffer) {
$InternOffer->save();
return ["result" => "Offers has been successfully created"];
} else {
return ["result" => "failed"];
}
}
}

Related

PHP - Laravel is not storing files from request although the response is 200

Trying to upload a photo locally using Laravel with Vuejs
I am sending the file from the Vue component to the backend like the code below:
<div class="form-group">
<label for="photo">photo</label>
<input
type="file"
class="form-control"
id="photo"
name="photo"
ref="inputFile"
/>
<hr />
</div>
<button
type="submit"
class="btn btn-primary">
Add
</button>
</form>
and this is the script in the same component
import { mapActions } from "vuex";
export default {
data() {
return {
category: {
photo: this.$refs.inputFile,
csrf: document.querySelector('meta[name="csrf-token"]').getAttribute('content'),
config: {
headers: { 'content-type': 'multipart/form-data' }
}
},
};
},
methods: {
...mapActions(["createCategory"]),
submitForm() {
const form_data = new FormData();
form_data.append('photo', this.category.photo);
form_data.append('csrf', this.category.csrf);
// The following method is the mapped action
this.createCategory(form_data);
}
},
};
</script>
The mutations.js file
createCategory(state, category) {
axios.post('http://127.0.0.1:8000/api/categories', category).then(res => {
console.log("Response: " + res);
}).catch(res => {
console.log("Exp: " + res);
});
}
The actions.js file
createCategory(context, category) {
context.commit('createCategory', category);
}
At the backend I am using categories driver in
> filesystems.php as the following:
'categories' => [
'driver' => 'local',
'root' => base_path() . '/images/categories',
'url' => env('APP_URL').'/public',
'visibility' => 'public',
],
uploading the file using $request->photo->store method as the code in the following Controller
public function store(CategoryRequest $request) {
try {
// Start Uploading File
$file = "";
if($request->has('photo')) {
$file = $request->photo;
$folder = 'categories';
$file->store('/', $folder);
$filename = $file->hashName();
$path = 'images/' . $folder . '/' . $filename;
}
// End Uploading File
// Start creating category
$category = new Category();
$category->photo = $path;
$category->save();
// End creating category
return response()->json(['message' => 'Created Successfully'], 200);
} catch(\Exception $ex) {
return $ex;
}
}

retrieving multiparts/ form data from angular to laravel php RESTfull api

I have an app developed using ionic angular and I want to upload files and send to laravel php
here I what I have done but this not working.
Here is my submit form in ionic angular :
async submitForm(){
let options = {headers: new HttpHeaders({
'Content-Type': 'multi-part/formdata',
}) };
let formData= new FormData();
formData.append("photo",this.file, this.file.name);
// console.log(formData)
this.http.post<any>(this.env.API_URL + 'auth/form', formData, options).subscribe(
data => {
this.alertService.presentToast("تم رفع الملفات بنجاح");
},
error => {
console.log(error);
},
)
laravel side:
public function apistore(Request $request)
{
$user = Auth::user()->id;
$this->validate($request, [
// 'photo' => 'required',
]);
$image = $request->{'photo'};
if($image->hasFile('photo'))
{
$file=$image->file('photo');
$filename = $file->getClientOriginalName();
$extension = $file->getClientOriginalExtension();
$picture = date('His').'-'.$filename;
$file->move(public_path().'/attach/images', $picture);
}
$attachments= new attachments();
$attachments->filename=$image;
$attachments->user_id = Auth::user()->id;
$attachments->take_image = $request->{'take_image'};
$attachments->save();
return response()->json([
'success' => true,
'data' => $attachments->toArray(),
'message' => 'Data updated'
]);
}
I usually retrieve data from ionic like this and it is working
$job_info->job = $request->{'job_info.job'};

"Call to a member function store() on array" When Uploading a File using Laravel 8 with Jetstream - Vue & Intertia.js

I am having a problem uploading an image from a from a form in a vue file. I tried several ways to do this but it seems the file is not properly being set.
I have set "enctype="multipart/form-data" in my form tag
Here is my input element:
<input
#change="onFileChange"
type="file"
accept="image/*"
class="form-control"
name="file"
id="file"
aria-describedby="helpId"
placeholder="Upload a file"
/>
Here is my data objetcs and methods that send the data:
data() {
return {
editMode: false,
professionaldevelopmentitems: [],
professionaldevelopmentitem: {
domain: 1,
domaincategory: 1,
title: "",
dateofpd: "",
location: "",
lengthofpd: "",
facilitatorname: "",
facilitatorcredentials: "",
reflection: "",
file: "",
},
};
},
methods: {
onFileChange(e) {
alert(e.target.files[0]);
alert(e.target.files[0].name);
var files = e.target.files || e.dataTransfer.files;
if (!files.length)
return;
this.professionaldevelopmentitem.file = e.target.files[0];
alert(this.professionaldevelopmentitem.file);
},
async addProfessionalDevelopmentItem() {
document.getElementById("pdForm").reset();
this.editMode = false;
const res = await axios.post(
"/api/professionaldevelopmentitems",
this.professionaldevelopmentitem
);
if (res.status === 201) {
Toast.fire({
icon: "success",
title: res.data,
});
document.getElementById("pdForm").reset();
$("#manageProfessionalDevelopmentItem").modal("hide");
Fire.$emit("modifiedPDItem");
}
},
async editProfessionalDevelopmentItem(data) {
this.professionaldevelopmentitem = Object.assign({}, data);
this.editMode = true;
},
async updateProfessionalDevelopmentItems(data) {
const res = await axios.put(
`/api/professionaldevelopmentitems/${data.id}`,
this.professionaldevelopmentitem
);
if (res.status === 200) {
Toast.fire({
icon: "success",
title: res.data,
});
document.getElementById("pdForm").reset();
$("#manageProfessionalDevelopmentItem").modal("hide");
Fire.$emit("modifiedPDItem");
this.editMode = false;
}
},
I receive data in my controller and try to store the file:
public function update(Request $request, $id)
{
dd($request->all());
$this->validate($request, [
'title' => ['required'],
'dateofpd' => ['required'],
'lengthofpd' => ['required'],
'location' => ['required']
]);
$path = $request->file('filename')->store('uploads');
$pditem = ProfessionalDevelopmentItem::find($id);
$pditem->domain = $request->domain;
$pditem->domaincategory = $request->domaincategory;
$pditem->title = $request->title;
$pditem->dateofpd = $request->dateofpd;
$pditem->lengthofpd = $request->lengthofpd;
$pditem->location = $request->location;
$pditem->facilitatorname = $request->facilitatorname;
$pditem->facilitatorcredentials = $request->facilitatorcredentials;
$pditem->certificategranted = $request->certificategranted;
$pditem->certificateexpires = $request->certificateexpires;
$pditem->certificateexpiration = $request->certificateexpiration;
$pditem->reflection = $request->reflection;
$pditem->nameofinstitution = $request->nameofinstitution;
$pditem->coursename = $request->coursename;
$pditem->coursecode = $request->coursecode;
$pditem->hoursofinstruction = $request->hoursofinstruction;
$pditem->creditgranted = $request->creditgranted;
$pditem->bookname = $request->bookname;
$pditem->bookauthor = $request->bookauthor;
$pditem->bookyear = $request->bookyear;
$pditem->bookpublisher = $request->bookpublisher;
$pditem->otherdescription = $request->otherdescription;
$pditem->filename = $path;
$pditem->save();
return response('Successfully Updated the Professional Development Item.', 200);
}
the response back is an error on the line when it tries to store the file:
"message": "Call to a member function store() on array",
"exception": "Error",
Any thoughts on what I am dong wrong would be appreciated.
Try sending the uploaded file within FormData. Define a method in the Vue component to prepare the FormData with all data you want to send via ajax to the server
prepareFormData() {
let data = new FormData;
Object.keys(this.professionaldevelopmentitem).forEach(
key => data.append(key, this.professionaldevelopmentitem[key]
);
return data;
}
Then use this method to get the FormData and send it as data to the server in addProfessionalDeveloomentItem and updataProfessionalDevelopmentItems
async addProfessionalDevelopmentItem() {
document.getElementById("pdForm").reset();
this.editMode = false;
const res = await axios.post(
"/api/professionaldevelopmentitems",
this.prepareFormData()
);
if (res.status === 201) {
Toast.fire({
icon: "success",
title: res.data,
});
document.getElementById("pdForm").reset();
$("#manageProfessionalDevelopmentItem").modal("hide");
Fire.$emit("modifiedPDItem");
}
},
async updateProfessionalDevelopmentItems(data) {
const res = await axios.put(
`/api/professionaldevelopmentitems/${data.id}`,
this.prepareFormData()
);
if (res.status === 200) {
Toast.fire({
icon: "success",
title: res.data,
});
document.getElementById("pdForm").reset();
$("#manageProfessionalDevelopmentItem").modal("hide");
Fire.$emit("modifiedPDItem");
this.editMode = false;
}
}
Then you should get the uploaded file in the $request under key file $request->file('file')
This error means that $request->file('filename') returns array. In our case it's because we allowed users to submit 2 files at once:
<form action="/upload" method="post" enctype="multipart/form-data">
#csrf
<input type="file" name="filename[]"><br>
<input type="file" name="filename[]"><br>
<input type="submit">
</form>
To fix this in Laravel 9 we added the type check of the variable in the controller's method:
public function upload(Request $request)
{
$file = $request->file('filename');
if (is_array($file)) {
foreach ($file as $item) {
$item->store('uploads');
}
} else {
$file->store('uploads');
}
// ...
}

React Native images save to php (laravel) server

I'm trying to save image to php application (made with laravel 6.0) using React Native. Here is my react native image picker
var ImagePicker = NativeModules.ImageCropPicker;
here is my image save function
addImages = async () => {
const { image, images } = this.state
const access_token = await AsyncStorage.getItem('access_token')
try {
let data = new FormData();
images.map((image, i) => {
data.append('id', id);
data.append('uri', image.uri);
data.append('type', image.mime);
data.append('name', 'test.jpg');
});
fetch(apiConfig.apiUrl + '/api/save-image', {
method: 'POST',
headers: {
'Content-Type' : 'multipart/form-data',
'Authorization': 'Bearer ' + access_token,
},
body:data
})
.then(function (response) {
return response.json();
})
.then(function (data) {
try {
console.log(data);
} catch (error) {
console.log(error);
}
}.bind(this))
.catch((error) => {
console.log(error)
});
}catch (error) {
console.log(error)
}
}
Here is my php code
public function saveImage(Request $request)
{
header( "Access-Control-Allow-Methods' => 'POST, GET, OPTIONS, PUT, DELETE");
header("Access-Control-Allow-Origin: *");
try {
$file= array('file'=>$request->uri);
Storage::disk('public')->put($request->imgName,File::get($file->file));
return response()->json(['true'=>'Successfully Created'], 200);
} catch (\Exception $e) {
Log::info('vehicle image: ', [$e->getMessage()]);
return response()->json(['error'=>$e], 200);
}
}
When I try to save I'm getting SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data.
when I return the $request->uri I'm getting something like this file:///data/user/0/com.carup/cache/react-native-image-crop-picker/IMG_20191103_161929.jpg
How can I fix this?
How can I fix this?
You need to specify file name as the third parameter to data.append:
data.append('file', image.uri, 'test.jpg');
Finally I have fixed it with Base64 method. Here is my code.
pick images with base64
pickMultipleBase64=()=> {
ImagePicker.openPicker({
multiple: true,
width: 300,
height: 300,
includeBase64: true,
includeExif: true,
}).then(images => {
this.setState({
images: images.map(image => {
return {uri: `data:${image.mime};base64,`+ image.data, width: image.width, height: image.height,type:image.mime}
}),
});
}).catch(e => alert(e));
}
And uploaded with other details like this
addImages = async () => {
const { image, images, stockNo } = this.state
const access_token = await AsyncStorage.getItem('access_token')
if(access_token == null) {
return(
this.gotoLogin()
)
}
this.setState({
isLoading:true,
message:'',
status:true
})
try {
let data = new FormData();
images.map((image, i) => {
data.append('id', id);
data.append('stock', stockNo);
data.append('chassis', chassis_no);
data.append('file'+i, this.state.images[i].uri);
data.append('type'+i, this.state.images[i].type);
imageCount++
});
data.append('imageCount', imageCount);
// console.log(data);
fetch(apiConfig.apiUrl + '/api/save-image', {
method: 'POST',
headers: {
'Authorization': 'Bearer ' + access_token,
},
body:data
})
.then(function (response) {
return response.json();
})
.then(function (data) {
console.log(data);
imageCount = 0
try {
this.setState({
isLoading: false,
message:data.true ? data.true:data.error,
messageColor:data.true ? CarColors.success : CarColors.error,
btnStatus:true
// chassis:''
})
if(data.true){
this.setState({
image:null,
images: null,
})
}
} catch (error) {
this.removeToken();
console.log('1 '+error);
}
}.bind(this))
.catch((error) => {
this.setState({
isLoading: false,
message:'error',
messageColor:CarColors.error,
})
console.log(error)
});
}catch (error) {
console.log(error)
}
And my php(laravel) code is like this. Here I have created a new folder (with vehicle id) in storage and save images to separate folders.
public static function saveImage($request)
{
$dir = "./storage/vehicle/" . $request->id;
if (is_dir($dir) === false) {
mkdir($dir);
}
DB::beginTransaction();
try {
for ($i = 0; $i < $request->imageCount; $i++) {
$type = [];
$file = 'file' . $i;
$mime = 'type' . $i;
$data = $request->$file;
$type = explode('/', $request->$mime);
$extension = $type[1];
list($type, $data) = explode(';', $data);
list(, $data) = explode(',', $data);
$data = base64_decode($data);
$Imgdata =Images::create([
'vehicle_id' => $request->id,
'img_name' => $i.'.'.$extension,
'img_ext' => $extension,
'img_order' => '0',
]);
Storage::disk('vehicle')->put($request->id . '/' . $i . '.' . $extension, $data);
}
//Update Vehicle table ImageStatus
$Vehicle = Vehicle::where('id',$request->id)->update([
'img_status' => '1',
]);
return response()->json(['true' => 'Successfully Uploaded'], 200);
} catch (\Exception $e) {
DB::rollback();
Log::info('vehicle image name save issue: ', [$e->getMessage()]);
return 'false';
}
}
Hope this will help others who are going to upload multiple images with react native

Stripe with ajax so the user is not redirected to another page

I have a multistep form, in the step 3 there is a button "Pay" that when is clicked it shows a Stripe modal using the jQuery below:
<form action="{{ route('registration.charge') }}" method="post" id="paymentForm">
{{csrf_field()}}
<input type="hidden" name="stripeToken" id="stripeToken"/>
<input type="submit" href="" id="payment" class="btn btn-primary float-right"
value="Pay"/>
</form>
Charge method to handle the Stripe charge:
public function charge(Request $request)
{
Stripe::setApiKey(config('services.stripe.secret'));
$source = $request->stripeToken;
Charge::create([
'currency' => 'eur',
'description' => 'Example charge',
'amount' => 2500,
'source' => $source,
]);
}
Route:
Route::post('/charge', [
'uses' => 'RegistrationController#charge',
'as' => 'registration.charge'
]);
When the user clicks in pay the stripe modal appears the user fills the form and click in Pay button the Stripe validates and send the token and the user is redirected to another page (http://proj.test/charge) because of the charge().
Do you know how to instead of redirecting the user to (http://proj.test/charge) change Stripe code to use Ajax so the user remains on the same page? So that is possible to show in that some page a success message, for example, informing that the payment was completed.
Stripe code:
let stripe = StripeCheckout.configure({
key: "{{config('services.stripe.key')}}",
image: "",
locale: "auto",
token: (token) => {
document.getElementById('stripeToken').value = token.id;
document.getElementById('paymentForm').submit();
}
});
document.getElementById('payment').addEventListener('click', function(e){
stripe.open({
name: 'test',
description: 'test',
amount: 1000
});
e.preventDefault();
});
Like this is not working, it appears the " console.log("Ajax Error!");" and then the user is redirected to "http://proj.test/charge".
let stripe = StripeCheckout.configure({
key: "{{config('services.stripe.key')}}",
image: "",
locale: "auto",
token: (token) => {
document.querySelector('#stripeToken').value = token.id;
document.querySelector('#paymentForm').submit();
$.ajax({
type: "POST",
url: '{{route('conferences.charge')}}',
data: {tokenid: token.id, email: token.email},
success: function(data) {
if (data == 'success') {
console.log("success");
}
else {
console.log("error");
console.log("Ajax Error!");
}
},
error: function(data) {
console.log(data);
}
});
}
});
document.getElementById('payment').addEventListener('click', function(e){
stripe.open({
name: 'test',
description: 'test',
amount: '{{session('total')}}'
});
e.preventDefault();
});
RegistrationController returning code 200:
public function charge(Request $request)
{
Stripe::setApiKey(config('services.stripe.secret'));
$source = $request->stripeToken;
$selectedRtypes = Session::get('selectedRtypes');
$amount = (collect($selectedRtypes)->first()['total']) * 100;
try{
Charge::create([
'currency' => 'eur',
'description' => 'Example charge',
'amount' => $amount,
'source' => $source,
]);
}
catch(\Exception $e){
return response()->json(['status' => $e->getMessage()], 422);
}
return response()->json([
'success' => true,
'message' => 'success',
], 200);
}
So this could probably be achieved in different ways.
Here is a solution from a VUE script that uses jquery to get the form
send: function () {
Stripe.setPublishableKey("stripekey")
const $form = $('#payment-form')
Stripe.card.createToken($form, (status, response) => {
if (response.error) {
return
}
this.payment_token = response.id
this.post('<your controller charge>', this.getFormData())
})
},
post: function (url, data) {
axios.post(url, data).then(response => {
// handle success here
}).catch(error => {
// handle error here
})
},
getFormData: function () {
return {
'payment_token': this.payment_token
}
},
But what I think you are looking for is
send: function () {
Stripe.setPublishableKey("stripekey")
const $form = $('#payment-form')
Stripe.card.createToken($form, (status, response) => {
if (response.error) {
return
}
let stripeToken = response.id
})
}
This uses the stripe javascript sdk
<script type="text/javascript" src="https://js.stripe.com/v2/"></script>

Categories