Laravel Storage not storing created PDF files - laravel

I am facing an issue where my created PDF's are not being stored in laravel.
I have the following set in my filesystems.php under the disks tag
'completedforms' => [
'driver' => 'local',
'root' => storage_path('app/storage/completedforms'),
],
In my controller I have the following:
$pdf = PDF::loadView('report.form19', compact('generalreport','monthlyRoll', 'nightsInMonth', 'groupfee', 'subs', 'wing','weeksinmonth', 'meetingnights', 'lastRollMap', 'month_name', 'totalmember', 'totalcadets', 'totalnco', 'totalto', 'totalofficer'));
Storage::disk('completedforms')->put('Form 19 - '.$month_name . ' ' . $lastRollMap->roll_year.'.pdf', $pdf->output());
return $pdf->download ('Form 19 - '.$month_name . ' ' . $lastRollMap->roll_year.'.pdf');
I have added use Illuminate\Support\Facades\Storage; to my Controller
The pdf is created and downloads no issues, however the file is not being saved in the located as difined for the disk in the filesystems.php.
I have created the folder manually to ensure it exists. I have even set the file name to test.php to remove any variables fromm the file name

storage_path already starts at: /storage,
so change it like so:
'root' => storage_path('/desired'),

Related

Laravel backup with spatie/laravel-backup - There is no disk set for the backup destination - Google Cloud Storage

I'm unable to backup to GCS from Laravel app
using spatie/laravel-backup
$ php artisan backup:run
Starting backup...
Dumping database reviewbooster...
Determining files to backup...
Zipping 720 files...
Created zip containing 720 files. Size is 29.86 MB
Copying zip to disk named gcs...
Copying zip failed because: There is no disk set for the backup destination.
Backup completed!
filesystems.php
'gcs' => [
'driver' => 'gcs',
'project_id' => env('GOOGLE_CLOUD_PROJECT_ID', 'project-id'),
'key_file' => env('GOOGLE_CLOUD_KEY_FILE', null), // optional: /path/to/service-account.json
'bucket' => env('GOOGLE_CLOUD_STORAGE_BUCKET', 'bucket'),
'path_prefix' => env('GOOGLE_CLOUD_STORAGE_PATH_PREFIX', null), // optional: /default/path/to/apply/in/bucket
'storage_api_uri' => env('GOOGLE_CLOUD_STORAGE_API_URI', null), // see: Public URLs below
'visibility' => 'private', // optional: public|private
],
backup.php
'destination' => [
/*
* The filename prefix used for the backup zip file.
*/
'filename_prefix' => '',
/*
* The disk names on which the backups will be stored.
*/
'disks' => [
'gcs',
],
],
I just had this same problem.
For me, the root cause was that my .env file had incorrect variables names that didn't match what Laravel expected in config/filesystems.php.
For example, I had:
AWS_KEY=xxx
AWS_SECRET=xxx
AWS_REGION=us-east-1
AWS_BUCKET=xxx
instead of:
AWS_ACCESS_KEY_ID=xxx
AWS_SECRET_ACCESS_KEY=xxx
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=xxx
P.S. Once I fixed that, I tried running the backup again and got a new error (403 Forbidden, Access Denied, Error executing "PutObject").
So then I visited https://console.aws.amazon.com/iam/home?region=us-east-1#/users/ and clicked "Add inline policy" for the relevant user. (See this answer.)

Laravel Invention Image - How to DELETE image from Storage

I created Laravel app where I wanted to upload images + resize and crop them, for that I used Invention Image
Here is my code how I'm storing images:
/*just image cropping + resizing*/
$light_image = Image::make($request->file('startup_screenshot'));
$light_image->resize(300, null, function ($constraint) {
$constraint->aspectRatio();
});
$light_image->crop(300, 275, 0, 0);
$light_image->encode('jpg');
/*just image cropping + resizing*/
/*image storing*/
$hashed_light_image = md5($light_image->__toString());
$light_image_name = $hashed_light_image . time() . '.jpg';
Storage::put('public/images/startups-screenshots/light_previews/' . $light_image_name, $light_image->__toString());
$path_to_light_image = '/storage/images/startups-screenshots/light_previews/' . $light_image_name;
/*image storing*/
I tried to use this code to delete images but it doesn't work:
...
$startup_to_update = Startup::find($request->id);
Storage::delete($startup_to_update->screenshot);
Storage::delete($startup_to_update->screenshot_light); // pay attention
...
How Can I delete those images ?
Thank you all very much for any ideas!
I realy appreciate this ))
From what you write we can only get conjetures but well, are you sure that you are storing the correct path?, remember that Storage will be storage/app (you can check it in config->filesystem) so it would be stored in
storage/app/public/images/startups-screenshots/light_previews/ . $light_image_name
But for what i can see/think you are looking inside of
/storage/images/startups-screenshots/light_previews/' . $light_image_name
in any case if you think that what is inside $startup_to_update is the real path then you can check if it exist with
Storage::has($direction)
if it return true, then the file exist and you may have a problem with permissions.
ProTip, for these cases i use to make my own disk inside config->filesystems.php
'light_previews' => [
'driver' => 'local',
'root' => storage_path('/app/public/images/startups-screenshots/light_previews/'),
'url' => env('APP_URL').'storage/app/public/images/startups-screenshots/light_previews/',
'visibility' => 'public',
],
And then i use it like these
Storage::disk('light_previews')->put($fileName, file_get_contents($file));//store
Storage::disk('light_previews')->delete($fileName);//delete
You don't have to use intervention to delete images from storage. Intervention only acts as a image helper, not a file system helper.
use Illuminate\Support\Facades\Storage;
Storage::delete(file_path_of_image);
I fixed this, path wasn't correct,
I used this type of path to store my images: "/storage/images/startups-screenshots/light_previews/image_name.jpg" , you can see code example below:
Storage::put('public/images/startups-screenshots/light_previews/' . $light_image_name, $light_image->__toString());
As you can see I used "public/images/...." on the begining, but when I tried to delete this I couldn't because I should point path of that type "public/images/...." , not that one which I used: "/storage/images/...."
so I just changed path from "public/images/...." to "public/images/...."
and it works now
Thanks all for good ideas!

