Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

cooperino's avatar

Masking actual database IDs in URL

Right now I am using IDs in the URL to perform actions based on the IDs. for example:

my-site.com/contact/<contact_id>?parameter=<some_other_id>

But now I want to mask it, so it won't show the actual IDs. What is the best practice to do it?

Ty!

0 likes
10 replies
martinbean's avatar

@cooperino You have a couple of ways. You can either use a second identifier that isn’t auto-incrementing, like a UUID. Or you can use something like Hashids that encodes your primary key values to an alpha-numeric string. You can then decode that alpha-numeric string back to the original integer value(s):

public function show(string $hashid)
{
    // Decoding always returns an array.
    // To get the original ID, just pluck the first value from the array, if there is one.
    // See https://github.com/vinkla/hashids#pitfalls for more information.
    $ids = $this->hashids->decode($hashid);

    if (count($ids) === 0) {
        throw new ModelNotFoundException();
    }

    $id = $ids[0];

    $foo = Foo::findOrFail($id);
}

Obviously that’s pretty cumbersome to write in multiple controller actions, so you could wrap it up in a trait with a method for finding models by Hashid:

trait HasHashid
{
    public function findByHashid(string $hashid)
    {
        $ids = resolve(Hashid::class)->decode($hashid);

        if (count($ids) === 0) {
            throw new ModelNotFoundException();
        }

        return static::findOrFail($ids[0]);
    }
}
public function show(string $hashid)
{
    $foo = Foo::findByHashid($hashid);
}
2 likes
Snapey's avatar

@cooperino is exactly the same approach except you would have very long urls ( except you would have to also url encode the string)

The best solution depends on the business requirements

1 like
martinbean's avatar

@cooperino I wouldn’t. If you ever roll your APP_KEY then you’d break every URL in your site.

I’ve also already given you two solutions.

1 like
_midhun's avatar

You can use php base64_encode($id) to hide the id, and to retreive u can use base64_decode($id)

1 like
cooperino's avatar

Thank you guys, in my case I think the best solution would be to use UUIDs: I'll add a column to the database, automatically assign UUID to every model created, and change routes to use UUID instead of id:

Route::get('/route_name/{table:uuid}', [TheController::class, 'action'])
    ->name('route.name');

Please or to participate in this conversation.