I have a Laravel 5.2 app and inside the public_html folder I have some assets stored in a subfolder called metronic as I am using a theme called metronic and wanted to keep it all bundled in one place to make updating it easier.
I have linked to these assets using the URL::asset() method like so:
<script src="{!! URL::asset('metronic/global/plugins/fullCalendar/fullcalendar/fullcalendar.js') !!}"></script>
This generates the following URL:
http://www.mywebsite.com/metronic/global/plugins/fullCalendar/fullcalendar/fullcalendar.js
For some reason this is working fine locally but when I run it on my production server the request is going through Laravel. I have some middleware that checks whether or not to show the coming soon page and this is being run and so rather than the script being fetched the holding page is just being run. This is the content of the middleware:
<?php namespace App\Http\Middleware;
use Closure;
use Request;
use Route;
use Session;
class HoldingPageCheck {
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if(env('HOLDING_PAGE')==true && (!$request->is('coming-soon') && !$request->is('member/subscribe') && !$request->is('migrate') && !$request->is('contact') && $request->segment(1)!='admin')) {
Session::reflash();
return redirect(route('holding_page'));
}
return $next($request);
}
}
It doesn't make any sense to me why Laravel would be interfering with an asset request it should just bypass Laravel entirely shouldn't it when a request for a JS file is made?
Found the problem, it was because I was using camel case in the path to the script. Locally with xampp it didn't mind but obviously my live environment was case sensitive.
Related
I am building an application, where there would be main application users (say support users) and separate client users (the application can have many different clients and each clients can have many users), every client has its own separate database, but the codebase for the entire application would be the same for every client.
What I wanted to achieve is, before calling auth in the main application, I wanted to call a middleware, which would detect a parameter (say db_slug) from request URL and according to that param it will change the DB respectively. And then login them to the client user to their respective DB.
Note: The client users will not be a part of the main DB. Their record would be only in their Client's DB.
But I am failing to do so, as my auth middleware is called first, before my custom middleware, and on accessing auth routes, it is saying unauthenticated, since that specific client user is not a part of my main application.
Note: I am using sanctum auth.
What I tried is, created a middleware called ClientDBMiddleware
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use DB;
use Config;
class ClientDBMiddleware
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle(Request $request, Closure $next)
{
if($request->has('db_slug')){
$dbSlug = $request->db_slug;
DB::purge('mysql');
Config::set('database.connections.mysql.database', "db_$dbSlug");
}
return $next($request);
}
}
and applied it my api.php auth routes before auth middleware
Route::group(['middleware' => ['clientDB', 'auth:sanctum']], function () {
Route::get('/me', [UserController::class, 'me']);
});
Important Note :
If there is a better approach to achieve my required thing, then that would be highly appreciated, please help me with it.
Fairly new to Laravel and I'm trying to add a functionality that allows the user to switch between two languages by clicking a button in a header.blade.php file. So far I've got it so there's a test.php file in the respective lang directories with test strings and have managed to get <p>{{__('test.test')}}</p> to display the correct language when manually set. At the moment I'm not sure if this is actually calling the route to update the language or if the logic I have for updating it is wrong since I get no errors and I'm using barryvdh/laravel-debugbar to debug.
My logic for the button:
<button href="{{ url('language', config('app.locale') == 'en' ? 'fr' : 'en') }}">{{ config('app.locale') }}</button>
In routes/web.php:
Route::get('/language', 'LanguageController#show');
Route::post('/language/{lang}', 'LanguageController#update');
LanguageController.php, created via php artisan make:controller --api
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class LanguageController extends Controller
{
/**
* Display the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function show($id)
{
return App::getLocale();
}
/**
* Update the specified resource in storage.
*
* #param \Illuminate\Http\Request $request
* #param int $id
* #return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
//Tried the following
config(['app.locale' => $id]);
App::setlocale($id);
}
}
Questions:
Is this the correct way to update the language at runtime?
How can I tell if my api calls are being made?
How can I achieve this inside of a template .vue file?
Is making a Controller for the language redundant?
Would the inner HTML of my button change if the locale was changed?
Is affecting config files at runtime bad practice?
--Edit--
I should also mention that the only reason I made a controller for this is because I had the route calls in web.php use a function instead however, they stated they were Closure running php artisan route:list and with the research I found I couldn't tell if that was correct
You are on the right way, but there is something missing.
You can't use the configuration to edit at runtime the language.
Save local language in user Session and create a new middleware to set on each request the language saved in session.
I found this article that can help you, localization-laravel
Problem
I am creating a signed URL through laravels 'temporarySignedRoute' function copied and pasted from laravels signed routes documentation, on my web server the url comes out to a 403 invalid signature. The signed URL's work on my local machine but upon uploading it to my test server it gives the error shown below.
What I've tried
I have been searching for a solution for awhile now and have tried many that have been posted on stack overflow but nothing seems to solve my problem.
I have tried all of the following:
Forcing all routes to https through the AppServiceProvider, this forced all of the url's to be https but gave the same result.
I tried changing Nginx's configuration as described here.
I also tried adding the TrustProxies middleware with the proxies configured to '*' or all, like described in laravel's documentation on Trust Proxies, same result.
Stopped the web server from forcing the domain to https to test if it was just https causing it, same result.
-- UPDATE --
I went into vendor/laravel/framework/src/Illuminate/Routing/UrlGenerator.php while trying to search around for any clues in the project. I decided to datadump (dd) out the tokens it was comparing on my local and hosted projects and this was the result. Code shown below as well.
public function hasValidSignature(Request $request, $absolute = true)
{
$url = $absolute ? $request->url() : '/'.$request->path();
$original = rtrim($url.'?'.Arr::query(
Arr::except($request->query(), 'signature')
), '?');
$expires = $request->query('expires');
$signature = hash_hmac('sha256', $original, call_user_func($this->keyResolver));
dd($signature . " :: " . $request->query('signature', ''));
return hash_equals($signature, (string) $request->query('signature', '')) &&
! ($expires && Carbon::now()->getTimestamp() > $expires);
}
Local Project
Hosted Project
So the Token is not being passed through on my web server but is on my local. Also another thing I noticed is that the web servers token is always the same and never changes no matter what.
My current Nginx configuration can be viewed here.
My current virtual hosts configuration is here.
I think this might be the issue.
Try to change your location block in the config file to
try_files $uri $uri/ /index.php?$query_string;
I think you have missed the ? between index and query string.
Update this and make sure to reload your Nginx server.
sudo service nginx reload
Let me know if this works.
The post from Prince Kumar Barnwal fixed my issue back then, I recently rediscovered another version of this issue while attempting to use docker in the same setup and I thought I would post it here in case anyone has the same issue.
We are using a Proxy Server and certifying our docker laravel projects on that, all projects have the TrustProxies setup, then we forceHTTPS in the AppServiceProvider.php which makes AJAX calls work. This causes issues as the project itself is not encrypted but all urls it generates thinks it is since we are forcing it. When the proxy passes the URL in the request it is http, when the project expects HTTPS.
I found a solution to this, its not the most clean and theirs probably a better fix out there but I made a middleware that goes on all of the projects signed routes, basically it just changes the url in the request to be secure if the project is in production. This is not insecure as the proxy handles the security and this is ONLY on the signed routes.
Below is the middleware that goes ONLY on the signed routes.
<?php
namespace App\Http\Middleware;
use Closure;
class SecureSignedURL
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if(config('app.env') === 'production' || config('app.env') === 'staging') {
$request->server->set('HTTPS', 'ON');
}
return $next($request);
}
}
My web.php with the middleware, its defined as secure_signed_url in my Kernel.php
Route::group(['middleware' => ['secure_signed_Url', 'signed']], function () {
route::get('/exampleurl1', 'TestController#route_exampleurl1_signed')->name('exampleurl1.signed');
route::get('/exampleurl2', 'Template\TemplateController#route_exampleurl2_signed')->name('exampleurl2.signed');
});
Again I don't know if this is the best fix, this is a very obscure bug in Laravel. If you have any suggestions for a better way of fixing this I'm open to suggestions.
My Old Github Issue that may help: https://github.com/laravel/framework/pull/31434
This is not a Nginx error. That's how laravel handles invalid signed urls if you check the Illuminate\Routing\Middleware\ValidateSignature it throws an Illuminate\Routing\Exceptions\InvalidSignatureException which aborts the request with a 403 status. What I did,
Created a custom signed middleware which extends the actual ValidateSignature
<?php
namespace App\Http\Middleware;
use App\Exceptions\InvalidEmailVerificationException;
use Closure;
use Illuminate\Routing\Middleware\ValidateSignature as MiddleWare;
class ValidateSignature extends Middleware
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if ($request->hasValidSignature()) {
return $next($request);
}
throw new InvalidEmailVerificationException;
}
}
which throws a custom App\Exceptions\InvalidEmailVerificationException
<?php
namespace App\Exceptions;
use Symfony\Component\HttpKernel\Exception\HttpException;;
class InvalidEmailVerificationException extends HttpException
{
/**
* Create a new exception instance.
*
* #return void
*/
public function __construct()
{
parent::__construct(403, 'Your email verification token seems to be invalid.');
}
}
then change the signed middleware in your App\Http\Kernel.php $routeMiddleware to 'signed' => \App\Http\Middleware\ValidateSignature::class,
in your 403.blade.php view, you can display the message as
#if ($exception instanceof \App\Exceptions\InvalidEmailVerificationException)
<h1 class="text-ginormous">Snap!</h1>
<h4 class="quick-error-description">Verification token expired.</h4>
#if (session('resent'))
<div class="alert alert-success" role="alert">
{{ __('A fresh verification link has been sent to your email address.') }}
</div>
#endif
<p class="error-description">{{ $exception->getMessage() }}</p>
<a href="{{ route('verification.resend') }}" class="button-solid button-error mb-3" data-no-pjax>Email me a new link</a>
#endif
I'm using 2 languages in my Laravel 5.2 app. There is a simple password-reminder page I'm implementing currently, and for reasons unknown to me I have problems in sending the new-password email in the correct language.
Let's say I see the page in German. In the view of the page, I echo 2 values, using Facades:
echo App::getLocale();
echo Session::get('locale');
The page is served in German, so both values echo de.
Now, I enter an email address into the form and submit it. The input gets to a controller method and calls a library to send a new password to the user:
public function resetPassword() {
// Validate the input, retrieve the user...
Mailer::sendNewPasswordEmail($user); // Call to the library sending emails
}
Finally, in the library, I var_dump the same 2 values, like this:
public static function sendNewPasswordEmail($user) {
var_dump(App::getLocale());
var_dump(Session::get('locale'));
die;
}
In this case, Session::get('locale') still equals de, but App::getLocale() shows en.
Why, why, why?
In my email template, I'm using the Blade's #lang() directive. As far as I know, the directive checks the application locale to determine which translation to serve. In my case, the email is being sent always in English and I have no clue why App::getLocale() returns a different value in the view and during the next POST request I'm making.
This is not the first time this happens, btw. At times is seems that views "know" more about the actual application locale, than the controllers, models or libraries. Confusing.
Ideas?
Laravel 5.2 App_Locale is not persistent. the only way I've found to make locales work properlly is creating a middleware that calls App::setLocale() like this:
<?php namespace App\Http\Middleware;
use Closure;
use Session;
use App;
use Config;
class Locale {
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
App::setLocale(Session::get('locale'));
return $next($request);
}
}
Register your middleware on Kernel.php
protected $middleware = [
.
.
.
'App\Http\Middleware\Locale'
];
So I have an api-version middleware that I use in laravel 5 that I am trying to use in lumen. However it uses getAction() and setAction() in the middleware which isn't available to lumen ("yet"). If I do $request->route()[1] I can get the current route but updating that with the new route does no good. I have thought about cloning the request and modifying it but I can't tell what part of the request object I would need to "update".
Here are my routes:
$app->group(['middleware' => ['api-version']], function() use ($app) {
$app->get('users', '{api-namespace}\UsersController#index');
$app->get('vips/{per_page?}', '{api-namespace}\VipsController#index');
$app->get('vip/{id}/profile', '{api-namespace}\VipsController#showProfile');
$app->get('vip/{id}', '{api-namespace}\VipsController#show');
});
Can anyone tell me how i can update the request with my simple route update?
Found this in my search for a solution. Here's what I came up with using middleware in Lumen 5.4.
First, I created an ExtractApiVersionMiddleware that extracts the version from the Accept header. I used the accept header because not all headers passed are trusted and it is becoming "Best Practice": to pass API versions in this manner:
<?php
namespace App\Http\Middleware;
use Closure;
class ExtractApiVersionMiddleware
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
*
* #return mixed
*/
public function handle($request, Closure $next)
{
$app = app();
$version = "0";
foreach (explode(';', $request->header('accept')) as $frag) {
if (stristr($frag, "version=")) {
$version = str_replace("version=", "", $frag);
break;
}
}
if ($version != 0) {
$app->group(['namespace' => "App\Http\Controllers\V{$version}\Reductions"],
function () use ($app, $version) {
require base_path() . "/routes/web/v{$version}.php";
});
} else {
$app->group(['namespace' => 'App\Http\Controllers\V0'], function () use ($app, $version) {
require base_path() . "/routes/web/v0.php";
});
}
return $next($request);
}
}
Second, I namespaced my code according to versions (the legacy codebase hasn't died yet).
Third, I pass the version that the call uses in the Accept header
Accept: application/json;version=1
Fourth, I have separate route files for each supported version. So, instead of having a web.php for all my routes, I created a web folder under routes and I placed my version files in there v0.php & v1.php
So, when I make a request, the Middleware extracts the API version and based on the version number enables the appropriate route group. This keeps the versions clean and separate but still enables me to get 'creative' with my Models.
Hope this helps. I had to apply this solution because I wasn't sure about using Dingo API in pre-release form