PHP code example of olorunda / laravel-aiface-websocket

1. Go to this page and download the library: Download olorunda/laravel-aiface-websocket library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

olorunda / laravel-aiface-websocket example snippets


use AiFace\WebSocket\Facades\AiFace;
use AiFace\WebSocket\Core\Protocol;

// Check if device is connected online
if (AiFace::isOnline('LF00000001')) {
    echo "Device is online!";
}

// 1. Remote Unlock Door
$response = AiFace::device('LF00000001')->openDoor(doorNum: 1);

// 2. Synchronize Device Clock with Server Time
$response = AiFace::device('LF00000001')->syncTime();

// 3. Reboot Device Hardware
$response = AiFace::device('LF00000001')->reboot();

// 4. Enroll User with Face Photo (base64 JPG)
$response = AiFace::device('LF00000001')->setUserFacePhoto(
    enrollId: 101,
    name: 'Sarah Connor',
    base64Jpg: base64_encode(file_get_contents('/path/to/face.jpg')),
    admin: 0
);

// 5. Enroll User with RFID Card Number
$response = AiFace::device('LF00000001')->setUserCard(
    enrollId: 102,
    name: 'John Doe',
    cardNumber: '9876543210'
);

// 6. Enroll User with PIN / Password
$response = AiFace::device('LF00000001')->setUserPassword(
    enrollId: 103,
    name: 'Admin User',
    pwd: 123456,
    admin: 1 // Device administrator
);

// 7. Pull Unread Attendance Records
$logs = AiFace::device('LF00000001')->getNewLog();

// 8. Trigger Device-Side Enrollment Wizard on hardware screen
AiFace::device('LF00000001')->addUser(
    enrollId: 105,
    backupNum: Protocol::BACKUP_FP_0 // Fingerprint slot 0
);

namespace App\Http\Controllers;

use AiFace\WebSocket\Facades\AiFace;
use AiFace\WebSocket\Core\Protocol;
use App\Models\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

class BiometricEmployeeController extends Controller
{
    protected string $deviceSn = 'LF00000001';

    /**
     * Step 1: Enroll an employee onto the biometric terminal
     */
    public function enroll(Request $request, int $userId): JsonResponse
    {
        $employee = User::findOrFail($userId);

        // 1. Verify the biometric hardware terminal is connected online
        if (!AiFace::isOnline($this->deviceSn)) {
            return response()->json([
                'success' => false,
                'message' => "Terminal [{$this->deviceSn}] is currently offline.",
            ], 503);
        }

        // 2. Check remaining device memory/capacity before adding
        $cap = AiFace::device($this->deviceSn)->getDevCap();
        if (($cap['useduser'] ?? 0) >= ($cap['usersize'] ?? 10000)) {
            return response()->json([
                'success' => false,
                'message' => 'Terminal user capacity is full.',
            ], 422);
        }

        // 3. Enroll employee with card and/or PIN password
        // (backupnum: 10 = password, 11 = card, 50 = face photo)
        $enrollResult = AiFace::device($this->deviceSn)->setUserInfo(
            enrollId: $employee->id,
            name: $employee->name,
            backupNum: Protocol::BACKUP_PASSWORD,
            record: $request->input('pin', '123456'), // User PIN
            admin: $employee->is_admin ? 1 : 0,       // 1 = Terminal Administrator
            enable: 1,                                // 1 = Active, 0 = Suspended
            extra: [
                'card' => $request->input('card_number', '99887766'),
                'aliasid' => 'EMP-' . $employee->id,
            ]
        );

        // 4. (Optional) Enroll face photo if uploaded
        if ($request->hasFile('face_photo')) {
            $base64Image = base64_encode(file_get_contents($request->file('face_photo')->getRealPath()));
            AiFace::device($this->deviceSn)->setUserFacePhoto(
                enrollId: $employee->id,
                name: $employee->name,
                base64Jpg: $base64Image
            );
        }

        // 5. (Optional) Prompt the device screen to open enrollment wizard for fingerprint
        if ($request->boolean('scan_fingerprint')) {
            AiFace::device($this->deviceSn)->addUser(
                enrollId: $employee->id,
                backupNum: Protocol::BACKUP_FP_0 // Fingerprint slot 0
            );
        }

        return response()->json([
            'success' => true,
            'message' => "Employee #{$employee->id} ({$employee->name}) enrolled successfully.",
            'terminal_response' => $enrollResult,
        ]);
    }