Laravel change filesystem disks path on run time

I am aware of the filesystems.php to create disks and I'm currently using it, having ~~ 20 disks configured.
I have a new problem with these, I'm currently trying to prefix to every disk, a string. The problem is that the paths are being saved when the php artisan config:cache is run but I need to change them on run time, as n example, for User Sergio it would need to append Sergio/ to the following disk for example:
//filesystems.php
'random' => [
'driver' => 'local',
'root' => storage_path('app/random'),
],
Then
Storage::disk("random")->getDriver()->getAdapter()->getPathPrefix();
//outputs /var/www/html/project/storage/app/random
and the goal is setting configurations in for example the middleware i'm currently setting the tentant database already like this
//Middleware
Config::set('database.connections.tenant.database', "Sergio");
DB::reconnect('tenant');
I can currently set the paths correctly with
Config::set('filesystems.disks.random.root',storage_path('app/Sergio/random'));
But i'm worried since that if before that line I try to reach to the path, the storage saves the initial path in memory instead of re-fetching it after it is altered.
For example. doing this without any middleware.
$fullPath1 = Storage::disk("random")->getDriver()->getAdapter()->getPathPrefix();
Config::set('filesystems.disks.random.root',storage_path('app/Sergio/random'));
$fullPath2 = Storage::disk("random")->getDriver()->getAdapter()->getPathPrefix();
What was intended to happen is that $fullPath1 would output the initial path which is /var/www/html/project/storage/app/random and then $fullPath2 would output /var/www/html/project/storage/app/Sergio/random
Is there any way of letting the Storage know that I've changed the disks local paths?
How about adding a new config instead of updating the already loaded one, something like this:
private function addNewDisk(string $diskName)
{
config(['filesystems.disk.' . $diskName => [
'driver' => 'local',
'root' => storage_path('app/' . $diskName),
]]);
}
and prior to using the Storage facade, call above method that way the config will be updated and when you use new disk, it will try to resolve again based on updated config.
{
....
$this->addNewDisk('new_random');
Storage::disk('new_random')->get('abc.txt'); // or any another method
...
}

Laravel file upload creates folder with a temp file

