framework: Route model binding parameter error passing a string with Postgres
- Laravel Version: 5.7.9
- PHP Version: 7.2.10
- Database Driver & Version: PostgreSQL 10.5
Description:
I noticed that the route model binding exists an error passing a string
variable when using the Postgres database, this does not happen with the MySQL database.
When I use the Postgres database, the route model binding if pass a parameter string it don’t abort and build the query with a string. When I use the MySQL database it abort and show error 404 the route is not found.
Steps To Reproduce:
Records
id | name |
---|---|
1 | John |
2 | Jean |
3 | Lian |
Routes
Route::get('/user/{user}', 'UserController@show');
UserController
public function show(User $user) {
return $user;
}
url abort
localhost/user/4
url does not abort
localhost/user/test
Error
SQLSTATE[22P02]: Invalid text representation: 7 ERROR: invalid input syntax for integer: "test" (SQL: select * from "users" where "id" = test limit 1)
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Reactions: 4
- Comments: 18 (10 by maintainers)
Commits related to this issue
- Add validation for route parameters (closes: #26239) — committed to matthijs/framework by matthijs 5 years ago
That would do the trick, sure, but it feels weird that you need to consider it (and litter your routes file with constraints) just because you’re using Postgres.
Do you have an idea for a fix?
We could wrap the query in a
try/catch
block and throw aModelNotFoundException
, but I don’t think that’s ideal. This makes it harder debug other issues like missing tables or misspelled columns.Or we use the model’s
$keyType
and check integer keys withctype_digit()
(ifgetRouteKeyName()
===getKeyName()
).@dwightwatson mariohbrino’s suggestion is checking that:
You’ll find Postgres has similar “Invalid text representation” exceptions for UUID columns that don’t allow any SQL integer or string value in the
SELECT
parameter binding. SoRouteServiceProvider
does turn into a regex fest:Instead of inferring from
Model@getKeyType()
A possible model-focused solution is to addgetRouteKeyType()
to indicate the type or pattern ofgetRouteKeyName()
:Now route pattern matching is spread across many model classes instead of all being located in
RouteServiceProvider
. However it would allow a project base model class to define everything in one spot without having to name the route bindings:I truthfully don’t see many problems with the current implementation other than a dozen or so explicit regex pattern lines? Do the docs just need explicit instructions for Postgres columns?
passing user submitted inputs to backticks is a seriously bad idea
you leave yourself vulnerable to shell injection / remote code execution
I’m facing the same issue in 2021 with Laravel 8. Really easy solution why not wrap the value in the query in back-ticks? Solves the issue for everyone. I wanted to return json for a Route::resource for which I use the ->missing() feature, but if a user passes in a string instead of an int I get the postgres related error. So I tried Route::pattern but this returns a html 404.
My solution is to overwrite your implicit findOrFail with the following in my model and it will work every time, sending back my ->missing json return statement
You also have to check the
$keyType
forint
/integer
. Otherwise, this breaks string primary keys.