php artisan storage:link on shared Hosting is not showing images - laravel

I have been working on a laravel app so for security reason I've placed all of my public files inside the base folder located in public_html and other files have been placed in the public_html/secondBase.
Now when I execute the command: php artisan storage:link the following error appears.
ErrorException
symlink(): No such file or directory
at vendor/laravel/framework/src/Illuminate/Filesystem/Filesystem.php:265
261| */
262| public function link($target, $link)
263| {
264| if (! windows_os()) {
> 265| return symlink($target, $link);
266| }
267|
268| $mode = $this->isDirectory($target) ? 'J' : 'H';
269|
I tired the solution below
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
public function register()
{
$this->app->bind('path.public', function() {
return base_path() . '/public_html/base';
});
}
the second method that I've tried is by making the file symlink.php, but the images are still broken.
symlink.php
<?php
symlink('/home/hmm/public_html/secondBase/storage/app/public','/home/hmm/public_html/base/storage');
and finally I made this route where the first error appears.
Route::get('/clear', function () {
Artisan::call('route:clear');
Artisan::call('storage:link', [] );
});
Thanks for any help.

Go to /public directory and run:
rm storage
Go to Laravel root directory and run:
php artisan storage:link
This problem comes when laravel project is moved/copied to some other folder.
The storage link is still there thus causing the exception error. public/storage folder exists and points to wrong location and it needs to be deleted with rm storage command.
After that run php artisan storage:link in terminal and it will create the storage link.
This needs to be done EVERY time when laravel is moved/copied/deployed!

Related

How to clear Laravel storage folder when migrate refresh with seed option

How to clear Laravel storage folder when migrate refresh?
I want to clear storage/app/public folder when running command php artisan migrate:refresh --seed
what I have tried:
add (new Filesystem)->deleteDirectory(storage_path('app/public/images')); on database/seeders/DatabaseSeeder.php but not working, when I
I'll share here some snippet, which you can put in your database/seeders/DatabaseSeeder.php, so it will do all the work. Just don't forget that you probably by default will have storage/app/public/.gitignore file, which is not need to be deleted.
So here's a snippet to delete files & filders with the exceptions.
NOTE: run "php artisan storage:link" before running the seeder, to have access to the resources in storage disk.
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Filesystem\Filesystem;
class DatabaseSeeder extends Seeder
{
public function run()
{
$fs = new Filesystem;
// delete directories
$except_folder_names = [
// folder name (storage/app/public/<folder_name>)
];
$folder_paths = $fs->directories(public_path('storage'));
foreach ($folder_paths as $folder_path) {
$folder_name = last(explode('/', $folder_path));
if (!in_array($folder_name, $except_folder_names)) {
$fs->deleteDirectory($folder_path);
}
}
// delete files
$except_file_names = [
'.gitignore',
// file name (storage/app/public/<file_name>)
];
$file_paths = $fs->files(public_path('storage'));
foreach ($file_paths as $file_path) {
$file_name = last(explode('/', $file_path));
if (!in_array($file_name, $except_file_names)) {
$fs->delete($file_path);
}
}
echo "Uploads successfully deleted!\n";
// OTHER SEEDERS...
}
}
With this you can delete all the stuff (files and folders recursively) from storage/app/public
In other case, if you want to just clean directories, but not delete them, you can use something like this instead:
$directory = public_path('storage/' . $folder_name);
$file->cleanDirectory($directory);

Unisharp Laravel File Manager where /public is \public_html

I am using Laravel 8. My site's public directory is public_html and I have made the appropriate changed to the appservice provider:
public function register()
{
$this->app->bind('path.public', function() {
return base_path().'/public_html';
});
}
and changed the lfm is config to
'base_directory' => 'public_html',
The filemanager is uploading to the correct directory and making thumbnails in a subdirectory correctly, but it's view is a broken symbol.
I appreciate any help.
You have to bind the new storage path to the app instance. Please try this:
AppServiceProvider
public function register()
{
$this->app->instance('path.storage', base_path() . '/public_html');
}
Just get rid of the /laravel-filemanager/ prefix from the src URLs.
you have got the photos as a route.
example:
https://quislingmovie.com/photos/shares/6183cadfd8b51.jpg

How to change public folder to public_html in laravel 8?

I wanna deploy my application on shared hosting on Cpanel where the primary document root has public_html but Laravel project public
You have to follow 2 steps to change your application's public folder to public_html then your can deploy it or anything you can do :)
Edit \App\Providers\AppServiceProvider register() method & add this code .
// set the public path to this directory
$this->app->bind('path.public', function() {
return base_path().'/public_html';
});
Open server.php you can see this code
if ($uri !== '/' && file_exists(__DIR__.'/public'.$uri)) {
return false;
}
require_once __DIR__.'/public/index.php';
Just Replace it with :
if ($uri !== '/' && file_exists(__DIR__.'/public_html'.$uri)) {
return false;
}
require_once __DIR__.'/public_html/index.php';
Then serve your application with php artisan serve, you also can deploy it on your Cpanel shared hosting where primary document root public_html
You can rename your public directory to whatever you want and tell Laravel to use the current directory path as the public path. Just navigate to the index.php inside the public folder (or whatever you renamed it to) and add the following code after the $app definition:
$app = require_once __DIR__.'/../bootstrap/app.php';
/* *** Add this code: *** */
$app->bind('path.public', function() {
return __DIR__;
});
/* ********************** */
there, idk if you have same problem like me, my cases is i using shared hosting, and i deploy it in my main domain. i place all my files in the root, my problem is the storage:link keep between public, not public_html (because its default by the hosting) so what i need to do i changhe the link using this code :
Before :
'links' => [
public_path('storage') => storage_path('app/public'),
],
After :
'links' => [
app()->basePath('public_html/storage') => storage_path('app/public'),
],
I hope it can help few people :)
Just Rename the "public" folder to "public_html" and it will work.
No changes are required in the code. Tested in Laravel 8.
my two cents :) What helped to me was:
Open LaravelService/vendor/laravel/framework/src/Illuminate/Foundation/Application.php and change publicPath() method to return public_html.
public function publicPath()
{
return $this->basePath.DIRECTORY_SEPARATOR.'public_html';
}
Then if you are using webpack also change the output folder:
const output = 'public_html';
mix.ts('resources/js/web/App.ts', output + '/js/web').setPublicPath(output).react();
This helped to me. Only issue is that it is probably not recommended to change Application.php as it is part of Laravel framework and after updating it, it will be probably erased so you have to put it back.