    /**
     * Step 2: Offboard / Delete an employee from the biometric terminal
     */
    public function offboard(int $userId): JsonResponse
    {
        $employee = User::findOrFail($userId);

        if (!AiFace::isOnline($this->deviceSn)) {
            return response()->json([
                'success' => false,
                'message' => "Terminal [{$this->deviceSn}] is offline. Reconnect terminal to delete.",
            ], 503);
        }

        // Delete user and all associated biometric credentials (face, fingerprints, card, PIN)
        $deleteResult = AiFace::device($this->deviceSn)->deleteUser(
            enrollId: $employee->id
        );

        return response()->json([
            'success' => true,
            'message' => "Employee #{$employee->id} deleted from terminal.",
            'terminal_response' => $deleteResult,
        ]);
    }

    /**
     * Step 3: Revoke only a specific credential (e.g. lost RFID card) without deleting user
     */
    public function revokeCard(int $userId): JsonResponse
    {
        // Deleting with backupNum = 11 removes only the RFID card credential
        $result = AiFace::device($this->deviceSn)->deleteUser(
            enrollId: $userId,
            backupNum: Protocol::BACKUP_CARD
        );

        return response()->json([
            'success' => true,
            'message' => "RFID card revoked for user #{$userId}.",
            'terminal_response' => $result,
        ]);
    }

    /**
     * Step 4: Delayed / Scheduled Deletion (Auto-Expire Access)
     * Useful for hotel guests, temporary visitors, contract workers, or scheduled offboarding.
     */
    public function scheduleOffboarding(int $userId): JsonResponse
    {
        // Option A: Pass delay in seconds (e.g., 3600 = 1 hour)
        $result = AiFace::device($this->deviceSn)->deleteUser(
            enrollId: $userId,
            delay: 3600
        );

        // Option B: Pass a Carbon / DateTime instance
        // $result = AiFace::device($this->deviceSn)->delayedDeleteUser(
        //     enrollId: $userId,
        //     delay: now()->addHours(8)
        // );

        return response()->json([
            'success' => true,
            'message' => "User #{$userId} scheduled for automatic removal when time elapses.",
            'task'    => $result,
        ]);
    }

    /**
     * Step 5: Cancel a scheduled deletion before it elapses
     */
    public function cancelScheduledOffboarding(int $userId): JsonResponse
    {
        $result = AiFace::device($this->deviceSn)->cancelDelayedDelete($userId);

        return response()->json([
            'success' => true,
            'result'  => $result,
        ]);
    }
}

namespace App\Listeners;

use AiFace\WebSocket\Events\UserClockedIn;
use AiFace\WebSocket\Events\UserClockedOut;
use App\Models\Timesheet;
use Illuminate\Support\Facades\Log;

class HandleBiometricAttendance
{
    /**
     * Handle Clock-In (Check-In) Events
     */
    public function handleClockIn(UserClockedIn $event): void
    {
        Log::info("Employee #{$event->enrollId} ({$event->name}) clocked IN on terminal {$event->sn} at {$event->time} via {$event->modeDesc}");

        // Record attendance in your database
        Timesheet::create([
            'user_id'         => $event->enrollId,
            'employee_name'   => $event->name,
            'device_sn'       => $event->sn,
            'action'          => 'clock_in',
            'punch_time'      => $event->time,
            'verification'    => $event->modeDesc, // e.g. "Face Recognition", "Fingerprint", "Card", "Password"
            'snapshot_base64' => $event->image,    // Captured snapshot if terminal camera is configured
        ]);

        // Trigger notifications, Slack alerts, or dispatch payroll sync jobs
    }

