Creating zip of multiple files and download in laravel - laravel

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

Related

Laravel download image

I have a function to add an image, and upon successful addition in the database, we have a path like public/images/asd.png. The question is how to make sure that when added to the name of the picture, an ID is added, and we have something like public/images/asd1.png, public/images/asd2.png, etc.
function in Model
public function getOriginImageUrl()
{
return $this->attributes['image'];
}
public function getImageAttribute($value)
{
return Storage::exists($value) ? Storage::url($value) : null;
}
function in Controller
if ($request->hasFile('image')) {
$file = $request->file('image');
$blog->image = $file->storeAs('public/images', $file->getClientOriginalName());
}
Instead of id you can combine time() with image name.
if ($request->hasFile('image')) {
$file = $request->file('image');
$namewithextension = $file->getClientOriginalName(); //Name with extension 'filename.jpg'
$name = explode('.', $namewithextension)[0]; // Filename 'filename'
$extension = $file->getClientOriginalExtension(); //Extension 'jpg'
$uploadname = $name. '-' .time() . '.' . $extension;
$blog->image = $file->storeAs('public/images', $uploadname);
}

Old File from storage is not being deleted on update Laravel

I am trying to delete the existing image from the storage while the new image is being updated.
But everytime the new image is inserted retaining the previous ones.
When I dd the image from database to unlink, I get full url
i.e.
http://127.0.0.1:8000/teacger-image/1598097262-85508.jpg
While only teacher-image/1598097262-85508.jpg
has been stored in the database.
Function to delete the image
public function deleteImageFromStorage($value)
{
if (!empty($value)) {
File::delete('public/' . $value);
}
}
I have called the method in the controller when there is image posted during update.
update method includes
if ($request->hasFile('image')) {
$teacher->deleteImageFromStorage($teacher->image);
$file = $request->file('image');
$filename = time() . '-' . mt_rand(0, 100000) . '.' . $file->getClientOriginalExtension();
$path = $file->storeAs('teacher-image', $filename);
$teacher->image = $path;
}
Also I have used Storage::delete() and unlink as well but none of them seem to work.
help
This is how I've been deleting files in Laravel.
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
class ImagesController extends Controller
{
public function deleteImageFromStorage($value)
{
if ( file_exists( storage_path($value) ) ) {
Storage::delete($value);
}
}
}
Make sure to use Illuminate\Support\Facades\Storage.
Try change your deleteImageFromStorage method to this:
public function deleteImageFromStorage($value)
{
if (!empty($value)) {
File::delete(public_path($value));
}
}
I had to do this to solve my problem.
The url was being taken by the configuration set on filesystems.php under config file.
public function deleteImageFromStorage($value)
{
$path_explode = explode('/', (parse_url($value))['path']); //breaking the full url
$path_array = [];
array_push($path_array, $path_explode[2], $path_explode[3]); // storing the value of path_explode 2 and 3 in path_array array
$old_image = implode('/', $path_array);
if ($old_image) {
Storage::delete($old_image);
}
}
If someone goes through the same problem in the future, this might be helpful.

ContextErrorException in Symfony 3

I am trying to upload images in SF3, and I have this error when I upload:
Missing argument 2 for Symfony\Component\HttpFoundation\File\UploadedFile::__construct().
This is the part of my entity where is the error is located (line 9 here):
public function preUpload()
{
// if there is no file (optional field)
if (null === $this->image) {
return;
}
// $file = new File($this->getUploadRootDir() . '/' . $this->image);
$file = new File($this->getUploadRootDir() .'/' . $this->image);
$uploadedfile = new UploadedFile($this->getUploadRootDir() .'/' . $this->image);
// the name of the file is its id, one should just store also its extension
// to make clean, we should rename this attribute to "extension" rather than "url"
$this->url = $file->guessExtension();
// and we generate the alt attribute of the <img> tag,
// the value of the file name on the user's PC
$this->alt = $uploadedfile->getClientOriginalName();
}
Then my controller :
public function mediaEditAction(Request $request)
{
$media = new Media();
$form = $this->createForm(MediaType::class, $media);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$file = $media->getImage();
$fileName = md5(uniqid()).'.'.$file->guessExtension();
$file->move(
$this->getParameter('images_directory'),
$fileName
);
$media->setImage($fileName);
$em = $this->getDoctrine()->getManager();
$em->persist($media);
$em->flush();
$request->getSession()->getFlashBag()->add('Notice', 'Photo added with success');
// redirection
$url = $this->generateUrl('medecin_parametre');
// permanent redirection with the status http 301
return $this->redirect($url, 301);
} else {
return $this->render('DoctixMedecinBundle:Medecin:mediaedit.html.twig', array(
'form' => $form->createView()
));
}
}
It seems like you are doing unnecessary work and making this a little more complicated than it probably needs to be. Have you followed this Symfony guide for How to Upload Files?
In the meantime, it seems like the image name is what is in $this->image so you can just pass that as the 2nd constructor argument.
$uploadedfile = new UploadedFile($this->getUploadRootDir().'/'.$this->image, $this->image);
However, UploadedFile should probably only come from the form submission, and in your entity you would want to use File instead - like so:
use Symfony\Component\HttpFoundation\File\File;
$uploadedfile = new File($this->getUploadRootDir() .'/' . $this->image);

ErrorException in AssetController.php line 21: Trying to get property of non-object

I have this code source that i'm trying to use in one of my projects, it worked with laravel 5.2. This the function in the assetController:
namespace App\Http\Controllers;
use App\Setting;
use File;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class AssetController extends Controller
{
/**
* List all image from image directory
*/
public function getAsset()
{
//Get Admin Images
$adminImages = array();
//get image file array
$images_dir = Setting::where('name', 'images_dir')->first();
$folderContentAdmin = File::files($images_dir->value);
//check the allowed file extension and make the allowed file array
$allowedExt = Setting::where('name', 'images_allowedExtensions')->first();
$temp = explode('|', $allowedExt->value);
foreach ($folderContentAdmin as $key => $item)
{
if( ! is_array($item))
{
//check the file extension
$ext = pathinfo($item, PATHINFO_EXTENSION);
//prep allowed extensions array
if (in_array($ext, $temp))
{
array_push($adminImages, $item);
}
}
}
//Get User Images
$userImages = array();
$userID = Auth::user()->id;
$images_uploadDir = Setting::where('name', 'images_uploadDir')->first();
if (is_dir( $images_uploadDir->value . "/" .$userID ))
{
$folderContentUser = File::files($images_uploadDir->value . "/" .$userID );
if ($folderContentUser)
{
foreach ($folderContentUser as $key => $item)
{
if ( ! is_array($item))
{
//check the file extension
$ext = pathinfo($item, PATHINFO_EXTENSION);
//prep allowed extensions array
//$temp = explode("|", $this->config->item('images_allowedExtensions'));
if (in_array($ext, $temp))
{
array_push($userImages, $item);
}
}
}
}
}
//var_dump($folderContent);
//var_dump($adminImages);
return view('assets/images', compact('adminImages', 'userImages'));
}
The problem is in the line 21 :
//get image file array
$images_dir = Setting::where('name', 'images_dir')->first();
$folderContentAdmin = File::files($images_dir->value);
From my research I find out that the reason is because the setting table is empty which it is true.
Please tell me if there is another cause to that problem if it's not the case I need a solution because I don't have a way to fill that table except doing it from the database itself (phpmyAdmin)

Cannot use object of type Illuminate\Http\UploadedFile as array

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

Resources