Not all variables in .env are cached after run php artisan config:cache

GOOGLE_APPLICATION_CREDENTIALS=../storage/app/service-account.json
I have a google api credential key in the .env file. However, after I run php artisan config:cache, the credential could not be loaded. It works fine before rhe caching the configuration.
I found the following function in the google api auth file in vendor folder. It seems the google service use the .env by default. So after config:cache, the fromEnv function breaks.
Use another auth method setAuthConfig('/path/to/client_credentials.json') solve the problem.
/**
* Load a JSON key from the path specified in the environment.
*
* Load a JSON key from the path specified in the environment
* variable GOOGLE_APPLICATION_CREDENTIALS. Return null if
* GOOGLE_APPLICATION_CREDENTIALS is not specified.
*
* #return array JSON key | null
*/
public static function fromEnv()
{
$path = getenv(self::ENV_VAR);
if (empty($path)) {
return;
}
if (!file_exists($path)) {
$cause = 'file ' . $path . ' does not exist';
throw new \DomainException(self::unableToReadEnv($cause));
}
$jsonKey = file_get_contents($path);
return json_decode($jsonKey, true);
}
The reason is the way you load the file.
You probably have this in your view/controller: env('GOOGLE_APPLICATION_CREDENTIALS ');. But this will break when you do php artisan config:cache. You should only use the config() helper in your views/controller. So in order to make that work, you should make a extra google-config file or add the following to your config/services.php:
'google' => [
'application-credentials' => env('GOOGLE_APPLICATION_CREDENTIALS'),
]
Now you can fetch that inside your views/controller:
config('services.google.application-credentials');
If your value for env contains space then you need to enclose it in quote. i.e. APP_NAME="This is myapp". Please confirm it first.
In your case try with GOOGLE_APPLICATION_CREDENTIALS="../storage/app/service-account.json"
First run
php artisan cache:clear
Then
php artisan config:cache

Cannot download file from storage folder in laravel 5.4

I have store the file in storage/app/files folder by $path=$request->file->store('files') and save the path "files/LKaOlKhE5uITzAbRj5PkkNunWldmUTm3tOWPfLxO.doc" it in a table's column name file.
I have also linked storage folder to public through php artisan storage:link.
In my view blade file, I put this
<a href="#if(count($personal_information)) {{asset('storage/'.$personal_information->file)}} #endif" download>Download File</a>
and the link for download file is http://localhost:8000/storage/files/LKaOlKhE5uITzAbRj5PkkNunWldmUTm3tOWPfLxO.doc
But I get the error
NotFoundHttpException in RouteCollection.php line 161
If I add /app after the /storage it gives the same error. How can I download file from my storage/app/files folder?
Problem is storage folder is not publicly accessible in default. Storage folder is most likely forsave some private files such as users pictures which is not accessible by other users. If you move them to public folder files will be accessible for everyone. I had similar issue with Laravel 5.4 and I did a small go around by writing a route to download files.
Route::get('files/{file_name}', function($file_name = null)
{
$path = storage_path().'/'.'app'.'/files/'.$file_name;
if (file_exists($path)) {
return Response::download($path);
}
});
Or you can save your files into public folder up to you.
I'm using Laravel 6.X and was having a similar issue. The go around according to your issue is as follows:
1)In your routes/web.php do something like
/**sample route**/
Route::get('/download/{path}/', 'MyController#get_file');
2)Then in your controller (MyController.php) for our case it should look like this:
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
class MyController extends Controller
{
public function get_file($path)
{
/**this will force download your file**/
return response()->download($path);
}
}
If you have your files is stored in the public directory then use: public_path(). But if your files are stored in the storage directory, then use: storage_path()
NOTE: If your storage folder contains only attachment folder then consider having it this way: storage_path('photos/');
$destination = storage_path('storage/photos/');
or
$destination = public_path('storage/photos/');
$filename = "user_3423423465.png";
$pathToFile = $destination.$filename;
return response()->download($pathToFile,'user_profile_photo.png');
For Laravel 8
Upload File to Storage Folder
in this example, i have created a test folder inside storage folder name: uploadedfiles
In FileSystem.php
'uploadedfiles' => [
'driver' => 'local',
'root' => storage_path('uploadedfiles'),
],
Upload File
public function upload_file()
{
$file_name = "files_"."_".strtotime("now")."_".$_FILES['file']['name'];
$content = file_get_contents($_FILES['file']['tmp_name']);
Storage::disk('uploadedfiles')->put($file_name,$content);
}
Download File from Storage Folder
Route::get('download/files/{filename}', function($filename) {
$file = Storage::disk('uploadedfiles')->download($filename);
return $file;
});
Laravel8
Create a link
<a href="{{ url('download?path='. $user->avatar) }}">
Download
</a>
Define a route
Route::get('download', [DownloadController::class,'download']);
Handle it
public function download(Request $request){
return Storage::download($request->path);
}

Resources