Laravel 8 how to use setter method to upload an image - laravel

I was using the old Laravel setter method in the model to upload an icon image when creating a new Category
class Category extends Model
{
public function setIconAttribute($value)
{
$fileName = 'Icon_'. $this->name .'_'.rand(11111,99999).'.'.$value->getClientOriginalExtension();
$destinationPath = public_path('images/Icon');
$value->move($destinationPath, $fileName); // uploading file to given path
$this->attributes['icon'] = $fileName;
}
}
and it was working fine ,
now I am upgrading to the new laravel 8.77 setter
protected function icon(): Attribute
{
return Attribute::make (
get: fn ($value) => asset('images/Icon/'.$value),
set: function ($value) {
$fileName = 'Icon_'.rand(11111,99999).'.'.$value->getClientOriginalExtension(); // renameing image
$destinationPath = public_path('images/Icon');
$value->move($destinationPath, $fileName); // uploading file to given path
return $fileName;
}
);
}
and it gets me an error
The file "Finishe_30574.png" was not uploaded due to an unknown error.
so first how to fix this error
and how to add the attribute name ($this->name) in the file name - in the new Laravel-8 setter like the old way
$fileName = 'Icon_'. $this->name .'_'.rand(11111,99999).'.'.$value->getClientOriginalExtension();
because adding ($this->name) in the new setter way getts an error

Related

Laravel frontend website logo showing problem. New logo isn't replacing previous logo

Logo is showing every times I uploaded a new logo. New logo isn't replacing previous logo.
Here it should look like.
https://imgur.com/foSkl37
But it's showing
https://i.stack.imgur.com/BycVa.png
This is index.blade.php code
https://imgur.com/ycOOpxh
This is Controller File
class LogoController extends Controller
{
//
public function index()
{
$logos = logo::all();
return view('front.index', compact('logos'));
}
public function create()
{
$logos = logo::all();
return view('backend.addlogo');
}
public function store(Request $request)
{
$logo = new logo;
if ($request->hasFile('logo'))
{
$file = $request->file('logo');
$extension = $file->getClientOriginalExtension();
$filename = time() . '.' . $extension;
$file->move('uploads/logo/', $filename);
$logo->logo = $filename;
}
$logo->save();
return redirect()->back()->with('status', 'Logo added successfully');
}
Please help me resolve the issue. Thank you.
I Think the old logo is stored on your CSS file, try to find the image url in CSS file, if you dont find it, try to use leftCtrl+LeftClick in your refresh icon on your website, it will reload all CSS and everything so its showed up.

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.

how to fix function getClientOriginalExtension() on null on laravel

check out the code that i am getting error on "Call to a member function getClientOriginalExtension() on bool"
i used image intervention properties on laravel to upload image on product table . while usng getClientOriginalExtension() i got error...
public function product_store(Request $request)
{
$image = $request->hasfile('product_image');
$img = $image->getClientOriginalExtension();
$location = public_path('images/products/' .$img);
Image::make($imge)->save($location);
$product_image = new productImage;
$product_image->product_id = 1;
$product_image->image = $img;
$product_image->save();
return redirect() -> route('admin.product.create');
}
Call to a member function getClientOriginalExtension() on bool
hasFile returning boolean.Try this -
$image = $request->file('product_image');
You can use hasFile() to check if there is a file or not!
if ($request->hasFile('product_image')) {
$image = $request->file('product_image');
}
then get the extension using :
$imageExt = $image->extension();

Creating zip of multiple files and download in 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));
}

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

Resources