Repositories with Laravel, saving image to DB - php

I have setup a repository to create a new resident.
<?php namespace Crescent\Repos;
interface ResidentRepository {
public function create($input);
}
Then in my controller I have, which uses the intervention image class to resize an image and it uploads correctly to the directory, but how can I save the name of the file to the DB using this repo?
public function store()
{
if (Input::hasFile('photo')){
$res = new Residents;
$file = Input::file('photo');
$name = $file->getClientOriginalName();
$input = Input::all();
$image = Image::make(Input::file('photo')->getRealPath())->resize(200, 200);
$image->save(public_path() . '/uploads/residents/' . $input['photo']->getClientOriginalName());
$res->photo = $name; // This doesn't work
}
$this->resident->create(Input::all());
}
Everything else works all the data, but the image isn't storing the name just showing some temp dir/name like /tmp/phpIX7KcY

I see that you have done $res = new Residents; and $res->photo = $name; but you haven't done $res->save(); which would have saved the name to the table corresponding to Residents. Also since you haven't added anything else to $res, only the photo would be saved.
Replace the code in your controller with the following:
public function store()
{
$input = Input::all();
if (Input::hasFile('photo')){
$file = Input::file('photo');
$name = $file->getClientOriginalName();
$image = Image::make(Input::file('photo')->getRealPath())->resize(200, 200);
$image->save(public_path() . '/uploads/residents/' . $input['photo']->getClientOriginalName());
$input['photo'] = $name;
}
$this->resident->create($input);
}
If in your code $this->resident->create(Input::all()); saves all data properly except the photo, it is because by passing Input::all() you're saving everything exactly as it was received from the client and the filename received from the resizing operation isn't present in Input::all(). By assigning Input::all() to the variable $input and doing $input['photo'] = $name;, the location of the file on the server is stored instead of the location on the client. So, by doing $this->resident->create($input);, the location on the server is stored along with other data received from the client.

Related

Laravel 5.5: add url to json object to save multiple pictures

