I want to download files in zip. How can I do this? I tried, but error occurred.
I have a table name is articles:
id | volume_id | image
5 | 9 | file1.pdf
6 | 9 | file2.pdf
I want to download file1.pdf and file2.pdf in zip based on volume_id
viewarticles.blade.php is:
Download ZIP
web.php is:
Route::get('create-zip/{volume_id}', 'foruserview#createzip')->name('create-zip');
controller is:
use App\article;
use ZipArchive;
public function createzip($volume_id)
{
$articles = article::where('volume_id',$volume_id)->get();
$file= public_path(). "/storage/upload_pic/";
$zipFileName = 'AllDocuments.zip';
$zip = new ZipArchive;
if ($zip->open($file . '/' . $zipFileName, ZipArchive::CREATE) === TRUE) {
foreach($articles as $article) {
$images = $article->image;
$zip->addFile($file, $images);
}
$zip->close();
}
// Set Header
$headers = array(
'Content-Type' => 'application/octet-stream',
);
$filetopath=$file.'/'.$zipFileName;
// Create Download Response
if(file_exists($filetopath)){
return response()->download($file,$zipFileName,$headers);
}
}
After click on download button. Zip file of both images related with volume_id should be download.
But error occurs:
ErrorException (E_WARNING)
ZipArchive::close(): Read error: No such file or directory
Related
I am trying to downloads multiple images as a zip folder but unfortunatly i am getting error please help me how can resolve that thanks.
getting error
The file "/home/developer/htdocs/yourstitchart.com/cms/public/uploads/images/58-Digitizing-logo/58-Digitizing-logo.zip" does not exist
please check it https://flareapp.io/share/87ngoJ65
InboxController
public function dowloads($id)
{
$url = config('yourstitchart.file_url');
$zip = new ZipArchive;
$inboxFiles = Inbox::where('id', $id)->first()->file;
$files = [];
foreach (json_decode($inboxFiles) as $file) {
$files[] =$url. $file;
}
$inbox = Inbox::find($id);
$folderName = $inbox->id.'-'.str_replace(' ', '-',$inbox->order_name);
$zip = new ZipArchive;
$zipFile = $url .$folderName.'/'.$folderName.'.zip';
if ($zip->open($zipFile, ZipArchive::CREATE) === TRUE)
{
//add files into a zip
foreach ($files as $key => $value) {
$relativeNameInZipFile = str_replace('full',$key,basename($value));
$zip->addFile($value, $relativeNameInZipFile);
}
$zip->close();
}
return response()->download($zipFile);
}
HTML VIEW
<td>
#if($digitizingInbox->file)
<a href="{{ route('download.inbox',$digitizingInbox->id) }}"
class="download btn btn-warning">Download
</a>
#endif
</td>
Try this if you want:
$zipFile = $folderName.'.zip';
Your root is already in the public folder so it tries to add the path to the public folder. That doesn't exist. That is why you get the error.
Or you can try and add the folders from the public folder so for example
'uploads/images/58-Digitizing-logo/' . $folderName . '.zip';
EDIT
Problem solved. Had to update my filesystems config.
I want to create a zip file including all invoices which have been generated before. The problem is, if I am trying to do it with laravels storage url() or get() function, ZipArchive can not find the files.
I tried to solve it with storage_path(), ->url(), ->get() but none of them worked. It only works if I am typing the path to the files.
This is how it looks right now and it works.
$invoiceZipFileName = Carbon::now()->toDateString() . "_invoices.zip";
$zip = new ZipArchive();
$zip->open($invoiceZipFileName, ZipArchive::CREATE);
$files->each(function ($item, $key) use ($zip, $disk) {
$zip->addFile("storage/invoices/" . $item, $item);
});
$zip->close();
What I want to achieve is something like that:
$invoiceZipFileName = Carbon::now()->toDateString() . "_invoices.zip";
$zip = new ZipArchive();
$zip->open($invoiceZipFileName, ZipArchive::CREATE);
$files->each(function ($item, $key) use ($zip, $disk) {
$zip->addFile($disk->get($item), $item);
});
$zip->close();
or:
$invoiceZipFileName = Carbon::now()->toDateString() . "_invoices.zip";
$zip = new ZipArchive();
$zip->open($invoiceZipFileName, ZipArchive::CREATE);
$files->each(function ($item, $key) use ($zip, $disk) {
$zip->addFile($disk->url($item), $item);
});
$zip->close();
or:
$invoiceZipFileName = Carbon::now()->toDateString() . "_invoices.zip";
$zip = new ZipArchive();
$zip->open($invoiceZipFileName, ZipArchive::CREATE);
$files->each(function ($item, $key) use ($zip, $disk) {
$zip->addFile(storage_path("invoices") . "/" . $item, $item);
});
$zip->close();
These are the error messages (each was in another case, they don't occur together) I get:
exception: "Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException"
file: "C:\xampp\htdocs\invoicing\vendor\symfony\http-foundation\File\File.php"
line: 36
message: "The file "2019-10-02_invoices.zip" does not exist"
exception: "ErrorException"
file: "C:\xampp\htdocs\invoicing\app\Http\Controllers\Api\V1\InvoiceController.php"
line: 211
message: "ZipArchive::close(): Failure to create temporary file: No error"
++++ EDIT ++++
Problem solved. Had to update my filesystems config.
Using the below link setup Zipper package into your laravel project.
https://github.com/Chumper/Zipper
after completion of Zipper package setup use the below code into your respected controller.
$files = glob($image_dir_media . $file_new_name);
$date = new DateTime();
$zip = $date->format('Y-m-d') . '_invoices.zip';
\Zipper::make(public_path() . '/media/' . $zip)->add($files)->close();
Thanks
PHPanchal
I am using aws to store my images and the code in the controller looks like this:
Storage::disk('3')->put($file->getClientOriginalName(), fopen($file, 'r+'), 'public');
The images are being saved in my local storage.
Now though, I want to be able to create a subfolder to keep the images organized.
For my case, it is registering a business. Therefore I want the images to be stored in a subfolder containing the appropriate business id. I tried this:
Storage::disk('3')->put($file->getClientOriginalName(), fopen($file, 'r+'), 'public/' . $business->id.
More about the controller is as follows:
$input = $request->all();
$files = isset($input['file']) ? $input['file'] : array ();
$business_names = json_decode($input['business_names'], true);
$business_details = json_decode($input['business_details']);
$share_amount = json_decode($input['share_amount'], true);
$entity = json_decode($input['entity'], true);
$directors = json_decode($input['directors'], true);
$shareholders = json_decode($input['shareholders'], true);
$appointments = json_decode($input['appointments'], true);
$input['user_id'] = Auth::user()->id;
Log::info(Auth::user());
Log::info($request->user());
/* Create Business Record */
$business = new Business;
$business->business_names = json_encode($business_names);
$business->share_amount = $share_amount ?: 0;
$business->entity = $entity ?: '';
$business->business_physical_address = json_encode($business_details->physical_address);
$business->has_business_postal_address = $business_details->has_postal_address;
$business->business_postal_address = json_encode($business_details->postal_address);
$business->user_id = $input['user_id'];
$business->save();
/* Create a new folder in storage/app/files named after the business ID */
Storage::makeDirectory('files/' . $business->id);
/* Upload Files */
// TODO: file storing?
foreach($files as $file) {
if ($file) {
Storage::disk('3')->put($file->getClientOriginalName(), fopen($file, 'r+'), 'public/' . $business->id);
// $file->storeAs('files/' . $business->id, $file->getClientOriginalName());
}
}
When I try to save a business now, I see the following error:
C:\xampp\htdocs\startingabandbaby\vendor\league\flysystem\src\Adapter\Local.php(356):
Illuminate\Foundation\Bootstrap\HandleExceptions->handleError(8,
'Undefined index...', 'C:\xampp\htdocs...', 356, Array)
Since I was able to store images before, I am assuming that it is something to do with concatenating the business id.
How can I create a subfolder with the business id everytime I create a new business and add all the files in that same folder?
As per our discussion, you can use below 2 solutions:
1) put():
$path = Storage::disk('s3')->put(
'/files/'. $business->id, //path you want to upload image to S3
file_get_contents($request->file('file')), //fileContent
'public' //visibility
2) putFileAs(): To achieve the same thing withputFileAs(), I needed to write it as below. 1st parameter expects the directory name, I left it blank as I'm mimicking the directory name in s3 through the filename.
$path = Storage::disk('s3')->putFileAs(
'', // 1st parameter expects directory name, I left it blank as I'm mimicking the directory name through the filename
'/files/'. $business->id,
$request->file('file'), //3rd parameter file resource
['visibility' => 'public'] //options
);
Hope this will helps you!
After some research I ended up with the following:
$directory = 'public/' . $business->id;
Storage::disk()->makeDirectory($directory);
foreach($files as $file) {
if ($file) {
Storage::disk()->put($directory . '/' .$file->getClientOriginalName(), fopen($file, 'r+'));
}
}
i am using the following codes to make zip and allow user to download the zip
but its not working.it shows the error as ZipArchive::close(): Read error: Bad file descriptor.What might be the problem?i am working with laravel.
public function downloadposts(int $id)
{
$post = Post::find($id);
// Define Dir Folder
$public_dir = public_path() . DIRECTORY_SEPARATOR . 'uploads/post/zip';
$file_path = public_path() . DIRECTORY_SEPARATOR . 'uploads/post';
// Zip File Name
$zipFileName = $post->post_title . '.zip';
// Create ZipArchive Obj
$zip = new ZipArchive();
if ($zip->open($public_dir . DIRECTORY_SEPARATOR . $zipFileName, ZipArchive::CREATE) === TRUE) {
// Add File in ZipArchive
foreach ($post->PostDetails as $postdetails) {
$zip->addFile($file_path, $postdetails->file_name);
}
// Close ZipArchive
$zip->close();
}
// Set Header
$headers = [
'Content-Type' => 'application/octet-stream',
];
$filetopath = $public_dir . '/' . $zipFileName;
dd($filetopath);
// Create Download Response
if (file_exists($filetopath)) {
return response()->download($filetopath, $zipFileName, $headers);
}
return redirect()->back();
}
For Laravel 7.29.3 PHP 7.4.11
Create a GET route in api.php
Route::get('/downloadZip','ZipController#download')->name('download');
Create controller ZipController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use File;
class ZipController extends Controller
{
public function download(Request $request)
{
$zip = new \ZipArchive();
$fileName = 'zipFile.zip';
if ($zip->open(public_path($fileName), \ZipArchive::CREATE)== TRUE)
{
$files = File::files(public_path('myFiles'));
foreach ($files as $key => $value){
$relativeName = basename($value);
$zip->addFile($value, $relativeName);
}
$zip->close();
}
return response()->download(public_path($fileName));
}
}
In the public folder make sure you have a folder myFiles. This snippet will get every file within the folder, create a new zip file and put within the public folder, then when route is called it returns the zip file created.
Only pure php code.
public function makeZipWithFiles(string $zipPathAndName, array $filesAndPaths): void {
$zip = new ZipArchive();
$tempFile = tmpfile();
$tempFileUri = stream_get_meta_data($tempFile)['uri'];
if ($zip->open($tempFileUri, ZipArchive::CREATE) !== TRUE) {
echo 'Could not open ZIP file.';
return;
}
// Add File in ZipArchive
foreach($filesAndPaths as $file)
{
if (! $zip->addFile($file, basename($file))) {
echo 'Could not add file to ZIP: ' . $file;
}
}
// Close ZipArchive
$zip->close();
echo 'Path:' . $zipPathAndName;
rename($tempFileUri, $zipPathAndName);
}
I will suggest you to use Zipper package
Try below code for creating zip of multiple files :
public function downloadZip($id)
{
$headers = ["Content-Type"=>"application/zip"];
$fileName = $id.".zip"; // name of zip
Zipper::make(public_path('/documents/'.$id.'.zip')) //file path for zip file
->add(public_path()."/documents/".$id.'/')->close(); //files to be zipped
return response()
->download(public_path('/documents/'.$fileName),$fileName, $headers);
}
you can use the following code
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\ImgUpload;
use ZipArchive;
use File;
class UserController extends Controller
{
/**
* Function to get all images from DB
*/
public function downloadZip()
{
$data = ImgUpload::all();
foreach($data as $key => $value)
{
$imgarr[] = "storage/image". '/' . $value->image;
}
$ziplink = $this->converToZip($imgarr);
return $ziplink;
}
/**
* Function to covert all DB files to Zip
*/
public function converToZip($imgarr)
{
$zip = new ZipArchive;
$storage_path = 'storage/image';
$timeName = time();
$zipFileName = $storage_path . '/' . $timeName . '.zip';
$zipPath = asset($zipFileName);
if ($zip->open(($zipFileName), ZipArchive::CREATE) === true) {
foreach ($imgarr as $relativName) {
$zip->addFile($relativName,"/".$timeName."/".basename($relativName));
}
$zip->close();
if ($zip->open($zipFileName) === true) {
return $zipPath;
} else {
return false;
}
}
}
}
you can refer this link for more information
The question got answer, but I am posting this solution for those who wants to download dynamically zip some (based on id) files from the same folder, I hope it might help them that how to create dynamic zip file of multiple files/images affiliated with some id.
I would be taking example of multiple images. You can do the same for files.
Assuming the above table the autos_id is foreign key and based on the autos_id, there are multiple images store in the database.
To make zip file of it I will do the following:
public function downloadZip($id)
{
$data = AutoImage::where('autos_id',$id)->get();
$imgarr=[];
foreach($data as $data){
$file = storage_path() . '/app/public/autoImages/'.$data->image_name;
if(\File::exists(public_path('storage/autoImages/'.$data->image_name))){
$imgarr[]= public_path('storage/autoImages/'.$data->image_name);
}
}
$zip = new ZipArchive;
$fileName = 'AutoImages.zip';
/*OVERWRITE will not make a different zip file on server but it will
replace the one which is in the server, this approach will help you to not
make multiple zip files, if you want to creat new you can do it with unique
name of the zip file and adding CREATE instead of OVERWRITE.*/
if ($zip->open(public_path($fileName), ZipArchive::OVERWRITE) === TRUE)
{
$files = $imgarr; //passing the above array
foreach ($files as $key => $value) {
$relativeNameInZipFile = basename($value);
$zip->addFile($value, $relativeNameInZipFile);
}
$zip->close();
}
return response()->download(public_path($fileName));
}
Note: for file storage I used storage and then made a link symlink for storing files.
For further info of file storage: https://laravel.com/docs/9.x/filesystem
This works for me, multiple files zip and download.
public function download_attachment($ticket_no)
{
$zip = new \ZipArchive();
$fileName = $ticket_no.'.zip';
if ($zip->open(public_path($fileName), \ZipArchive::CREATE)== TRUE)
{
$files = File::files(public_path('uploads/tickets/' . $ticket_no));
foreach ($files as $key => $value){
$relativeName = basename($value);
$zip->addFile($value, $relativeName);
}
$zip->close();
}
return response()->download(public_path($fileName));
}
I have code written to allow someone to enter a date. if the submit date equals the file name then codeigniter should download the file to the desktop. The code shown makes sense to me but when I run it I get 'file was not found'. I can pull the file up on the server though and the name matches what is returned in the mysql database. My end goal is to be able to download the file with the same filename as my submission_date field
if($this->input->post('submit')) {
$trlr_num = $this->input->post('trlr_num');
} elseif($this->uri->segment(4)) {
$trlr_num = $this->uri->segment(4);
}
if( !empty($trlr_num)) {
$query = $this->trailer_model->select_trailer_draw($trlr_num);
$result =& $query->row_array();
if( !empty($result)) {
// Get filepath to bill
$directory = 'http://intranet.gmwdc.com/inc/img/inspection/upload';
$file = $directory.'/'.$result['submission_date'];
$this->load->helper('download');
if(file_exists($file)) {
$data = file_get_contents($file);
force_download($result['submission_date'],$data);
} else {
$this->session->set_status_data('error','File was not found.');
}
return;
} else {
$this->session->set_userdata('error','No Inspection Draw Found');
}
}
You might be referring wrong directory or file name. Also, it seems that $file is having no extension.
$file = $directory . '/' . $result['submission_date'] . $extension;
Edited
Instead of $directory try Codeigniter FCPATH which points to your Codeigniter installation directory.
$file = FCPATH . 'dir1/dir2/' . $result['submission_date'];