68

I am trying to move the public folder to other place. However, I can't find the place to modify public_path() variable. Now, the 'public_path()' return the wrong path of folder.

Where can I set the variable for public_path()?

Moppo
  • 18,797
  • 5
  • 65
  • 64
user1995781
  • 19,085
  • 45
  • 135
  • 236

7 Answers7

82

You can override the public path using ioc container :

What worked for me flawlessly was adding to public/index.php the following three lines:

 $app->bind('path.public', function() {
    return __DIR__;
});

For more detailed explanation click here

Jigs Virani
  • 4,067
  • 1
  • 23
  • 24
  • 7
    Tried with your solution, it works on display webpages. However, it doesn't work for artisan command. The artisan still refer `public_path` to the default public path. – user1995781 Aug 01 '15 at 15:55
  • 4
    @user1995781 you can apply the same code in the file "artisan" which is the "index.php" of the command. – Spir May 07 '18 at 13:43
  • 2
    Thanks for providing the reference link too. – Hemant Kumar Nov 28 '19 at 10:33
49

While accepted answer works for requests coming from HTTP, it will not work for artisan.

If you need artisan to know your custom public path, you need to extend Laravel main Application class. I know it sounds scary, but it's actually very simple.

All you need to do is following:
Step 1: In the file: bootstrap/app.php change the very first declaration of $app variable

$app = new Illuminate\Foundation\Application(
    realpath(__DIR__.'/../')
);

to reflect your own custom Application class:

$app = new App\Application(
    realpath(__DIR__.'/../')
);

Step 2: Define your custom Application class somewhere. For example in app/Application.php

<?php namespace App;

class Application extends \Illuminate\Foundation\Application
{
}

Congrats! You have extended Laravel core Application class.

Step 3: Overwrite the publicPath method. Copy and paste Laravel original method to your new class and change it to your needs. In my particular case I did like this:

public function publicPath()
{
    return $this->basePath.DIRECTORY_SEPARATOR.'..'.DIRECTORY_SEPARATOR.'public_html';
}

That's it! You can overwrite any method in Application class the same way.

ruuter
  • 2,453
  • 2
  • 30
  • 44
  • Regarding `Step 3` ... where in /bootstrap/app.php should I be putting that override? – dcolumbus Nov 13 '15 at 20:39
  • @dcolumbus This should not go to bootstrap/app.php file. It should be in you custom `Application` class, which is extending Laravel core (step 2) and therefor overriding Laravel core `publicPath` method. – ruuter Nov 16 '15 at 08:32
  • I originally had the declaration in my index.php file, which worked for regular http requests. I came to an error when running PHPunit, it said "File (...) not defined in asset manifest". The reason was that it couldn't find the asset manifest because it wasn't looking in the right public folder. The solution you demonstrate here solved that. So it works for HTTP, artisan ánd PHPunit. It should really be the accepted answer! – mcProgrammer Sep 22 '16 at 07:53
  • Scary yea, but it works. But i don't understand why this part `'..'.DIRECTORY_SEPARATOR.` I have this `return $this->basePath.DIRECTORY_SEPARATOR.'public_html'` for shared host. – FONGOH MARTIN May 16 '17 at 17:00
  • 1
    @FONGOHMARTIN `..` is a name for parent directory in Linux, while `.` is a current directory. Which means, I have public_html dir one level up from the basePath, not inside it. – ruuter May 16 '17 at 18:51
  • Yea @ruuter you right. I fixed it. Your approach is perfectly correct. Sorry for the mixup. – FONGOH MARTIN May 23 '17 at 18:27
  • I did this, but im not understanding how to adjust blade relative/ or root paths. I thought that would fix it there too. Note, my public path had to be in a subdir, since laravel is one piece of a larger site, e.g. `../html/public` blade e.g. `{{asset('css/styles.css')}}` is not finding correct path, but `{{asset('public/css/styles.css')}}` is. how can i eliminate the `public/` portion? – blamb Sep 29 '17 at 17:44
  • @blamb it should work. If `public/css` works, then your public path must be set one level too high. It points to `html` not `html/public` – ruuter Sep 29 '17 at 18:29
27

I suggest you add it in app/Providers/AppServiceProvider.php:

public function register()
{
    $this->app->bind('path.public', function() {
        return realpath(base_path().'/../public_html');
    });
}

This affects artisan as well.

Broshi
  • 3,334
  • 5
  • 37
  • 52
10

In laravel 5.6 this work for me ... adding this code to bootstrap/app.php :

$app->bind('path.public', function() {
    return realpath(__DIR__.'/../');
});

where __DIR__.'/../' is path to your public folder

AnasSafi
  • 5,353
  • 1
  • 35
  • 38
4

In my case in Laravel 6.0 work this.
This file: bootstrap/app.php

......
$app = new Illuminate\Foundation\Application(
    $_ENV['APP_BASE_PATH'] ?? dirname(__DIR__) );

$app->bind('path.public', function() {
    return realpath(__DIR__.'/../httpdocs'); });
.....

I changed the public_path() folder, this example is with httpdocs folder, you can put watherver you want.

Unai Susperregi
  • 398
  • 3
  • 16
3
$app->bind('path.public', function() {
  return base_path().'/mynewpublic';
});
Tunaki
  • 132,869
  • 46
  • 340
  • 423
macieks
  • 452
  • 6
  • 13
0

Have you tried updating the filesystems.php

'disks' => [

    'public' => [
       'driver' => 'local',
             'root' => env('PATH_PUBLIC'),
       'visibility' => 'public',
       'url' => env('SITE_ROOT'),
    ],
Harry Bosh
  • 3,611
  • 2
  • 36
  • 34