A clean, modern Laravel package for integrating with Hikvision ISAPI Face Recognition Terminals and access control devices. Supports multi-device management, universal device providers (config, database, API), multi-tenant architectures, and real-time event webhooks.
- Real-Time Event Webhooks: Configure devices to push events to your API endpoints (v1.4.0+)
- Multi-Device Support: Manage unlimited Hikvision terminals simultaneously (v1.2.0+)
- Universal Device Providers: Load devices from config, database, API, or custom sources (v1.3.0+)
- Multi-Tenant Ready: Tenant-scoped device loading with runtime registration (v1.3.0+)
- Device Management: Get device info, status, and capabilities
- Person Management: Add, update, search, and delete persons
- Card Management: Handle access cards with full CRUD operations
- Face Recognition: Upload and manage face images with advanced search (v1.1.0+)
- Fingerprint Support: Register and manage fingerprints
- Access Control: Control doors remotely
- Event Handling: Search and subscribe to access events
- Event Notifications: HTTP webhooks for real-time event delivery (v1.4.0+)
- Clean Architecture: SOLID principles, dependency injection, contracts
- Type Safety: PHP 8.2+ features (enums, readonly properties)
- Performance: Built-in caching with configurable TTL (v1.3.0+)
- XML/JSON Support: Automatic format detection and conversion (v1.4.0+)
- Laravel 12: Full Laravel 12.x support with service provider and facade
- Requirements
- Installation
- Configuration
- Quick Start
- Event Webhooks & Notifications
- Multi-Device Support
- Services Overview
- DTOs (Data Transfer Objects)
- Enums
- Error Handling
- Advanced Usage
- Testing
- Troubleshooting
- Security
- Contributing
- Changelog
- PHP ^8.2
- Laravel ^12.0
- Guzzle HTTP ^7.8
- ext-curl
- ext-json
Install the package via Composer:
composer require shaykhnazar/hikvision-isapiPublish the configuration file:
php artisan vendor:publish --tag=hikvision-configAdd these environment variables to your .env file:
HIKVISION_IP=192.168.1.100
HIKVISION_PORT=80
HIKVISION_USERNAME=admin
HIKVISION_PASSWORD=your_password
HIKVISION_PROTOCOL=http
HIKVISION_TIMEOUT=30
HIKVISION_VERIFY_SSL=false
HIKVISION_FORMAT=jsonThe published config/hikvision.php supports multiple devices:
return [
'default' => env('HIKVISION_DEFAULT_DEVICE', 'primary'),
'devices' => [
'primary' => [
'ip' => env('HIKVISION_IP', '192.168.1.100'),
'port' => env('HIKVISION_PORT', 80),
'username' => env('HIKVISION_USERNAME', 'admin'),
'password' => env('HIKVISION_PASSWORD'),
'protocol' => env('HIKVISION_PROTOCOL', 'http'),
'timeout' => env('HIKVISION_TIMEOUT', 30),
'verify_ssl' => env('HIKVISION_VERIFY_SSL', false),
],
],
'format' => env('HIKVISION_FORMAT', 'json'),
'logging' => [
'enabled' => env('HIKVISION_LOGGING', true),
'channel' => env('HIKVISION_LOG_CHANNEL', 'stack'),
],
];use Shaykhnazar\HikvisionIsapi\Services\DeviceService;
$deviceService = app(DeviceService::class);
if ($deviceService->isOnline()) {
$info = $deviceService->getInfo();
echo "Device Model: " . $info['DeviceInfo']['model'];
}use Shaykhnazar\HikvisionIsapi\Services\PersonService;
use Shaykhnazar\HikvisionIsapi\DTOs\Person;
use Shaykhnazar\HikvisionIsapi\Enums\UserType;
$personService = app(PersonService::class);
$person = new Person(
employeeNo: 'EMP001',
name: 'John Doe',
userType: UserType::NORMAL,
validEnabled: true,
beginTime: now()->toISOString(),
endTime: now()->addYear()->toISOString(),
doorRight: '1',
rightPlan: [
['doorNo' => 1, 'planTemplateNo' => '1']
]
);
$response = $personService->add($person);use Shaykhnazar\HikvisionIsapi\Services\FaceService;
$faceService = app(FaceService::class);
// Read image file
$imageData = file_get_contents('path/to/photo.jpg');
$imageBase64 = base64_encode($imageData);
// Upload face (person must exist first)
$response = $faceService->uploadFace('EMP001', $imageBase64, 1);use Shaykhnazar\HikvisionIsapi\Services\FaceService;
$faceService = app(FaceService::class);
// Search face data with pagination
$results = $faceService->searchFace(
page: 0,
maxResults: 30,
faceLibType: 'blackFD',
fdid: 1,
fpid: '31903791410044'
);
// Upload face data record with image file
$imageContent = file_get_contents('face.jpg');
$response = $faceService->uploadFaceDataRecord(
fdid: 1,
fpid: '31903791410044',
imageContent: $imageContent,
faceLibType: 'blackFD'
);
// Delete face search data
$faceService->deleteFaceSearch(fdid: 1, faceLibType: 'blackFD');$personService = app(PersonService::class);
// Get total count
$total = $personService->count();
// Search with pagination (30 persons per page)
$persons = $personService->search(page: 0, maxResults: 30);
foreach ($persons as $person) {
echo "{$person->employeeNo}: {$person->name}\n";
}use Shaykhnazar\HikvisionIsapi\Services\CardService;
use Shaykhnazar\HikvisionIsapi\DTOs\Card;
$cardService = app(CardService::class);
$card = new Card(
employeeNo: 'EMP001',
cardNo: '1234567890',
cardType: 'normal'
);
$response = $cardService->add($card);use Shaykhnazar\HikvisionIsapi\Services\AccessControlService;
$accessControl = app(AccessControlService::class);
// Open door
$accessControl->openDoor(1);
// Get door status
$status = $accessControl->getDoorStatus(1);
// Close door
$accessControl->closeDoor(1);use Shaykhnazar\HikvisionIsapi\Services\EventService;
$eventService = app(EventService::class);
$events = $eventService->search([
'major' => 5, // Access control
'minor' => 75, // Face recognition
'startTime' => now()->subDay()->toISOString(),
'endTime' => now()->toISOString(),
], page: 0, maxResults: 50);Configure Hikvision devices to automatically push events (access granted, face recognized, etc.) to your application's webhook endpoint in real-time. This eliminates the need for polling and provides instant event notifications.
The EventNotificationService allows you to configure HTTP event notifications on Hikvision devices:
use Shaykhnazar\HikvisionIsapi\Services\EventNotificationService;
$eventNotificationService = app(EventNotificationService::class);The easiest way to set up a webhook is using the configureWebhook() method:
// Configure device to send all events to your webhook endpoint
$webhookUrl = 'https://your-api.com/api/webhooks/hikvision/events';
$response = $eventNotificationService->configureWebhook(
webhookUrl: $webhookUrl,
hostId: 1 // Host ID (1-8), default is 1
);
// Enable the webhook
$eventNotificationService->enableHttpHost(1);For more control over webhook configuration, use configureHttpHost():
$response = $eventNotificationService->configureHttpHost(
url: 'https://your-api.com/api/webhooks/hikvision/events',
id: 1, // Host ID (1-8)
protocol: 'HTTPS', // HTTP or HTTPS
port: 443, // Port number
httpAuthType: 'basic', // none, basic, or digest
username: 'webhook_user', // Optional: for authentication
password: 'webhook_pass', // Optional: for authentication
eventTypes: [ // Optional: specific event types (empty = all events)
'AccessControllerEvent',
'VideoMotion',
'linedetection'
]
);// Get webhook configuration
$config = $eventNotificationService->getHttpHost(1);
// Get all webhook configurations (supports up to 8 hosts)
$allConfigs = $eventNotificationService->getAllHttpHosts();
// Enable webhook
$eventNotificationService->enableHttpHost(1);
// Disable webhook
$eventNotificationService->disableHttpHost(1);
// Remove webhook configuration
$eventNotificationService->removeHttpHost(1);
// Get notification capabilities
$capabilities = $eventNotificationService->getCapabilities();Test if your webhook endpoint is reachable from the device:
// Send a test event to configured webhook
$response = $eventNotificationService->testHttpNotification(1);Create a controller to receive webhook events from Hikvision devices:
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
class HikvisionWebhookController extends Controller
{
/**
* Receive events from Hikvision devices
*/
public function handleEvent(Request $request)
{
// Hikvision sends events as XML
$xmlData = $request->getContent();
// Parse XML to array
$xml = simplexml_load_string($xmlData);
$event = json_decode(json_encode($xml), true);
// Log the event
Log::info('Hikvision Event Received', $event);
// Process event based on type
$eventType = $event['eventType'] ?? null;
match($eventType) {
'AccessControllerEvent' => $this->handleAccessControl($event),
'faceDetection' => $this->handleFaceDetection($event),
'VideoMotion' => $this->handleMotionDetection($event),
default => Log::warning('Unknown event type', ['type' => $eventType])
};
// Return 200 OK to acknowledge receipt
return response('OK', 200);
}
protected function handleAccessControl(array $event)
{
// Example: Handle access control event
$employeeNo = $event['employeeNoString'] ?? null;
$cardNo = $event['cardNo'] ?? null;
$doorNo = $event['doorNo'] ?? null;
Log::info('Access Control Event', [
'employee' => $employeeNo,
'card' => $cardNo,
'door' => $doorNo,
'time' => $event['dateTime'] ?? now()
]);
// Your business logic here
// - Record attendance
// - Send notifications
// - Update access logs
}
protected function handleFaceDetection(array $event)
{
// Handle face detection event
Log::info('Face Detection Event', $event);
}
protected function handleMotionDetection(array $event)
{
// Handle motion detection event
Log::info('Motion Detection Event', $event);
}
}Route setup:
// routes/api.php
Route::post('webhooks/hikvision/events', [HikvisionWebhookController::class, 'handleEvent'])
->name('hikvision.webhook');Configure webhooks for multiple devices:
use Shaykhnazar\HikvisionIsapi\Facades\Hikvision;
use Shaykhnazar\HikvisionIsapi\Services\EventNotificationService;
$devices = ['entrance', 'exit', 'canteen'];
$webhookUrl = 'https://your-api.com/api/webhooks/hikvision/events';
foreach ($devices as $deviceName) {
$client = Hikvision::device($deviceName);
$eventService = new EventNotificationService($client);
// Configure webhook with device name in URL for identification
$deviceWebhookUrl = $webhookUrl . '?device=' . $deviceName;
$eventService->configureWebhook($deviceWebhookUrl);
$eventService->enableHttpHost(1);
Log::info("Webhook configured for device: {$deviceName}");
}Protect your webhook endpoint:
// Add authentication to webhook configuration
$eventNotificationService->configureHttpHost(
url: 'https://your-api.com/api/webhooks/hikvision/events',
id: 1,
protocol: 'HTTPS',
port: 443,
httpAuthType: 'basic',
username: env('HIKVISION_WEBHOOK_USER'),
password: env('HIKVISION_WEBHOOK_PASSWORD')
);
// In your controller, validate the credentials
public function handleEvent(Request $request)
{
// Laravel automatically handles basic auth with middleware
// Or manually validate:
if ($request->getUser() !== env('HIKVISION_WEBHOOK_USER') ||
$request->getPassword() !== env('HIKVISION_WEBHOOK_PASSWORD')) {
return response('Unauthorized', 401);
}
// Process event...
}Access Control Event (Face Recognition):
<EventNotificationAlert>
<eventType>AccessControllerEvent</eventType>
<eventState>active</eventState>
<eventDescription>Access Control Event</eventDescription>
<dateTime>2025-10-30T14:30:00Z</dateTime>
<ActivePost>
<eventType>AccessControllerEvent</eventType>
<employeeNoString>EMP001</employeeNoString>
<name>John Doe</name>
<cardNo>1234567890</cardNo>
<doorNo>1</doorNo>
<swipeResult>success</swipeResult>
</ActivePost>
</EventNotificationAlert>Motion Detection Event:
<EventNotificationAlert>
<eventType>VideoMotion</eventType>
<eventState>active</eventState>
<dateTime>2025-10-30T14:35:00Z</dateTime>
</EventNotificationAlert>use Shaykhnazar\HikvisionIsapi\Facades\HikvisionIsapi;
// Get device info
$info = HikvisionIsapi::get('/ISAPI/System/deviceInfo');
// Custom endpoint
$response = HikvisionIsapi::post('/ISAPI/CustomEndpoint', [
'key' => 'value'
]);$deviceService = app(DeviceService::class);
$deviceService->getInfo(); // Get device information
$deviceService->getCapabilities(); // Get device capabilities
$deviceService->getStatus(); // Get device status
$deviceService->isOnline(); // Check if device is online$personService = app(PersonService::class);
$personService->add(Person $person); // Add person
$personService->update(Person $person); // Update person
$personService->apply(Person $person); // Apply person changes
$personService->search(int $page, int $maxResults); // Search persons
$personService->delete(array $employeeNos); // Delete persons
$personService->count(); // Count persons
$personService->getCapabilities(); // Get capabilities$cardService = app(CardService::class);
$cardService->add(Card $card); // Add card
$cardService->update(Card $card); // Update card
$cardService->search(...); // Search cards
$cardService->delete(array $employeeNos); // Delete cards
$cardService->deleteAll(); // Delete all cards
$cardService->count(?string $employeeNo); // Count cards
$cardService->batchAdd(array $cards); // Batch add cards$faceService = app(FaceService::class);
$faceService->uploadFace(string $employeeNo, string $imageBase64, int $fdid);
$faceService->deleteFace(int $fdid, int $fpid);
$faceService->searchFace(int $page, int $maxResults, string $faceLibType, ?int $fdid, ?string $fpid);
$faceService->deleteFaceSearch(int $fdid, string $faceLibType);
$faceService->uploadFaceDataRecord(int $fdid, string $fpid, string $imageContent, string $faceLibType);
$faceService->getLibraries();
$faceService->createLibrary(array $data);
$faceService->getCapabilities();$fingerprintService = app(FingerprintService::class);
$fingerprintService->add(string $employeeNo, int $fingerprintId, string $data);
$fingerprintService->search(...);
$fingerprintService->capture(int $timeout);
$fingerprintService->delete(array $employeeNos);
$fingerprintService->getCapabilities();$accessControl = app(AccessControlService::class);
$accessControl->openDoor(int $doorNo);
$accessControl->closeDoor(int $doorNo);
$accessControl->getDoorStatus(int $doorNo);$eventService = app(EventService::class);
$eventService->search(array $conditions, int $page, int $maxResults);
$eventService->count(array $conditions);
$eventService->subscribe(array $eventTypes, int $heartbeat);$eventNotificationService = app(EventNotificationService::class);
// Simple webhook setup
$eventNotificationService->configureWebhook(string $webhookUrl, int $hostId);
// Advanced configuration
$eventNotificationService->configureHttpHost(string $url, int $id, string $protocol, int $port, string $httpAuthType, ?string $username, ?string $password, array $eventTypes);
// Manage webhooks
$eventNotificationService->getHttpHost(int $id);
$eventNotificationService->getAllHttpHosts();
$eventNotificationService->enableHttpHost(int $id);
$eventNotificationService->disableHttpHost(int $id);
$eventNotificationService->removeHttpHost(int $id);
// Testing
$eventNotificationService->testHttpNotification(int $id);
// Capabilities
$eventNotificationService->getCapabilities();use Shaykhnazar\HikvisionIsapi\DTOs\Person;
use Shaykhnazar\HikvisionIsapi\Enums\UserType;
$person = new Person(
employeeNo: 'EMP001',
name: 'John Doe',
userType: UserType::NORMAL,
validEnabled: true,
beginTime: '2025-01-01T00:00:00',
endTime: '2025-12-31T23:59:59',
doorRight: '1',
rightPlan: [
['doorNo' => 1, 'planTemplateNo' => '1']
],
email: '[email protected]',
phoneNumber: '+1234567890',
organizationId: 1,
belongGroup: null
);
// Convert to array for API
$array = $person->toArray();
// Create from API response
$person = Person::fromArray($response);use Shaykhnazar\HikvisionIsapi\DTOs\Card;
$card = new Card(
employeeNo: 'EMP001',
cardNo: '1234567890',
cardType: 'normal',
enabled: true
);use Shaykhnazar\HikvisionIsapi\DTOs\Face;
$face = new Face(
employeeNo: 'EMP001',
faceData: base64_encode($imageData),
faceLibId: 1,
faceLibType: 'blackFD'
);use Shaykhnazar\HikvisionIsapi\Enums\UserType;
UserType::NORMAL // Normal user
UserType::VISITOR // Visitor
UserType::BLOCKLIST // Blocklist user
// Get label
$label = UserType::NORMAL->label(); // "Normal User"use Shaykhnazar\HikvisionIsapi\Enums\EventType;
EventType::ACCESS_GRANTED // 0x01
EventType::ACCESS_DENIED // 0x02
EventType::FACE_RECOGNIZED // 0x4b
EventType::CARD_SWIPED // 0x05
// Get description
$desc = EventType::ACCESS_GRANTED->description(); // "Access Granted"All exceptions extend HikvisionException:
use Shaykhnazar\HikvisionIsapi\Exceptions\HikvisionException;
use Shaykhnazar\HikvisionIsapi\Exceptions\AuthenticationException;
use Shaykhnazar\HikvisionIsapi\Exceptions\DeviceNotFoundException;
try {
$response = $personService->add($person);
} catch (AuthenticationException $e) {
// Handle authentication errors
Log::error('Authentication failed', ['error' => $e->getMessage()]);
} catch (DeviceNotFoundException $e) {
// Handle device not found
Log::error('Device not found', ['error' => $e->getMessage()]);
} catch (HikvisionException $e) {
// Handle other Hikvision errors
Log::error('Hikvision error', ['error' => $e->getMessage()]);
}The package supports managing multiple Hikvision devices simultaneously. This is useful when you have multiple terminals at different locations (entrance, exit, canteen, etc.).
Device Sources Supported:
- ✅ Config files (default)
- ✅ Database tables
- ✅ Custom callbacks (API, Redis, cache, etc.)
- ✅ Runtime registration
Configure multiple devices in config/hikvision.php:
return [
'default' => env('HIKVISION_DEFAULT_DEVICE', 'primary'),
'devices' => [
'primary' => [
'ip' => env('HIKVISION_IP', '192.168.1.100'),
'port' => env('HIKVISION_PORT', 80),
'username' => env('HIKVISION_USERNAME', 'admin'),
'password' => env('HIKVISION_PASSWORD'),
'protocol' => env('HIKVISION_PROTOCOL', 'http'),
'timeout' => env('HIKVISION_TIMEOUT', 30),
'verify_ssl' => env('HIKVISION_VERIFY_SSL', false),
],
'entrance' => [
'ip' => env('HIKVISION_ENTRANCE_IP', '192.168.1.101'),
'port' => env('HIKVISION_ENTRANCE_PORT', 80),
'username' => env('HIKVISION_ENTRANCE_USERNAME', 'admin'),
'password' => env('HIKVISION_ENTRANCE_PASSWORD'),
'protocol' => env('HIKVISION_ENTRANCE_PROTOCOL', 'http'),
'timeout' => env('HIKVISION_ENTRANCE_TIMEOUT', 30),
'verify_ssl' => env('HIKVISION_ENTRANCE_VERIFY_SSL', false),
],
'exit' => [
'ip' => env('HIKVISION_EXIT_IP', '192.168.1.102'),
'port' => env('HIKVISION_EXIT_PORT', 80),
'username' => env('HIKVISION_EXIT_USERNAME', 'admin'),
'password' => env('HIKVISION_EXIT_PASSWORD'),
'protocol' => env('HIKVISION_EXIT_PROTOCOL', 'http'),
'timeout' => env('HIKVISION_EXIT_TIMEOUT', 30),
'verify_ssl' => env('HIKVISION_EXIT_VERIFY_SSL', false),
],
'canteen' => [
'ip' => env('HIKVISION_CANTEEN_IP', '192.168.1.103'),
'port' => env('HIKVISION_CANTEEN_PORT', 80),
'username' => env('HIKVISION_CANTEEN_USERNAME', 'admin'),
'password' => env('HIKVISION_CANTEEN_PASSWORD'),
'protocol' => env('HIKVISION_CANTEEN_PROTOCOL', 'http'),
'timeout' => env('HIKVISION_CANTEEN_TIMEOUT', 30),
'verify_ssl' => env('HIKVISION_CANTEEN_VERIFY_SSL', false),
],
],
];Add device-specific environment variables to .env:
# Primary Device (Default)
HIKVISION_DEFAULT_DEVICE=primary
HIKVISION_IP=192.168.1.100
HIKVISION_PORT=80
HIKVISION_USERNAME=admin
HIKVISION_PASSWORD=your_password
# Entrance Device
HIKVISION_ENTRANCE_IP=192.168.1.101
HIKVISION_ENTRANCE_PORT=80
HIKVISION_ENTRANCE_USERNAME=admin
HIKVISION_ENTRANCE_PASSWORD=entrance_password
# Exit Device
HIKVISION_EXIT_IP=192.168.1.102
HIKVISION_EXIT_PORT=80
HIKVISION_EXIT_USERNAME=admin
HIKVISION_EXIT_PASSWORD=exit_password
# Canteen Device
HIKVISION_CANTEEN_IP=192.168.1.103
HIKVISION_CANTEEN_PORT=80
HIKVISION_CANTEEN_USERNAME=admin
HIKVISION_CANTEEN_PASSWORD=canteen_passworduse Shaykhnazar\HikvisionIsapi\Facades\Hikvision;
// Use default device
$defaultClient = Hikvision::default();
$info = $defaultClient->get('/ISAPI/System/deviceInfo');
// Use specific devices
$entranceClient = Hikvision::device('entrance');
$exitClient = Hikvision::device('exit');
$canteenClient = Hikvision::device('canteen');
// Get device information from each terminal
$entranceInfo = $entranceClient->get('/ISAPI/System/deviceInfo');
$exitInfo = $exitClient->get('/ISAPI/System/deviceInfo');
$canteenInfo = $canteenClient->get('/ISAPI/System/deviceInfo');
// List all available devices
$devices = Hikvision::availableDevices();
// Returns: ['primary', 'entrance', 'exit', 'canteen']
// Check if device exists
if (Hikvision::hasDevice('entrance')) {
// Work with entrance device
}use Shaykhnazar\HikvisionIsapi\Facades\Hikvision;
use Shaykhnazar\HikvisionIsapi\Services\PersonService;
use Shaykhnazar\HikvisionIsapi\DTOs\Person;
use Shaykhnazar\HikvisionIsapi\Enums\UserType;
// Create person DTO
$person = new Person(
employeeNo: 'EMP001',
name: 'John Doe',
userType: UserType::NORMAL,
validEnabled: true,
beginTime: now()->toISOString(),
endTime: now()->addYear()->toISOString()
);
// Get device-specific clients
$entranceClient = Hikvision::device('entrance');
$exitClient = Hikvision::device('exit');
$canteenClient = Hikvision::device('canteen');
// Create person service for each device
$entrancePersonService = new PersonService($entranceClient);
$exitPersonService = new PersonService($exitClient);
$canteenPersonService = new PersonService($canteenClient);
// Add person to all devices
$entrancePersonService->add($person);
$exitPersonService->add($person);
$canteenPersonService->add($person);use Shaykhnazar\HikvisionIsapi\Facades\Hikvision;
use Shaykhnazar\HikvisionIsapi\Services\PersonService;
use Shaykhnazar\HikvisionIsapi\Services\FaceService;
use Shaykhnazar\HikvisionIsapi\DTOs\Person;
class EmployeeSyncService
{
public function syncToAllDevices(Person $person, string $faceImagePath): array
{
$results = [];
$devices = Hikvision::availableDevices();
foreach ($devices as $deviceName) {
try {
// Get device client
$client = Hikvision::device($deviceName);
// Create services for this device
$personService = new PersonService($client);
$faceService = new FaceService($client);
// Add person
$personService->add($person);
// Upload face
$imageData = file_get_contents($faceImagePath);
$imageBase64 = base64_encode($imageData);
$faceService->uploadFace($person->employeeNo, $imageBase64, 1);
$results[$deviceName] = [
'success' => true,
'message' => 'Synced successfully',
];
} catch (\Exception $e) {
$results[$deviceName] = [
'success' => false,
'error' => $e->getMessage(),
];
}
}
return $results;
}
}The DeviceManager provides the following methods:
use Shaykhnazar\HikvisionIsapi\Facades\Hikvision;
// Get client for specific device (or default if null)
$client = Hikvision::device('entrance');
$client = Hikvision::device(); // Uses default device
// Get default device client
$defaultClient = Hikvision::default();
// Get all available device names
$devices = Hikvision::availableDevices();
// Returns: ['primary', 'entrance', 'exit', 'canteen']
// Check if device exists in configuration
$exists = Hikvision::hasDevice('entrance'); // true or false
// Reload devices from provider (useful for database-driven configs)
Hikvision::reload(); // Clears cache and reloads from source
// Clear cached clients (useful for testing)
Hikvision::clearClients();
// Register device at runtime (v1.3.0+)
Hikvision::registerDevice('temp_device', [
'ip' => '192.168.1.150',
'port' => 80,
'username' => 'admin',
'password' => 'password',
'protocol' => 'http',
'timeout' => 30,
'verify_ssl' => false,
]);
// Switch device provider at runtime (v1.3.0+)
use Shaykhnazar\HikvisionIsapi\Client\Providers\DatabaseDeviceProvider;
$dbProvider = new DatabaseDeviceProvider(table: 'terminals');
Hikvision::setProvider($dbProvider);The package maintains 100% backward compatibility. If you're using the default device setup, your existing code will work without any changes:
use Shaykhnazar\HikvisionIsapi\Services\PersonService;
// This still works - uses default device
$personService = app(PersonService::class);
$person = $personService->add($newPerson);For applications that store terminal configurations in database (multi-tenant, dynamic terminals, etc.), use the DatabaseDeviceProvider:
// Migration: create_terminals_table.php
Schema::create('terminals', function (Blueprint $table) {
$table->id();
$table->string('name')->unique(); // Device identifier
$table->string('ip');
$table->integer('port')->default(80);
$table->string('username');
$table->string('password');
$table->string('protocol')->default('http');
$table->integer('timeout')->default(30);
$table->boolean('verify_ssl')->default(false);
$table->boolean('is_active')->default(true);
$table->timestamps();
});In your AppServiceProvider or custom service provider:
use Shaykhnazar\HikvisionIsapi\Client\Providers\DatabaseDeviceProvider;
public function register(): void
{
// Bind custom device provider
$this->app->singleton('hikvision.device.provider', function ($app) {
return new DatabaseDeviceProvider(
table: 'terminals',
nameColumn: 'name',
configColumns: [
'ip' => 'ip',
'port' => 'port',
'username' => 'username',
'password' => 'password',
'protocol' => 'protocol',
'timeout' => 'timeout',
'verify_ssl' => 'verify_ssl',
],
defaultDevice: 'primary',
whereConditions: ['is_active' => true], // Only load active terminals
cache: true, // Enable caching
cacheTtl: 3600 // Cache for 1 hour
);
});
}use Shaykhnazar\HikvisionIsapi\Facades\Hikvision;
use Shaykhnazar\HikvisionIsapi\Services\PersonService;
// Get all available terminals from database
$terminals = Hikvision::availableDevices();
// Returns: ['entrance', 'exit', 'canteen', 'office'] - loaded from DB
// Use specific terminal
$entranceClient = Hikvision::device('entrance');
$personService = new PersonService($entranceClient);
// Add person to entrance terminal
$personService->add($person);use Shaykhnazar\HikvisionIsapi\Facades\Hikvision;
// After adding/updating terminals in database
Hikvision::reload(); // Clears cache and reloads from DBFor more complex scenarios with Eloquent relationships:
use Shaykhnazar\HikvisionIsapi\Client\Providers\CallbackDeviceProvider;
use App\Models\Terminal;
// In your service provider
$this->app->singleton('hikvision.device.provider', function ($app) {
return CallbackDeviceProvider::fromEloquent(
query: Terminal::where('status', 'active')
->where('company_id', auth()->user()->company_id),
nameColumn: 'slug',
configMap: [
'ip' => 'ip_address',
'port' => 'port',
'username' => 'username',
'password' => 'password',
'protocol' => 'protocol',
'timeout' => 'connection_timeout',
'verify_ssl' => 'ssl_enabled',
]
);
});For multi-tenant applications where each tenant has their own terminals:
use Shaykhnazar\HikvisionIsapi\Client\Providers\CallbackDeviceProvider;
use App\Models\Terminal;
// In AppServiceProvider
$this->app->singleton('hikvision.device.provider', function ($app) {
return new CallbackDeviceProvider(
deviceNamesCallback: function () {
// Only load terminals for current tenant
$tenantId = auth()->user()->tenant_id;
return Terminal::where('tenant_id', $tenantId)
->where('is_active', true)
->pluck('name')
->toArray();
},
deviceConfigCallback: function (string $deviceName) {
$tenantId = auth()->user()->tenant_id;
$terminal = Terminal::where('tenant_id', $tenantId)
->where('name', $deviceName)
->first();
if (!$terminal) {
return null;
}
return [
'ip' => $terminal->ip,
'port' => $terminal->port,
'username' => $terminal->username,
'password' => decrypt($terminal->password), // Decrypt if encrypted
'protocol' => $terminal->protocol,
'timeout' => $terminal->timeout,
'verify_ssl' => $terminal->verify_ssl,
];
},
defaultDevice: 'primary'
);
});Register devices dynamically at runtime:
use Shaykhnazar\HikvisionIsapi\Facades\Hikvision;
// Register a temporary device
Hikvision::registerDevice('temp_device', [
'ip' => '192.168.1.150',
'port' => 80,
'username' => 'admin',
'password' => 'password',
'protocol' => 'http',
'timeout' => 30,
'verify_ssl' => false,
]);
// Use the temporary device
$client = Hikvision::device('temp_device');Change device provider dynamically:
use Shaykhnazar\HikvisionIsapi\Facades\Hikvision;
use Shaykhnazar\HikvisionIsapi\Client\Providers\DatabaseDeviceProvider;
use Shaykhnazar\HikvisionIsapi\Client\Providers\ConfigDeviceProvider;
// Switch to database provider
$dbProvider = new DatabaseDeviceProvider(table: 'terminals');
Hikvision::setProvider($dbProvider);
// Now all devices are loaded from database
$devices = Hikvision::availableDevices();
// Switch back to config provider
$configProvider = new ConfigDeviceProvider(config('hikvision'));
Hikvision::setProvider($configProvider);$cardService = app(CardService::class);
$cards = [
new Card('EMP001', '1234567890'),
new Card('EMP002', '0987654321'),
new Card('EMP003', '1122334455'),
];
$results = $cardService->batchAdd($cards);
/*
Returns:
[
'total' => 3,
'success' => 3,
'failed' => 0,
'errors' => []
]
*/$personService = app(PersonService::class);
$total = $personService->count();
$perPage = 30;
$pages = ceil($total / $perPage);
for ($page = 0; $page < $pages; $page++) {
$persons = $personService->search($page, $perPage);
// Process persons...
}use Shaykhnazar\HikvisionIsapi\Facades\HikvisionIsapi;
// GET request
$response = HikvisionIsapi::get('/ISAPI/CustomEndpoint', [
'param1' => 'value1',
]);
// POST request
$response = HikvisionIsapi::post('/ISAPI/CustomEndpoint', [
'key' => 'value',
]);
// PUT request
$response = HikvisionIsapi::put('/ISAPI/CustomEndpoint', [
'key' => 'value',
]);
// DELETE request
$response = HikvisionIsapi::delete('/ISAPI/CustomEndpoint');# Run tests
./vendor/bin/phpunit
# Run specific test file
./vendor/bin/phpunit tests/Feature/PersonServiceTest.php
# Run with coverage
./vendor/bin/phpunit --coverage-html coverageCheck your credentials in .env:
# Test with curl
curl -v --digest -u admin:password http://192.168.1.100/ISAPI/System/deviceInfo- Verify device IP and network connectivity
- Increase timeout in config:
HIKVISION_TIMEOUT=60 - Check firewall rules
- Ensure image is JPEG format
- Check image size (max 200KB)
- Verify person exists on device first
- Image quality should be good with clear face
- Check IP address in
.env - Verify device is powered on
- Ensure device is on same network
- Store credentials in
.envfile (never commit) - Use HTTPS in production
- Enable SSL verification with valid certificates
- Implement rate limiting on your API endpoints
- Validate all user input
Contributions are welcome! Please follow these guidelines:
- Fork the repository
- Create a feature branch
- Write tests for new features
- Follow PSR-12 coding standards
- Submit a pull request
- EventNotificationService: New service for configuring HTTP event notifications (webhooks)
- Real-Time Webhooks: Configure devices to push events to your API endpoints automatically
- XML Support: Added
putXml()method to HikvisionClient for XML-only endpoints - HTTP Client Enhancements:
- Added
arrayToXml()method for converting arrays to XML format - Added
xmlToArray()method for parsing XML responses - Automatic XML/JSON format detection based on Content-Type
- Added
- Event Notification Methods:
configureWebhook()- Simple one-line webhook setupconfigureHttpHost()- Advanced webhook configuration with authenticationenableHttpHost()/disableHttpHost()- Enable/disable webhookstestHttpNotification()- Test webhook connectivitygetCapabilities()- Get notification capabilities
- Dependencies: Added
ext-simplexmlandext-libxmlfor XML processing - Multi-Device Webhooks: Configure webhooks for multiple devices simultaneously
- Webhook Security: Support for HTTP Basic and Digest authentication
- 100% backward compatible with v1.3.0
- Universal Device Providers: Framework for loading devices from any source
- DatabaseDeviceProvider: Load terminals from database tables with built-in caching
- CallbackDeviceProvider: Maximum flexibility with custom callbacks (API, Redis, etc.)
- Multi-Tenant Support: Tenant-scoped device loading and isolation
- Runtime Device Registration: Register devices dynamically at runtime
- Provider Switching: Change device providers on-the-fly
- Hot Reload: Update database-driven configurations without restart
- Configurable Caching: Built-in cache support with TTL control
- 100% backward compatible with v1.2.0
- Multi-Device Support: Manage unlimited Hikvision devices simultaneously
- DeviceManager: Central manager with lazy initialization and caching
- New Hikvision Facade: Multi-device access with
Hikvision::device() - Device Discovery: List and validate configured devices
- Device-Specific Clients: Automatic client caching per device
- 100% backward compatible with single-device setups
- Face Search Functionality: Search face data with pagination support
- Face Data Record Upload: Multipart/form-data support for face images
- Fixed PersonService Delete Endpoint: Updated to match ISAPI specification
- Configuration Validation: Required username/password validation
- Extended HTTP Client: Added multipart form-data upload support
- Enhanced error handling and validation
- Initial release
- Full ISAPI support
- Person, Card, Face, Fingerprint management
- Access control and event handling
- Laravel 12.x support
- PHP 8.2+ with modern features
This package is open-sourced software licensed under the MIT license.
- Author: Shaykhnazar
- Email: [email protected]
For issues, questions, or contributions:
- GitHub Issues: https://github.com/shaykhnazar/hikvision-isapi/issues
- Email: [email protected]
This package is designed for legitimate access control systems and defensive security purposes only. Do not use for malicious purposes.
Made with ❤️ for the Laravel community