You can override the public path using ioc container :
App::bind('path.public', function() {
return base_path().'/public_html';
});
Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.
I have my public directory named public_html instead of public. So where do I change this setting?
I have a packages that uses $this->app['path.public'], but that package is trying to use public instead of what I want, public_html. So how do I tell Laravel 5 to use public_html?
You can override the public path using ioc container :
App::bind('path.public', function() {
return base_path().'/public_html';
});
Thanks mate. I added it to AppServiceProvider.php.
<?php namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider {
...
public function register()
{
$this->app->bind('path.public', function() {
return base_path().'/public_html';
});
}
}
You could open index.php (in your public directory) and change:
/*
|--------------------------------------------------------------------------
| Turn On The Lights
|--------------------------------------------------------------------------
|
| We need to illuminate PHP development, so let us turn on the lights.
| This bootstraps the framework and gets it ready for use, then it
| will load up this application so that we can run it and send
| the responses back to the browser and delight our users.
|
*/
$app = require_once __DIR__.'/../bootstrap/app.php';
// set the public path to this directory
$app->bind('path.public', function() {
return __DIR__;
});
Now you dont need to change your public path when your public directory has changed.
Elixir has a hardcoded public path! Do not forget to set the changed public path in the Elixir config.
I placed it inside the bootstrap/app.php file. I tried placing it inside a service provider, but then you can't use public_path() in a config file, which makes packages like pingpong modules or stylist not working properly because they keep publishing to /public
$app = new Illuminate\Foundation\Application(
realpath(__DIR__ . '/../')
);
$app->bind('path.public', function ()
{
return base_path() . '/public_html';
});
changing the public folder name seems like a bit of a hustle for me (I had to edit elixir version.js then I realized that elixir was still looking for my assets in the public folder instead of the renamed public folder)
I used a symlink :
ln -s public public_html
how would you set this based on APP_ENV? locally, the default public folder location applies but when i deploy to production, it's different and varies project to project since it's a shared environment/one server, multiple apps.
in laravel 4 i had to mess with index.php and bootstrap files coz i had a conditional statement that checks the value of APP_ENV. this was also tricky when running php artisan from the CLI, luckily there's a flag you can use to set the ENV during runtime.
it would be great if it can be set in the .env file. is this possible?
As a new Laravel user, I find it staggering that there is no simple, elegant, centralized, and environment-aware means by which to define both the "private" and the "public" filesystem paths that are referenced throughout the application.
While it may make sense to nest the public directory beneath the application root for source-control and packaging/distribution purposes, that is an unrealistic structure in a real-world deployment scenario.
The scenario that the OP describes is far more realistic, wherein the "public" directory is actually the web-server's "document root", and the rest of the application resides above and outside of the document root.
The default directory structure inspires less capable users to dump the entire application (including everything outside of the public directory) into the web-server's document root. This practice should be discouraged, as it exposes a broad attack-vector: the ability to access application resources via HTTP.
One might argue that a properly-configured server does not expose the application to unnecessary risk when Laravel is deployed as-is, but there is no guarantee as to the environment's viability. If PHP is upgraded and the process goes awry, thereby causing the web-server to present .php files as raw file downloads, an active attacker could conceivably "scrape" most or all source code. This type of mis-configuration has the potential to expose application details, ranging from filesystem paths to various credentials (cringe).
My research on this subject has yielded five possible approaches to using a more sensible "public" path (and I'm sure there are others):
1.)
Using a symbolic link (or junction point, on NTFS volumes)
This method is not portable. While it may be an acceptable solution for a solo developer, in a collaborative development environment, it's a non-option because it doesn't travel with the application source-code and is therefore cumbersome to implement consistently.
2.)
Using IoC container in /app/Providers/AppServiceProvider.php
This is not a bad approach, but as @patrickbrouwers notes, it suffers from a considerable flaw: the public_path() helper function remains unaffected in the context of configuration files, which causes the public path to be defined incorrectly in many third-party packages.
Also, if I were going to implement this approach, I would create a new Service Provider, rather than modify the included AppServiceProvider class (only because doing so reduces the likelihood of having to merge-in upstream changes).
3.)
Using IoC container in /bootstrap/app.php
This works well enough -- until environment-detection via the .env file is necessary. Any attempt to access $app->environment() at this stage yields, Uncaught exception 'ReflectionException' with message 'Class env does not exist'. Furthermore, in order to minimize the impact of upstream changes, my preference is to limit customization to as few files as possible, which brings me to the next method.
4.)
Using IoC container in /index.php
Given that /public/index.php already requires modifications to function out-of-the-box on many systems (the fact that realpath() is not used in the require and require_once statements causes the application to fail fatally in environments in which PHP enforces open_basedir restrictions, which do not allow nor resolve relative path notations, such as ../), my preference would be to make this change (to the public path definition) in the same file.
But, as with the above method, attempts to perform environment-detection cause a fatal error in this context, because the required resources have not yet been loaded.
5.)
Using custom IoC container in /app/Providers/*.php, coupled with overriding public_path() helper function
I settled on this method because it is the only method that solves the third-party package configuration problem (mentioned in method #2) and accounts for environment-detection.
The public_path() helper function (defined in /vendor/laravel/framework/src/Illuminate/Foundation/helpers.php) is wrapped in if ( ! function_exists('public_path')), so, if a function by the same name is defined before this instance is referenced, it becomes possible to override its functionality.
Given that I have already had to modify index.php (due to the open_basedir problems that I explained in #4), I elected to make this change in index.php, too.
//Defining this function here causes the helper function by the same name to be
//skipped, thereby allowing its functionality to be overridden. This is
//required to use a "non-standard" location for Laravel's "public" directory.
function public_path($path = '')
{
return realpath(__DIR__);
}
Next, I created a custom Service Provider (instead of using AppServiceProvider.php, the reasons for which I explain in #2):
php artisan make:provider MyCustomServiceProvider
The file is created at /app/Providers/MyCustomServiceProvider.php. The register() method can then be populated with something like the following:
/**
* Register the application services.
*
* @return void
*/
public function register()
{
if (env('PUBLIC_PATH') !== NULL) {
//An example that demonstrates setting Laravel's public path.
$this->app['path.public'] = env('PUBLIC_PATH');
//An example that demonstrates setting a third-party config value.
$this->app['config']->set('cartalyst.themes.paths', array(env('PUBLIC_PATH') . DIRECTORY_SEPARATOR . 'themes'));
}
//An example that demonstrates environment-detection.
if ($this->app->environment() === 'local') {
}
elseif ($this->app->environment() === 'development') {
}
elseif ($this->app->environment() === 'test') {
}
elseif ($this->app->environment() === 'production') {
}
}
At this point, everything seems to be working over HTTP. And while all of the artisan commands that I've tried have worked as expected, I have not exhausted all possible CLI scenarios.
I welcome any comments, improvements, or other feedback regarding this approach.
Thanks to everyone above for contributing to this solution!
You shouldn't call \App::bind(...) inside index.php because in this way it wouldn`t be executed when you run the application from the command line or in the case of the queue jobs.
So that it works from both Http and Console, add to your bootstrap/app.php
$app->bind('path.public', function() {
return base_path().'/public_html';
});
@mtvs_dev Good point about not using App::bind() in index.php. And this reason is in addition to the reason I describe in my first post within this thread (item 4).
@iboinas There are problems with the approach you describe above. Most notably, the problem that I address in item 3 above: this approach is incompatible with environment-detection via the .env file.
@cbj4074 I have tried to implement your solution but it does not work :/ It gives me the following error when I run php artisan serve:
[ErrorException]
chdir(): No such file or directory (errno 2)
Here's what I edited:
public/index.php: I added this:
function public_path($path = '')
{
return realpath(__DIR__);
}
after this:
$app = require_once __DIR__ . '/../private/bootstrap/app.php';
private/app/Providers/PublicPathServiceProvider.php:
<?php namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class PublicPathServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* @return void
*/
public function boot()
{
//
}
/**
* Register the application services.
*
* @return void
*/
public function register()
{
if (env('PUBLIC_PATH') !== NULL) {
//An example that demonstrates setting Laravel's public path.
$this->app['path.public'] = env('PUBLIC_PATH');
// An example that demonstrates setting a third-party config value.
//$this->app['config']
// ->set('cartalyst.themes.paths',
// array(env('PUBLIC_PATH') . DIRECTORY_SEPARATOR . 'themes'));
} else {
$this->app['path.public'] = base_path() . '/../public';
}
// Possible environment changes
if ($this->app->environment() === 'local') {
} elseif ($this->app->environment() === 'development') {
} elseif ($this->app->environment() === 'test') {
} elseif ($this->app->environment() === 'production') {
}
}
}
@ferrolho , I apologize for the long-delayed reply. I could have sworn that I had enabled notifications for this thread, but, apparently, I had not.
I don't use PHP's built-in HTTP server via Laravel, so I had not tried php artisan serve, but I just tried it on my development server and the HTTP server at least starts:
# php artisan serve
Laravel development server started on http://localhost:8000/
I receive a 500 error when I try to browse to http://localhost:8000, but that could be for so many different reasons. I have a particularly complex stack configuration (out of necessity), so I'm not at all surprised that PHP's built-in HTTP server doesn't work for me out-of-the-box. I probably need to pass it a path, at a minimum, but, unfortunately, I can't spare the time to troubleshoot it further.
I won't belabor the issues that Taylor (and others) raise in this discussion, but I urge you to consider using Homestead, plain-old VirtualBox, or something better suited to the task:
https://github.com/laravel/laravel/commit/80fb944e45801cec81b459f73892dbfc80c39de6
But let's try to work through your issue, nonetheless.
Firstly, this bit should be placed at the top of index.php, not the bottom:
function public_path($path = '')
{
return realpath(__DIR__);
}
But in looking back at my notes regarding this subject, I appear to have gone a slightly different direction some time after my initial post in this thread.
I removed that function in favor of what seems to be a slightly more involved, although less error-prone, approach.
I've prepared a GitHub Gist of the changes that I typically make to index.php:
https://gist.github.com/cbj4074/9bb210706f8f2fdd61b0
All one should have to do is change lines 23 and 24 to suit his environment. The default values are intended to work with a "stock" Laravel configuration.
Regarding the Service Provider, your code looks okay to me.
You remembered to add the Service Provider to the 'providers' array in /config/app.php, correct?
If the revisions to your index.php don't solve the problem, I'd need additional details regarding the error that you receive:
[ErrorException]
chdir(): No such file or directory (errno 2)
I suspect that this is related to using PHP's built-in HTTP server without specifying a path to the document root. Because I don't use it, I'm not sure how php artisan serve sets the web-server's document root, but you might experiment with starting the server manually and see if you can get it to behave. Something like this:
php -S localhost:8000 -t public/
where public/ represents the correct path on your particular system. If you manage to get that to work, then we may have yet one more place within the Laravel source to override the public path definition.
Please do let us know what you find! Again, sorry for the late reply!
Now I created new project (Laravel 5.1) and just I rename "public" folder to "www" and everything works fine, nothing need be set ... How is this possible?
@inyansuta did you moved the application files outside the web root?
@FrancoM I did not move application files, application files are still beyond the standard root of the web ... As I say, I only renamed the folder public (to www), I have not changed anything, and everything works.
@inyansuta My best guess is that Laravel is using PHP's __DIR__ constant, so as long as your relative directory structure is the same, everything "just works".
It's when the relative structure changes that employing the measures discussed in this thread becomes necessary.
For anyone interested, the right way to do it is mentioned here. http://stackoverflow.com/questions/31758901/laravel-5-change-public-path
The second answer is the right answer, where you extend the Application class. So the path is available to artisan as well.
@shanecp Thank you for sharing this tip! I'm delighted to find that this does, in fact, do the job! Very simple and elegant as compared to some of the alternatives posited (including my own).
I still had to modify index.php because my relative directory structure (between Laravel's "base path" and its "public path") deviates from the default, but this approach is definitely the best I've seen to date.
Thanks again for taking the time to let us know!
@shanecp Thanks for your in depth replies on this subject. But I seem to have the same problem on your solution and the soultion on stack exchange.
My error is "Object not found! Error 404"
Where in public/index.php do you put this:
function public_path($path = '')
{
return realpath(__DIR__);
}
And if I wanted my new path to be public_html would I do this in Providers/MyCustomServiceProvider.php:
$this->app['path.public_html'] = env('PUBLIC_PATH');
Edit: I forgot to mention that I am using Laravel 5.1 on a windows 7 machine using xampp.
Thanks :)
With this "new"/"better" method, you don't put that in /public/index.php. In fact, you don't put that function anywhere.
In the simplest terms possible (basically, duplicating the correct [though, not accepted] answer on StackOverflow):
1.) In /bootstrap/app.php (not /public/index.php!), change the $app variable's declaration to this:
$app = new Illuminate\Foundation\Application(
realpath(__DIR__.'/../')
);
To be clear, in an unmodified installation, the lines to be replaced with the above snippet are here: https://github.com/laravel/laravel/blob/master/bootstrap/app.php#L14-L16
2.) Create the file /app/Application.php. Populate it with the following contents:
<?php namespace App;
class Application extends \Illuminate\Foundation\Application
{
public function publicPath()
{
return $this->basePath . '/../../web';
}
}
Be sure to change the return value in the above method to reflect the actual path to the desired public directory on your system.
That's all there is to it! Happy to answer any questions if you're still stuck.
Rename the server.php in the your Laravel root folder to index.php and copy the .htaccess file from /public directory to your Laravel root folder. -- Thats it !! :)
Do not follow @inforox recommendation since your .env file will be exposed.
Those that say just rename public folder - this is ok, but the public_path() helper will still point to public and create a folder if you try and save something there.
I am going to give your method a try @warmwhisky
Although I would like to know how this method will work with pulling from repos.
My dir structure is as follows.
/home/myaccount/public_html/myproject/public/
When I push updates to my codebase on github will I need to pull in the changes to my myproject/public/ folder and then copy that folder to my /home/myaccount/public_html folder again so that also receives the changes.
This is doable but seems a little convoluted.
Thanks
@drfishflan if public_html is your document root then what you have described is the perfect way to have your site hacked
This is the errors message, when I try to upload image (1/1) NotWritableException Can't write image data to path (/home/congo/LaraU/public_html/images/1500404560.jpg)
@Ivan-Tshimanga start a new thread with your specific issue rather than tagging something unrelated to the end of a two-year old thread,
I have read through this thread but not sure of the current right solution especially for Laravel 5.5 ?
My case: using shared hosting, so my public directory is
/home//public_html/
Initially I uploaded Laravel directory into public_html folder . The system worked with the quirks of having the URL www.mydomain.xyz/public/ as the URL to root.
Then I tried this approach of modifying the path:
So my laravel folder resides here:
/home//
Copied the content of /public into /public_html
Edited the index.php file within /public_html
FROM: require DIR.'/../vendor/autoload.php'; $app = require_once DIR.'/../bootstrap/app.php';
TO: require '/home//vendor/autoload.php'; $app = require_once '/home//bootstrap/app.php';
And now my main page loaded fine (welcome view) as stated in my web.php route file
Route::get('/', function () { return view('welcome'); });
===================================================================
MY ISSUE:
However, any other routes would fail
"Not Found
The requested URL / was not found on this server"
Any other steps that i needed to do?
I tried:
loading a simple jpg file stored in public_html folder, and that worked fine (mydomain.xyz/test.jpg )
changed the route for root to return invalid view, that threw a Laravel error
Route::get('/', function () { return view('test'); });
"InvalidArgumentException View [test] not found."
Route::get('/main', function () { return view('tempview.main'); });
What did i miss? .htaccess changes? another place where i need to change the public path?
@Snapey @ejdelmonico @alhoqbani : thoughts?
@mohdm if you want people to spot that you have posted an issue, don't do it on an ancient thread
Your install looks fine but did you remember to copy / create .htaccess in your public_html folder.
Also, with the setup you have described, editing index.php should not have been necessary
@Snapey : sorry, i commented here because this is the thread that i followed. And i just realised that this forum had removed the sharp bracket i used in explaining the issue (and i did not use the formatting properly). perhaps it is better to read in SO of the same question i asked.
I do have .htaccess file in my public_html directory, it looks like this.
# Installation directory
RewriteBase /
Options -Indexes
# Turn on URL rewriting
RewriteEngine On```
I've reverted the modification to my index.php file, yeah the domain loaded fine, but the issue still persist. Anything else i can try or should try?
I might just use the default public path (so it would be mydomain.com/public/ ) to access laravel public directory as that worked fine but not sure how i can override to remove the /public from the URL (and also the issue with my .env file residing on my public folder).
Please or to participate in this conversation.