Mã hoá tham số trong url bằng SqidUrl
Tự động mã hóa URL bằng Sqids + Chữ ký HMAC mà không cần sửa view, route, controller
✔ Không sửa Controller.
✔ Không sửa Route.
✔ Không sửa View.
✔ Không sửa Model.
✔ Tự động encode.
✔ Tự động decode.
✔ Có thể bật tắt.
✔ Có chữ ký chống sửa URL.
✔ Tốc độ gần như không ảnh hưởng.
Cấu trúc tổng quan:
app
│
├── Http
│ └── Middleware
│ └── DecodeSqidRouteParameters.php
│
├── Providers
│ └── SqidUrlServiceProvider.php
│
└── Support
└── SqidUrl
├── SqidUrl.php
└── SqidUrlGenerator.php
config
└── sqid_url.php
bootstrap
├── app.php
└── providers.php
.env
Bước 1: Cài Sqids
composer require sqids/sqids
Bước 2: Khai báo .env; nếu muốn tắt chế độ mã thì đặt: SQID_URL_ENABLED=false rồi php artisan optimize:clear
SQID_URL_ENABLED=true
SQID_URL_MIN_LENGTH=8
SQID_URL_SIGNED=true
SQID_URL_SIGNATURE_LENGTH=10
Bước 3. Tạo file config/sqid_url.php
<?php
return [
'enabled' => env('SQID_URL_ENABLED', false),
'min_length' => env('SQID_URL_MIN_LENGTH', 8),
'signed' => env('SQID_URL_SIGNED', true),
'signature_length' => env('SQID_URL_SIGNATURE_LENGTH', 10),
'separator' => '~',
'ignore_parameters' => [
'page',
'q',
'keyword',
'search',
'sort',
'direction',
'date',
'from_date',
'to_date',
'month',
'year',
'slug',
'token',
'locale',
],
];
Bước 4. Tạo app/Support/SqidUrl/SqidUrl.php
<?php
namespace App\Support\SqidUrl;
use Sqids\Sqids;
class SqidUrl
{
protected static ?Sqids $sqids = null;
public static function enabled(): bool
{
return (bool) config('sqid_url.enabled', false);
}
public static function signed(): bool
{
return (bool) config('sqid_url.signed', true);
}
public static function instance(): Sqids
{
if (! static::$sqids) {
static::$sqids = new Sqids(
minLength: (int) config('sqid_url.min_length', 8)
);
}
return static::$sqids;
}
public static function encode(int|string $id): string
{
$code = static::instance()->encode([(int) $id]);
if (! static::signed()) {
return $code;
}
return $code . config('sqid_url.separator', '~') . static::signature($code);
}
public static function decode(string $value): ?int
{
if (static::signed()) {
$separator = config('sqid_url.separator', '~');
if (! str_contains($value, $separator)) {
return null;
}
[$code, $signature] = explode($separator, $value, 2);
if (! hash_equals(static::signature($code), $signature)) {
return null;
}
$decoded = static::instance()->decode($code);
return $decoded[0] ?? null;
}
$decoded = static::instance()->decode($value);
return $decoded[0] ?? null;
}
public static function looksSigned(string $value): bool
{
return str_contains($value, config('sqid_url.separator', '~'));
}
protected static function signature(string $code): string
{
$key = config('app.key');
$hash = hash_hmac('sha256', $code, $key, true);
$signature = rtrim(strtr(base64_encode($hash), '+/', '-_'), '=');
return substr($signature, 0, (int) config('sqid_url.signature_length', 10));
}
public static function shouldHandleParameter(?string $name): bool
{
if (! $name) {
return false;
}
return ! in_array(
$name,
config('sqid_url.ignore_parameters', []),
true
);
}
}
Bước 5: Tạo app/Support/SqidUrl/SqidUrlGenerator.php
<?php
namespace App\Support\SqidUrl;
use Illuminate\Contracts\Routing\UrlRoutable;
use Illuminate\Routing\Route;
use Illuminate\Routing\UrlGenerator;
class SqidUrlGenerator extends UrlGenerator
{
public function toRoute($route, $parameters, $absolute)
{
if (SqidUrl::enabled() && $route instanceof Route) {
$parameters = $this->encodeRouteParameters($route, $parameters);
}
return parent::toRoute($route, $parameters, $absolute);
}
protected function encodeRouteParameters(Route $route, $parameters): array
{
$parameters = is_array($parameters) ? $parameters : [$parameters];
$names = $route->parameterNames();
foreach ($parameters as $key => $value) {
$paramName = is_string($key)
? $key
: ($names[$key] ?? null);
if (! SqidUrl::shouldHandleParameter($paramName)) {
continue;
}
if ($value instanceof UrlRoutable) {
$value = $value->getRouteKey();
}
if (is_numeric($value) && (int) $value > 0) {
$parameters[$key] = SqidUrl::encode($value);
}
}
return $parameters;
}
}
Bước 6: Tạo app/Http/Middleware/DecodeSqidRouteParameters.php
<?php
namespace App\Http\Middleware;
use App\Support\SqidUrl\SqidUrl;
use Closure;
use Illuminate\Http\Request;
class DecodeSqidRouteParameters
{
public function handle(Request $request, Closure $next)
{
if (! SqidUrl::enabled()) {
return $next($request);
}
$route = $request->route();
if (! $route) {
return $next($request);
}
foreach ($route->parameters() as $name => $value) {
if (! SqidUrl::shouldHandleParameter($name)) {
continue;
}
if (! is_string($value)) {
continue;
}
if (is_numeric($value)) {
continue;
}
$decoded = SqidUrl::decode($value);
if ($decoded) {
$route->setParameter($name, $decoded);
continue;
}
if (SqidUrl::signed() && SqidUrl::looksSigned($value)) {
abort(403, 'Invalid URL signature.');
}
}
return $next($request);
}
}
Bước 7: Tạo app/Providers/SqidUrlServiceProvider.php
<?php
namespace App\Providers;
use App\Support\SqidUrl\SqidUrlGenerator;
use Illuminate\Support\ServiceProvider;
class SqidUrlServiceProvider extends ServiceProvider
{
public function register(): void
{
$this->app->singleton('url', function ($app) {
$url = new SqidUrlGenerator(
$app['router']->getRoutes(),
$app['request'],
$app['config']['app.asset_url'] ?? null
);
$url->setSessionResolver(function () use ($app) {
return $app->bound('session') ? $app['session'] : null;
});
$url->setKeyResolver(function () use ($app) {
return $app['config']['app.key'];
});
$app->rebinding('request', function ($app, $request) {
$app['url']->setRequest($request);
});
return $url;
});
}
}
Bước 8. Đăng ký Provider: bootstrap/providers.php
return [
......
App\Providers\SqidUrlServiceProvider::class,
];
Bước 9. Đăng ký Middleware: bootstrap/app.php
- thêm ở đẩu file: use App\Http\Middleware\DecodeSqidRouteParameters;
- tìm đến:
->withMiddleware(function (Middleware $middleware) {
//thêm đoạn này vào
$middleware->web(prepend: [
DecodeSqidRouteParameters::class,
]);
})
Bước 10: Xoá cache
php artisan optimize:clear
https://tritue.edu.vn/tuecode/tracnghiem30/site/data/YVdRc01qVXpMRjl5YjNWMFpTeGlZV2wyYVdWMEwzQnZjM1F2ZG1sbGR3PT0%3D