laravel / framework

The Laravel Framework.
https://laravel.com
MIT License
32.31k stars 10.95k forks source link

The route helper method ignores https scheme #48134

Closed Stunext closed 1 year ago

Stunext commented 1 year ago

Laravel Version

10.19.0

PHP Version

8.2.8

Database Driver & Version

PostgreSQL 14

Description

As the name of the issue suggests, the "route" helper is not taking into account the schema of the application url.

Taking as an example that in my .env file I have the following:

APP_URL=https://example.com

And in my web routes file I have the route:

Route::get('/home', fn () => view('welcome'))->name("welcome");

If I use the route() helper to get the absolute URL:

$route = route('welcome', [], true);

The resulting path is as follows:

http://example.com/home

When it should be:

https://example.com/home

Steps To Reproduce

You can use my previous explanation as an example, it is very easy to reproduce the error. It is a simple example, in my code I have routes with parameters and other things. The solution that I apply for example is:

$route = config('app.url') . route('welcome', [], false);

But it seems to me a bad implementation.

crynobone commented 1 year ago

Hey there, thanks for reporting this issue.

We'll need more info and/or code to debug this further. Can you please create a repository with the command below, commit the code that reproduces the issue as one separate commit on the main/master branch and share the repository here?

Please make sure that you have the latest version of the Laravel installer in order to run this command. Please also make sure you have both Git & the GitHub CLI tool properly set up.

laravel new bug-report --github="--public"

Do not amend and create a separate commit with your custom changes. After you've posted the repository, we'll try to reproduce the issue.

Thanks!

BlazeIsClone commented 1 year ago

The issue might be here: https://github.com/laravel/framework/blob/7f287ed2ee8aa0067b66c002b582f8ff7eedc00c/src/Illuminate/Http/Request.php#L91C1-L99C6

I added a conditional check to override the default behaviour and to get the app URL from the config.

FYI, for the default behaviour, Laravel is using Symfony under the hood and Symfony checks the PHP superglobal $_SERVER['SERVER_PORT'] to format the base domain scheme.

    /**
     * Get the root URL for the application.
     *
     * @return string
     */
    public function root()
    {
        $schemeAndHttpHost = $this->getSchemeAndHttpHost(); 

        if(config('app.url')) {
            $schemeAndHttpHost = config('app.url');
        }

        return rtrim($schemeAndHttpHost.$this->getBaseUrl(), '/');
    }

The syntax that I've used might need some optimization so I'm not going to submit a PR.

BlazeIsClone commented 1 year ago

@Stunext in your case since you tested on localhost the PHP superglobal SERVER_PORT gets set to 80 and Symfony will determine that your domain scheme is http:// since your on port 80.

Stunext commented 1 year ago

@BlazeIsClone Hmmmm actually I am using a virtual host like "example.test" in nginx using a self signed ssl cert with mkcert.

timacdonald commented 1 year ago

@Stunext the route helper will use the APP_URL only on the CLI, e.g., in queued jobs and artisan commands. When in a web context, the route helper will use the browsers URL, e.g., the HOST.

This means that if you have:

APP_URL=https://example.test
Route::get('/', fn () => 'The home URL is: '.route('home'))->name('home');

and you run

php artisan tinker --execute="echo route('home')"

it will output the following, noting the https scheme:

https://example.test

If you now serve the site unsecured, with something like valet link example, the homepage will output the following, noting the http scheme.

The home URL is: http://example.test

If you now secure the site, e.g., with valet secure, it will output the following:

The home URL is: https://example.test

If you want all of these to have a consistent scheme, you need to call:

use Illuminate\Support\Facades\URL;

URL::forceScheme('https');

in a service provider's boot method.

You should know, however, that if I also - on the SAME application - serve the site from a different URL, e.g., with valet link different-domain, the scheme will stay https, however the root domain will not use the domain in the environment when visiting via a browser.

If I now visit http://different-domain.test I will see the following output:

The home URL is: http://different-domain.test

The general idea here is that the route helper will always generate a URL to the scheme and domain you are currently on in your web browser. It uses the environment value as a fallback on CLI when that information is not present.