I'm trying to get my application to upload files to "public/uploads/documentos/{the-id}" but can't figure out what's wrong with my current setup. Right now, if I upload a file called "myfile.pdf", it creates a folder named "myfile.pdf" and inside of it a *.tmp file. In my database, "{the-id}/myfile.pdf" is saved as the file url but this takes me to the folder view, when what I want is to see the file inside of it.
How can I change it so that when a document is upload, it creates the file "myfile.pdf" directly under "public/uploads/documentos/{the-id}" so that I can access it like that? {the-id} is a folder created based on the patient's id, so all documents belonging to them are saved to the same folder.
Controller
public function store(Request $request)
{
$this->validate($request, [
'tipo' => 'required|max:100',
'descripcion' => 'max:200',
'fecha_documento' => 'max:20',
'archivo' => 'required|mimes:doc,docx,pdf,jpg,png,jpeg',
'mascota_id' => 'required',
'mascota_num' => 'required',
]);
$documento = new Documento;
$documento->mascota_num = $request->input('mascota_num');
$documento->mascota_id = $request->input('mascota_id');
$documento->tipo = ucfirst($request->input('tipo'));
$documento->descripcion = ucfirst($request->input('descripcion'));
$documento->fecha_documento = $request->input('fecha_documento');
if($request->hasFile('archivo')) {
$archivo = $request->file('archivo');
$archivo_folder = public_path('/uploads/documentos/') . $request->input('mascota_num');
$archivo_nombre = $archivo->getClientOriginalName();
$archivo_url = $archivo_folder . '/' . $archivo_nombre;
if (file_exists($archivo_folder)) {
$archivo->move($archivo_folder . '/' . $archivo_nombre);
} else {
File::makeDirectory($archivo_folder, $mode = 0777, true, true);
$archivo->move($archivo_folder . '/' . $archivo_nombre);
}
$documento->archivo = $request->input('mascota_num') . '/' . $archivo_nombre;
$documento->save();
return redirect()->route('mascotas.show', [$request->input('mascota_num')])->with('message', 'Documento agregado exitosamente.');
}
}
How my uploaded files look with this code:
uploads/documentos/
-- 1
-- file.pdf /folder
-- random_name.tmp /file
-- 2
-- file.pdf /folder
-- random_name.tmp /file
-- otherfile.pdf /folder
-- random_name.tmp /file
}
What I want
uploads/documentos/
-- 1
-- myfile.pdf /file
-- 2
-- myfile.pdf /file
-- otherfile.pdf /file
Ideally, I'd like to keep the files private, so I tried to upload them to the storage folder with this code:
Storage::put('documentos/'.$request->input('mascota_num').'/', $archivo_nombre);
$documento->archivo = Storage::url('documentos/'.$request->input('mascota_num').'/'.$archivo_nombre);
but {the-id} folder wasn't created and the files weren't saved, all I got was:
storage/app/documentos/
-- 1 /file without extension
-- 2 /file without extension
I'd settle for making the first part work for now. Thanks in advance for your help.
After much trial and error, I managed to upload files to the storage folder of my application.
if($request->hasFile('archivo')) {
$archivo = $request->file('archivo');
Storage::disk('documentos')->put($request->input('mascota_num') . '/' . $archivo->getClientOriginalName(), File::get($archivo));
$documento->archivo = $request->input('mascota_num') . '/' . $archivo_nombre;
$documento->save();
}
Files are saved to /storage/app/public/documentos/ under the correct patient id folder and with the correct file name.
I haven't found a way to correctly link to the files from my show blade, Storage::url('documentos/'.$documento->archivo)) shows a 404 error page, even though the file path is correct. Hopefully I can get this working next.

Using Laravel core in scripts built without it

I have built a Laravel 3 application, it involves a lot of per-user content management.
For prototype and internal testing I got away with plain configuration of KCFinder, now we're about to start a closed beta.
Firstly, I must lock the KCFinder behind Laravel applications Auth system.
Secondly, I must configure the KCF with a per-user settings.
While it may seem like those are two questions, I doubt they are.
My Laravel is installed in /srv/http/, KCFinder in /srv/http/public/php/kcfinder/.
KCFinder exposes two incoming files - browse.php and upload.php. These files include core/autoload.php, that ultimately ties the KCF together.
I tried requiring Laravel's public/index.php inside it, then tried to access something KCF (/php/kcfinder/browse.php) through browser. Got redirected to a mix of the request path and Laravel applications root route: /php/kcfinder/browser.
How could I prevent the Routing from Laravel and be able to use Laravel inside the KCF scope?
P.S. I did try to go the Bundle way, but apparently KCF is so poorly written that it appears that in order to Bundle it up, I'll have to rewrite everything there.
I managed to do it with a very, very dirty hack.
In /srv/http/public/php/kcfinder/core/autoload.php I appended the lines:
require '../../../paths.php';
require path('sys').'core.php';
\Laravel\Bundle::start(DEFAULT_BUNDLE);
$KCFinderRoot = addslashes(realpath(dirname(__FILE__). '/../') . DS);
\Laravel\Autoloader::map(array(
'browser' => $KCFinderRoot . 'core/browser.php',
'uploader' => $KCFinderRoot . 'core/uploader.php',
'type_img' => $KCFinderRoot . 'core/types/type_img.php',
'type_mime' => $KCFinderRoot . 'core/types/type_mime.php',
'gd' => $KCFinderRoot . 'lib/class_gd.php',
'input' => $KCFinderRoot . 'lib/class_input.php',
'zipFolder' => $KCFinderRoot . 'lib/class_zipFolder.php',
'dir' => $KCFinderRoot . 'lib/helper_dir.php',
'file' => $KCFinderRoot . 'lib/helper_file.php',
'httpCache' => $KCFinderRoot . 'lib/helper_httpCache.php',
'path' => $KCFinderRoot . 'lib/helper_path.php',
'text' => $KCFinderRoot . 'lib/helper_text.php',
));
if (!\Laravel\Auth::check())
{
die('no user :(');
}
Wherever KCF had some file inclusions, I had to squeeze in $KCFinderRoot, in some methods even requiring to global them before.
In KCF's config I added:
// ...
'uploadURL' => "/useruploads/" . sha1(Auth::user()->id . Auth::user()->email),
'uploadDir' => path('public') . "useruploads/" . sha1(Auth::user()->id . Auth::user()->email),
// ...
The end result works like I wanted it to, except I have no idea how "smart" this is.
P.S. In the following days I'm going to try to bundle, IoC this up while leaving KCF files intact.

Resources