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

Shivamyadav's avatar

Prevent Users From Opening the Same Test in Multiple active Tabs?

I am building an online test/exam system in Laravel where users access URLs like:

http://manual5.uishare.local/test/{id}/attempt

I want to prevent a user from:

Opening the same test in multiple tabs

If a test is already active, I want to show a message like: "This test is already active in another session/tab."

My concerns:

  1. Reliability
  2. Preventing race conditions
  3. Handling browser crashes/tab closes
  4. Supporting scalability
  5. Avoiding false locks
  6. Security against bypassing frontend checks
0 likes
3 replies
Glukinho's avatar

Interesting task. I have some ideas but on deep thought they are far from true reliability. I'd listen for other opinions as well.

General idea is: you can't reliably control what is going on in user's browser. An advanced user can break through your protection.

You can't prevent a user from taking screenshots of a tab, closing it and opening new tab with screenshots opened in image viewer, after all.

Snapey's avatar

Maybe something with reverb/pusher and a presence channel?

Make sure each user gets a unique ID for their instance of a test, issue that same ID if the test already exists (eg, they simply refresh the page). Broadcast that Id on the presence channel, and refuse to start a new instance of the test if the presence channel already contains the test ID.

imrandevbd's avatar

Snapey's presence channel idea is solid, but if you want to avoid the overhead of Reverb/websockets, you can handle this reliably using a Redis cache lock combined with a JS heartbeat. I've used this exact pattern in production for high-stakes exam platforms.

Backend Lock: In that controller, store the lock in Redis: Cache::put("test_lock_{$test->id}user{$user->id}", $tab_id, 10);. The 10-second TTL is the magic number here.

Enforcement: On the actual test attempt route (and on subsequent test submissions), check this cache key. If the key exists AND the value doesn't match the current request's tab_id, throw your "already active" error.

Please or to participate in this conversation.