I need to save multiple pictures with Laravel. The pictures are stored separately on disk and the links to the places are stored in a JSON file in the database. So each users has an column in the database with:
{"images": ["/user/57/house-11-1.png", "/use/57/house-12-2.png"]}
So when the user uploads a file and click on save this code happens:
$path = $this->processImage($request, $user->id, $house->id);
/* uploads the image to the server and pass path of the image*/
if ($path) {
$jsonstring = $house->images;
dd($jsonstring);
$arr = json_decode($jsonstring);
$arr['images'] = [$path];
$json = json_encode($arr);
dd($json);
$house->images = $json;
$house->save();
}
The laravel model that is used is called userHouse and saves images as:
class userHouse extends Model implements Changeable
{
protected $casts = [
'images' => 'array',
];
...
}
processImage function:
private function processImage($request, $userID, $houseId)
{
$path = null;
$number = rand(1, 99);
if ($request->hasFile('image')) {
$image = Image::make($request->file('image'))
->resize(750, null, function ($constraint) {
$constraint->aspectRatio();
})
->encode('png');
$path = "/vendors/{$userID}/horse-{$houseId}-{$number}.png";
Storage::disk('fileadmin')->put($path, $image->encoded);
}
return $path;
}
the error I get is:
[2019-05-27 08:01:15] local.ERROR: Serialization of 'Illuminate\Http\UploadedFile' is not allowed {"userId":57,"email":"info#test.com","exception":"[object] (Exception(code: 0): Serialization of 'Illuminate\\Http\\UploadedFile' is not allowed at /Users/dsfsdf/ah-website/user/laravel/framework/src/Illuminate/Session/Store.php:128)
[stacktrace]
How can I add the url to the JSON string in the database? Uploading single images works.
What I could think of is that the processImage method cannot handle multiple uploaded files in the request.
Also, IMO, this method should actually receive the UploadedFile object instead of the entire request.
So, the code would be similar to:
$images = $house->images;
foreach ($request->images as $uploadedFile) {
$images[] = $this->processImage($uploadedFile, $user->id, $house->id);
}
$house->images = $images;
$house->save();
Also, if you defined the images attribute as array in the model, there is no need to decode/encode it as laravel already does it.

laravel - saving and accessing an uploaded file

I am studying some laravel code that I downloaded and I am getting some problem.
This supposed to be the functions to save,delete and download the files but the problem is.
The files are being saved in a folder named with a number on "storage\app\public\project-files\" (i.e. storage\app\public\project-files\11), both destroy and download methods are referencing different paths, I tried to change but didn't worked, download show FileNotFoundException and destroy just remove from the database but not from the folder
So is this code wrong? How It supposed to be?
I've read about using artisan:link but seems odd to me run this command every time I want upload a file to make a link
PS. I cheched the routes, so the methods are being called
Thanks
public function store(Request $request)
{
if ($request->hasFile('file')) {
$file = new ProjectFile();
$file->user_id = $this->user->id;
$file->project_id = $request->project_id;
$request->file->store('public/project-files/'.$request->project_id);
$file->filename = $request->file->getClientOriginalName();
$file->hashname = $request->file->hashName();
$file->size = $request->file->getSize();
$file->save();
$this->project = Project::find($request->project_id);
return view('project-files');
}
public function destroy($id)
{
$file = ProjectFile::find($id);
File::delete('storage/project-files/'.$file->project_id.'/'.$file->hashname);
ProjectFile::destroy($id);
$this->project = Project::find($file->project_id);
return view('project-files');
}
public function download($id) {
$file = ProjectFile::find($id);
return response()->download('storage/project-files/'.$file->project_id.'/'.$file->hashname);
}
You are storing files in storage so i assume you have uploaded image in the following path
project\storage\app\public\project-files
if this is the path then you can delete using
Storage::delete('public/project-files/1.JPG');
for Downlaoding file
$path= storage_path('app/public/project-files/3.JPG');
return response()->download($path);

Laravel ajax deleting files fails

IN my vue js ajax post am storing file like
$imagename = sha1(time()).".".$request->profile_pic->extension();
$path = $request->profile_pic->storeAs('public/images/users',$imagename);
$user = \Auth::user();
//remove old file and retain new one
if(\Storage::has($user->profile_pic)){
\Storage::delete($user->profile_pic);
}
$user->picture = $path;
$user->save();
THe above works and the image is saved in the storage/app/public/images/users which is okay
But the database field is saved as public/images/users so when accessing the value in the frontend its not found
After several tests i found out that in the database i need to save the file as
storage/images/users //note path is not starting with public
so i changed the
$user->picture="storage/images/users".$imagename;
But now after doing this the part that removes old file fails
if(\Storage::has($user->profile_pic)){
\Storage::delete($user->profile_pic);
}
How do i adjust the delete part to also work.
UPDATE FOR FULL CONTROLLER CODE
public function changeProfilePic(Request $request){
if ($request->hasFile('profile_pic')) {
$imagename = sha1(time()).".".$request->profile_pic->extension();
$path = $request->profile_pic->storeAs('public/images/users',$imagename);
$user = \Auth::user();
//remove old file and retain new one
if(\Storage::has($user->profile_pic)){
\Storage::delete($user->profile_pic);
}
$user->profile_pic = "storage/images/users".$imagename;
//if save fails delete the uploaded image
if($user->save()){
return response("true", 200);
}else {
\Storage::delete($path);
return response("false", 200);
}
}else{
return response("false", 200);
}
}
in mmy vue js during upload am using vue-image-crop-upload plugin
<image-uploader field="profile_pic"
...other stuff for plugin
url="/change-profile-picture"
langType="en"
:headers="headers"
img-format="png"></image-uploader>
laravel route
Route::post('/change-profile-picture', 'UserController#changeProfilePic');
This is the way i resolved it
After a quick check i found out that no matter what i try
Storage::has or Storage::exists
Aways returns false and `Storage::delete doesnt throw any error even if the file doesnt exists
Also a quick check on the file path i had to change the name stored on database from storage to public hence explde and implode
TRHe final code that works is
public function changeProfilePic(Request $request){
if ($request->hasFile('profile_pic')) {
$imagename = sha1(time()).".".$request->profile_pic->extension();
$path = $request->profile_pic->storeAs('public/images/users',$imagename);
$user = \Auth::user();
$olduserpicdata = explode("/",$user->profile_pic);
$olduserpicdata[0] = "public";
//remove old file and retain new one
Storage::delete(implode("/",$olduserpicdata));
$user->profile_pic = "storage/images/users/".$imagename;
//if save fails delete the uploaded image
if($user->save()){
return response("true", 200);
}else {
Storage::delete($path);
return response("false", 200);
}
}else{
return response("false", 200);
}
}

Laravel storing temporary filename in database

The upload script is working, the file also gets saved by the correct/desired name. However, while storing data in database, it stores .tmp filename instead
controller code:
public function store(CreateChapterRequest $request)
{
if($request['chapter_content_type']==6) {
//upload file
$record_save = $this->processFile($request->file('chapter_document'));
$request['chapter_document']=$record_save;
}
Chapter::create($request->all());
}
protected function processFile($requestData)
{
$input['chapter_document'] = time().'.'.$requestData->getClientOriginalExtension();
$destinationPath = public_path('uploads/chapters/');
$requestData->move($destinationPath, $input['chapter_document']);
return $input['chapter_document'];
}
It's storing file name as C:\project\xampp\tmp\phpD837.tmp. What's wrong?
It works with $record=new Chapter(); $record->save($request->all()); but not with ::create()
Don't know why!

Laravel Access Images outside public folder

I need to store images in a backend for logged in users. The stored images need to be protected and not visible from the outside (public). I choosed a "storage" folder for this.
I came up with this in my Controller:
public function update(Request $request, $id)
{
//Show the image
echo '<img src="'.$_POST['img_val'].'" />';
//Get the base-64 string from data
$filteredData=substr($_POST['img_val'], strpos($_POST['img_val'], ",")+1);
//Decode the string
$unencodedData=base64_decode($filteredData);
//Save the image
$storagepath = storage_path('app/images/users/' . Auth::user()->id);
$imgoutput = file_put_contents($storagepath.'/flyer.png', $unencodedData);
return view('backend.flyers.index')->withImgoutput($imgoutput)
//->withStoragepath($storagepath);
}
after hitting the save button, which triggers the update() I am able to see the image in my view, and it is also stored in my folder (current users=10) "storage/app/images/users/10/flyer.png"
my question is how can I access the image path?
I want to show the stored image with img src="">. I have no idea what to put inside "src= ..."
While dealing with user file uploads in web applications, the major aspect is about user's content's security.
One should use secure way to upload private files of a user in web applications.
As in your case, you want to access user's image outside public folder.
This can be done in a most secure way as given below.
First of all create a directory right in the root directory of Laravel (where the public folder is located), let the directory's name be uploads. Use this directory to upload private user files.
In the case of images create an another directory inside uploads as uploads/images/ inside uploads directory so that you can have a different storage locations for different type of files.
Remember to upload the image in images directory with a different name and without their extensions so that it looks like a extension-less file.
Keep the file name and its extension in the database which can be used later to retain image's location.
Now you need to create a separate route to show user's image.
Route::get('users/{id}/profile_photo', 'PhotosController#showProfilePhoto')->name('users.showProfilePhoto');
PhotosController.php
class PhotosController extends Controller {
private $image_cache_expires = "Sat, 01 Jan 2050 00:00:00 GMT";
public function showProfilePhoto($id) {
$user = User::find($id);
$path = base_path() . '/uploads/images/';
if($user && $user->photo) // Column where user's photo name is stored in DB
{
$photo_path = $path . $user->photo; // eg: "file_name"
$photo_mime_type = $user->photo_mime_type; // eg: "image/jpeg"
$response = response()->make(File::get($photo_path));
$response->header("Content-Type", $photo_mime_type);
$response->header("Expires", $this->image_cache_expires);
return $response;
}
abort("404");
}
}
The method above inside PhotosController - showProfilePhoto($user_id) will run as soon as you access the route named - users.showProfilePhoto.
Your HTML code will look like this.
<img src="<?php echo route('users.showProfilePhoto', array('id' => $user->id)); ?>" alt="Alter Text Here">
The above code will work like a charm and the image will be shown to the user without declaring/publishing the proper image path to public.
According to me this is the secure way to deal with file uploads in web applications.
You can do this like this:
Route::get('images/{filename}', function ($filename)
{
$path = storage_path() . '/' . $filename;
if(!File::exists($path)) abort(404);
$file = File::get($path);
$type = File::mimeType($path);
$response = Response::make($file, 200);
$response->header("Content-Type", $type);
return $response;
});
Reference:
Laravel 5 - How to access image uploaded in storage within View?
Or Alternatively you can use this library: https://github.com/thephpleague/glide
Just use composer to install it in your project
By default, this will render images from your storage, and allow you to do all sorts of things with it such as cropping, color correction etc.
Reference:
http://glide.thephpleague.com/
https://laracasts.com/discuss/channels/laravel/laravel-5-how-can-we-access-image-from-storage?page=1
Atimes you might have some images you do not wish to store in public directory for some various reasons.
Although storing your images has lots of advantages.
There are many ways you can achieve this, however I have this simple solution.
You should create a helper class like so if already don't have one
<?php namespace App\Services;
class Helper
{
public function imageToBase64($path)
{
$type = pathinfo($path, PATHINFO_EXTENSION);
$data = file_get_contents($path);
return 'data:image/' . $type . ';base64,' . base64_encode($data);
}
}
Then in your view (blade)
#inject('helper', 'App\Services\Helper')
<img width="200" height="250" src="{{$helper->imageToBase64(storage_path('app/images/users/' . Auth::user()->id)}}">
It will work 100% work. Open file filesystem in app/config/filesystem.php and write like that
'profile' => [
'driver' => 'profile',
'root' => '/home/folder/public_html/projectname/public/profiles',
],
Add this file at top
use Illuminate\Support\Facades\Storage;
My variable name is
$directoryName = 'profile';
$imageName = $request->image; // image is array of base64 encoded urls
$directory_path ='profiles';
Below function save your file in public/profiles folder.
function UploadImagesByBase64($directoryName, $imageName,$directory_path)
{
$data = array();
$image = $imageName;
foreach ($image as $image_64) {
if($image_64 !=null){
$extension = explode('/', explode(':', substr($image_64, 0, strpos($image_64, ';')))[1])[1]; // .jpg .png .pdf
$replace = substr($image_64, 0, strpos($image_64, ',')+1);
// find substring fro replace here eg: data:image/png;base64,
$image = str_replace($replace, '', $image_64);
$image = str_replace(' ', '+', $image);
$imageName = Str::random(10).time().'.'.$extension;
Storage::disk($directoryName)->put($imageName, base64_decode($image));
$data[] = $directory_path.'/'.$imageName;
}
}
$imageName = implode(',', $data);
return $imageName;
}

Categories