    /**
     * Handle Clock-Out (Check-Out) Events
     */
    public function handleClockOut(UserClockedOut $event): void
    {
        Log::info("Employee #{$event->enrollId} ({$event->name}) clocked OUT on terminal {$event->sn} at {$event->time}");

        Timesheet::create([
            'user_id'         => $event->enrollId,
            'employee_name'   => $event->name,
            'device_sn'       => $event->sn,
            'action'          => 'clock_out',
            'punch_time'      => $event->time,
            'verification'    => $event->modeDesc,
        ]);
    }
}

namespace App\Providers;

use AiFace\WebSocket\Events\UserClockedIn;
use AiFace\WebSocket\Events\UserClockedOut;
use App\Listeners\HandleBiometricAttendance;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        Event::listen(UserClockedIn::class, [HandleBiometricAttendance::class, 'handleClockIn']);
        Event::listen(UserClockedOut::class, [HandleBiometricAttendance::class, 'handleClockOut']);
    }
}

use AiFace\WebSocket\Events\UserClockedIn;
use AiFace\WebSocket\Events\UserClockedOut;
use AiFace\WebSocket\Events\UserDeleteScheduled;
use AiFace\WebSocket\Events\UserDeleted;
use AiFace\WebSocket\Events\AttendanceLogReceived;
use AiFace\WebSocket\Events\DeviceRegistered;
use Illuminate\Support\Facades\Event;

// Triggered whenever a user clocks in (inout = 0)
Event::listen(UserClockedIn::class, function (UserClockedIn $event) {
    logger()->info("User #{$event->enrollId} ({$event->name}) clocked IN on {$event->sn} at {$event->time} via {$event->modeDesc}");
    // Example: send SMS, notify Slack, update attendance timesheet
});

// Triggered whenever a user clocks out (inout = 1)
Event::listen(UserClockedOut::class, function (UserClockedOut $event) {
    logger()->info("User #{$event->enrollId} ({$event->name}) clocked OUT on {$event->sn} at {$event->time}");
});

// Triggered when a delayed deletion task is scheduled
Event::listen(UserDeleteScheduled::class, function (UserDeleteScheduled $event) {
    logger()->info("User #{$event->enrollId} scheduled for deletion on {$event->sn} in {$event->delaySeconds}s (at " . date('Y-m-d H:i:s', $event->executeAt) . ")");
});

// Triggered when deletion is transmitted and effected on device
Event::listen(UserDeleted::class, function (UserDeleted $event) {
    logger()->info("User #{$event->enrollId} deleted on {$event->sn}");
});

// Triggered when a device registers or completes handshake
Event::listen(DeviceRegistered::class, function (DeviceRegistered $event) {
    logger()->info("AiFace device {$event->sn} registered from IP: {$event->ip}");
});

'webhooks' => [
    'enabled' => true,
    'url' => 'https://your-domain.com/webhooks/aiface',
    'secret' => 'your-secret-key',
    'events' => [
        'attendance.clockin',       // Individual user clock-in punch
        'attendance.clockout',      // Individual user clock-out punch
        'attendance.logged',        // Batch attendance log payload
        'device.registered',        // Device handshake completed
        'device.connected',         // New socket connected
        'device.disconnected',      // Device disconnected
        'user.pushed',              // On-device user enrollment report
        'user.delete_scheduled',    // User deletion task scheduled
        'user.deleted',             // User deletion effected on device
        'pin.received',             // Door access PIN entered
        'qrcode.scanned',           // Visitor/employee QR code scan
        'gps.received',             // Device GPS location
        'intercom.call',            // Video intercom doorbell ring
    ],
],
bash
php artisan vendor:publish --tag=aiface-config
php artisan migrate
bash
php artisan aiface:serve
text
===============================================================
  AiFace Biometric WebSocket Server Daemon  
===============================================================
  ● Protocol:       ws
  ● Listening:      0.0.0.0:7788/pub/chat
  ● Device URL:     ws://<YOUR_SERVER_IP>:7788/pub/chat
  ● Storage:        Enabled
  ● Webhooks:       Disabled
===============================================================
bash
php artisan aiface:serve --port=7788 --path=/pub/chat --wss
bash
# Simulates physical hardware with an embedded SQLite database (tynyteko_LF00000001.sqlite):
php examples/mock_device.php 127.0.0.1 7788 /pub/chat LF00000001