I am trying to make POST to a rest API where I need to send multiple files from a user input form. I have managed to get it to work with a single file, but when there are multiple files sent as an array ($file[]), I can't see anything in the laravel docs to show how this can be done.
$response = 'API_URL';
$response = Http::withToken(ENV('API_KEY'))
->attach('file', fopen($request->file, 'r'))
->post($url, [
'uuid' => $request->uuid,
]);
You can do it by:
->attach('file[0]', fopen($request->file[0], 'r'))
->attach('file[1]', fopen($request->file[1], 'r'))
if your $files is an array of files that wants to send, you can do like below:
$response = Http::withToken(ENV('API_KEY'));
foreach($files as $k => $file)
{
$response = $response->attach('file['.$k.']', $file);
}
$response = $response->post($url, [
'uuid' => $request->uuid,
]);
Attach multiple files if the file name also unknown, together with request data in one request, if request has file or does not have file. with authorization header
if ($method == 'POST') {
// Attached multiple file with the request data
$response = Http::withHeaders($headers);
if($request->files) {
foreach ($request->files as $key=> $file) {
if ($request->hasFile($key)) {
// get Illuminate\Http\UploadedFile instance
$image = $request->file($key);
$fileName = $request->file($key)->getClientOriginalName();
$response = $response->attach($key, $image->get(),$fileName);
}
}
$response = $response->post($this->$requestUrl, $request->all());
} else {
$response = Http::withHeaders($headers)->post($this->webApiBaseUri, $request->all());
}
}
Related
I need to create a document using Google Drive API, then give writer permission to logged in user and redirect them to created file. I'm trying to do it like this:
$credentials = storage_path('credentials.json');
$user = Socialite::driver('google')->stateless()->user();
$token = [
'access_token' => $user->token,
'refresh_token' => $user->refreshToken,
'expires_in' => $user->expiresIn
];
$client = new Google_Client();
$client->setApplicationName('Sheets');
$client->setScopes([Google_Service_Docs::DRIVE, Google_Service_Docs::DOCUMENTS]);
$client->setAccessType('offline');
$client->setAuthConfig($credentials);
$client->setAccessToken($token);
$service = new Google_Service_Docs($client);
$serviceDrive = new Google_Service_Drive($client);
$body = new Google_Service_Drive_DriveFile(array(
"name" => 'Testing ' . Lang::get('pls.export.name')
));
$doc = $serviceDrive->files->create($body);
$permission = $this->insertPermission($serviceDrive, $doc->id, $user->email, 'user', 'writer');
$url = "https://docs.google.com/document/d/" . $doc->id . "/edit#";
return Redirect::away($url);
This is the insertPermission function
function insertPermission($service, $fileId, $value, $type, $role)
{
$newPermission = new Google_Service_Drive_Permission();
$newPermission->setEmailAddress($value);
$newPermission->setType($type);
$newPermission->setRole($role);
if ($role == 'owner') {
$permission = $service->permissions->create($fileId, $newPermission, array('fields' => 'id', 'transferOwnership' => 'true'));
} else {
$permission = $service->permissions->create($fileId, $newPermission);
}
if ($permission) {
return $permission;
}
return NULL;
}
After I run this code, I can see that the file was indeed created (I can get its id too), I also receive a notification on email that the file was shared with me, but I can't open the file itself. I'm getting a notification that page does not exist and "Sorry, unable to open the file at this time".
P.S. The same approach works perfectly fine when I'm creating a spreadsheet, instead of document. I can access the spreadsheet without any issues afterwards
After some research and testing I managed to fix the issue. The problem was I was using google drive api to create the file. Instead, I used Google Docs API like so:
$document = new Google_Service_Docs_Document(array(
'title' => 'Testing ' . Lang::get('pls.export.name')
));
$document = $service->documents->create($document);
Everything worked like a charm
This question already has an answer here:
File uploading in Laravel
(1 answer)
Closed 3 years ago.
Been working on this problem for 2 days and still cannot figure it out. I am trying to upload multiple files into storage in my Laravel project. I know my code works up to the foreach as I tested this with dd.
My controller:
$files = $request->file('current_plan_year_claims_data_file_1');
$folder = public_path(). "\storage\\$id";
if (!File::exists($folder)) {
File::makeDirectory($folder, 0775, true, true);
}
if (!empty($files)) {
foreach($files as $file) {
Storage::disk(['driver' => 'local', 'root' => $folder])->put($file->getClientOriginalName(), file_get_contents($file));
}
}
I see that you are trying to store the files directly in public folder, but why not use the Storage API of Laravel and use the public disk? You can do something like this to upload the files to the public directory:
$id = 123;
$files = $request->file();
$folder = $id;
if (count($files) > 0) {
foreach ($files as $file) {
$file->store($folder, ['disk' => 'public']);
}
}
And be sure that you have linked the storage path to public:
php artisan storage:link
Focus on $files = $request->file(); line. When you don't pass an argument to file() method, all uploaded file instances are returned. Now when you will loop over the $files array, you will get access to individual uploaded files.
And then you can store the file using your logic, i.e. you can use the original name or whatever else. Even you can use the Storage facade to process the file instance.
i.e. if you want to store the files with their original names, I find this a cleaner way rather than what you are doing:
$id = 123;
$files = $request->file();
$folder = $id;
if (count($files) > 0) {
foreach ($files as $file) {
Storage::disk('public')->putFileAs(
$folder,
$file,
$file->getClientOriginalName()
);
}
}
And as suggested by #cbaconnier, you can use allFiles() method too that's more descriptive:
$files = $request->allFiles();
I hope this helps.
You're trying to iterate over files, and file is just a reference to request->file(), which is a SINGLE UploadedFile object.
As indicated by your comment, you have multiple file inputs with different name attributes, so you can't easily loop over them with one statement, eg: if you had multiple files all uploaded as "attachments[]" as the input name attribute, you could get them all with $request->allFiles('attachments'), however, if you want to keep the input names as they are, this should be close to what you want.
public function foo(Request $request, $id){
$folder = public_path(). "\storage\\$id";
if (!File::exists($folder)) {
File::makeDirectory($folder, 0775, true, true);
}
$files = array();
$files[] = $request->file('current_plan_year_claims_data_file_1');
$files[] = $request->file('prior_plan_year_claims_data_file_1');
$files[] = $request->file('etc_file_whatever');
foreach($files as $file) {
Storage::disk(['driver' => 'local', 'root' => $folder])->put($file->getClientOriginalName(), file_get_contents($file));
}
}
Side note, i'm not sure what you're doing with File and public_path, but if your goal is just to put something in your app storage, something like this should work fine
public function foo(Request $request, $id){
if(!\Storage::exists($id)){
\Storage::makeDirectory($id);
}
$files = array();
$files[] = $request->file('current_plan_year_claims_data_file_1');
$files[] = $request->file('prior_plan_year_claims_data_file_1');
$files[] = $request->file('etc_file_whatever');
foreach($files as $file) {
\Storage::put("$id/" . $file->getClientOriginalFileName(), $file);
}
}
I need to send a CSV file through rest api.
I am using reactjs for front end development and constructing backend apis with Laravel.
I am confused with how to send a CSV file through api response ?
Can anyone help me?
this function will download csv file
public function downloadCSV(Request $request){
$table = User::orderBy('created_at','desc')->with('user')->get();
$filename = "users.csv";
$handle = fopen($filename, 'w+');
fputcsv($handle, array('user_name','user_email','country','state','address','zip_code','city'));
foreach($table as $row) {
fputcsv($handle, array(
$row['user_name'],
$row['user_email'],
$row['country'],
$row['state'],
$row['address'],
$row['zip_code'],
$row['city']
));
}
fclose($handle);
$headers = array('Content-Type' => 'text/csv');
return response()->download($filename, 'users.csv', $headers);
}
I wanted to add a job to send a mail to a big list of adresses; but i get an exception
Swift_IoException: Unable to open file for reading
I method was working perfectly without the job but now when i use a dispatch job with database i get this error. someone knows why i get the exception ?
When i use this directly in the controller the attachement work :
if($request->uploads){
foreach($request->uploads as $file) {
$files[] = [
'file' => $file->getRealPath(),
'options' => [
'mime' => $file->getClientMimeType(),
'as' => $file->getClientOriginalName()
],
];
}
}else{
$files = null;
}
Mail::to($emails)->send(new MassiveEmail($subject , $bodyMessage , $files));
But when i use this, it's doesn't work :
$job = (new SendEmailMassiveJob($emails , $subject , $bodyMessage , $files))
->delay(Carbon::now()->addSeconds(10));
dispatch($job);
Here my job class :
public function handle()
{
$emails = $this->emails;
$subject = $this->subject;
$bodyMessage = $this->bodyMessage;
$files = $this->files;
foreach ($emails as $email){
Mail::to($email)->send(new MassiveEmail($subject , $bodyMessage , $files));
}
}
Here my mail class who generate an error when i attach the files:
public function build()
{
$subject = $this->subject;
$bodyMessage = $this->bodyMessage;
$files = $this->files;
$email = $this->markdown('email.MassiveMail',compact('bodyMessage'))
->subject($subject.'-'.'FFRXIII Licences & Compétitions');
if($files){
foreach($files as $file) {
$email->attach($file['file'],$file['options']);
}
}
return $email;
}
I try to send attachement files but i get
Cannot use object of type Illuminate\Http\UploadedFile as array
I use laravel 5.4
Someone know why i'm getting this error ?
( I don't upload the file into a directory, i just want to send the file who was requested on my controller )
Hope someone could help , best regards :)
Here my controller :
public function postSendMassive(Request $request){
$files = $request->file('uploads');
$emails = Structure::where('type_structure_id', 4)->pluck('adresse_email_structure');
$subject = $request->subject;
$bodyMessage = $request->texte;
foreach($files as $file) {
$files[] = [
'file' => $file->getRealPath(),
'options' => [
'mime' => $file->getClientMimeType(),
'as' => $file->getClientOriginalName()
],
];
}
Mail::to('test#gmaIL.com')->send(new MassiveEmail($subject , $bodyMessage , $files));
return back()->with('status', "Email envoyé");
}
here my build mail :
public function build()
{
$subject = $this->subject;
$bodyMessage = $this->bodyMessage;
$files = $this->files;
$email = $this->markdown('email.MassiveMail',compact('bodyMessage'))
->subject($subject.'-'.'FFRXIII Licences & Compétitions');
foreach($this->files as $file) {
$email->attach($file['file'],$file['options']);
}
return $email;
}
This is because $request->file('uploads') returns an object and you're trying iterate over it with foreach
If you want to upload multiple files, make sure you're doing something like this:
<input type="file" name="uploads[]" multiple />
And iterate over uploaded files:
foreach ($request->uploads as $file)
This works!
if($request->hasFile('files')){
foreach ($request->files as $file) {
//get file name with extenstion
$fileNameWithExt = $file->getClientOriginalName();
//get just filename
$fileName = pathinfo($fileNameWithExt, PATHINFO_FILENAME);
//get extension
$extension = $file->getClientOriginalExtension();
//file to store
$fileNameToStore = $fileName.'_'.time().'.'.$extension;
//upload to store
$path = $file->storeAs('${your_storage_path}', $fileNameToStore);
}
}