Add ZK library classes for device interaction and user management
- Implemented Os class for retrieving OS information. - Added Pin class for getting PIN width. - Created Platform class for fetching platform details and version. - Developed SerialNumber class to retrieve device serial number. - Introduced Ssr class for SSR information retrieval. - Implemented Time class for setting and getting device time. - Added User class for user management including setting, getting, clearing, and removing users. - Created Util class with various utility functions for command handling and data processing. - Implemented Version class for fetching device version. - Added WorkCode class for retrieving work code information. - Set up Composer autoloading for the ZK library.
This commit is contained in:
91
zklib/src/Attendance.php
Normal file
91
zklib/src/Attendance.php
Normal file
@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
namespace ZK;
|
||||
|
||||
use ZKLib;
|
||||
|
||||
class Attendance
|
||||
{
|
||||
/**
|
||||
* @param ZKLib $self
|
||||
* @return array [uid, id, state, timestamp]
|
||||
*/
|
||||
public function get(ZKLib $self)
|
||||
{
|
||||
$self->_section = __METHOD__;
|
||||
|
||||
$command = Util::CMD_ATT_LOG_RRQ;
|
||||
$command_string = '';
|
||||
|
||||
$session = $self->_command($command, $command_string, Util::COMMAND_TYPE_DATA);
|
||||
if ($session === false) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$attData = Util::recData($self);
|
||||
|
||||
$attendance = [];
|
||||
if (!empty($attData)) {
|
||||
$attData = substr($attData, 10);
|
||||
|
||||
while (strlen($attData) > 40) {
|
||||
$u = unpack('H78', substr($attData, 0, 39));
|
||||
|
||||
$u1 = hexdec(substr($u[1], 4, 2));
|
||||
$u2 = hexdec(substr($u[1], 6, 2));
|
||||
$uid = $u1 + ($u2 * 256);
|
||||
$id = hex2bin(substr($u[1], 8, 18));
|
||||
$id = str_replace(chr(0), '', $id);
|
||||
$state = hexdec(substr($u[1], 56, 2));
|
||||
$timestamp = Util::decodeTime(hexdec(Util::reverseHex(substr($u[1], 58, 8))));
|
||||
$type = hexdec(Util::reverseHex(substr($u[1], 66, 2 )));
|
||||
|
||||
// $timestamp_date = date('Y-m-d', $timestamp);
|
||||
date_default_timezone_set('Asia/Jakarta');
|
||||
$timestamp_date = date('Y-m-d', strtotime($timestamp));
|
||||
$current_date = date('Y-m-d');
|
||||
|
||||
|
||||
// if ($timestamp_date == $current_date) {
|
||||
// $attendance[] = [
|
||||
// 'uid' => $uid,
|
||||
// 'id' => $id,
|
||||
// 'state' => $state,
|
||||
// 'timestamp' => $timestamp,
|
||||
// 'type' => $type
|
||||
// ];
|
||||
// }
|
||||
|
||||
$attendance[] = [
|
||||
'uid' => $uid,
|
||||
'id' => $id,
|
||||
'state' => $state,
|
||||
'timestamp' => $timestamp,
|
||||
'type' => $type
|
||||
];
|
||||
|
||||
|
||||
|
||||
$attData = substr($attData, 40);
|
||||
}
|
||||
|
||||
}
|
||||
// var_dump($current_date);
|
||||
// die();
|
||||
return $attendance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ZKLib $self
|
||||
* @return bool|mixed
|
||||
*/
|
||||
public function clear(ZKLib $self)
|
||||
{
|
||||
$self->_section = __METHOD__;
|
||||
|
||||
$command = Util::CMD_CLEAR_ATT_LOG;
|
||||
$command_string = '';
|
||||
|
||||
return $self->_command($command, $command_string);
|
||||
}
|
||||
}
|
||||
82
zklib/src/Connect.php
Normal file
82
zklib/src/Connect.php
Normal file
@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
namespace ZK;
|
||||
|
||||
use ZKLib;
|
||||
use ErrorException;
|
||||
use Exception;
|
||||
|
||||
class Connect
|
||||
{
|
||||
/**
|
||||
* @param ZKLib $self
|
||||
* @return bool
|
||||
*/
|
||||
public function connect(ZKLib $self)
|
||||
{
|
||||
$self->_section = __METHOD__;
|
||||
|
||||
$command = Util::CMD_CONNECT;
|
||||
$command_string = '';
|
||||
$chksum = 0;
|
||||
$session_id = 0;
|
||||
$reply_id = -1 + Util::USHRT_MAX;
|
||||
|
||||
$buf = Util::createHeader($command, $chksum, $session_id, $reply_id, $command_string);
|
||||
|
||||
socket_sendto($self->_zkclient, $buf, strlen($buf), 0, $self->_ip, $self->_port);
|
||||
|
||||
try {
|
||||
@socket_recvfrom($self->_zkclient, $self->_data_recv, 1024, 0, $self->_ip, $self->_port);
|
||||
if (strlen($self->_data_recv) > 0) {
|
||||
$u = unpack('H2h1/H2h2/H2h3/H2h4/H2h5/H2h6', substr($self->_data_recv, 0, 8));
|
||||
|
||||
$session = hexdec($u['h6'] . $u['h5']);
|
||||
if (empty($session)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$self->_session_id = $session;
|
||||
return Util::checkValid($self->_data_recv);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} catch (ErrorException $e) {
|
||||
return false;
|
||||
} catch (Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ZKLib $self
|
||||
* @return bool
|
||||
*/
|
||||
public function disconnect(ZKLib $self)
|
||||
{
|
||||
$self->_section = __METHOD__;
|
||||
|
||||
$command = Util::CMD_EXIT;
|
||||
$command_string = '';
|
||||
$chksum = 0;
|
||||
$session_id = $self->_session_id;
|
||||
|
||||
$u = unpack('H2h1/H2h2/H2h3/H2h4/H2h5/H2h6/H2h7/H2h8', substr($self->_data_recv, 0, 8));
|
||||
$reply_id = hexdec($u['h8'] . $u['h7']);
|
||||
|
||||
$buf = Util::createHeader($command, $chksum, $session_id, $reply_id, $command_string);
|
||||
|
||||
|
||||
socket_sendto($self->_zkclient, $buf, strlen($buf), 0, $self->_ip, $self->_port);
|
||||
try {
|
||||
@socket_recvfrom($self->_zkclient, $self->_data_recv, 1024, 0, $self->_ip, $self->_port);
|
||||
|
||||
$self->_session_id = 0;
|
||||
return Util::checkValid($self->_data_recv);
|
||||
} catch (ErrorException $e) {
|
||||
return false;
|
||||
} catch (Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
50
zklib/src/Device.php
Normal file
50
zklib/src/Device.php
Normal file
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace ZK;
|
||||
|
||||
use ZKLib;
|
||||
|
||||
class Device
|
||||
{
|
||||
/**
|
||||
* @param ZKLib $self
|
||||
* @return bool|mixed
|
||||
*/
|
||||
public function name(ZKLib $self)
|
||||
{
|
||||
$self->_section = __METHOD__;
|
||||
|
||||
$command = Util::CMD_DEVICE;
|
||||
$command_string = '~DeviceName';
|
||||
|
||||
return $self->_command($command, $command_string);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ZKLib $self
|
||||
* @return bool|mixed
|
||||
*/
|
||||
public function enable(ZKLib $self)
|
||||
{
|
||||
$self->_section = __METHOD__;
|
||||
|
||||
$command = Util::CMD_ENABLE_DEVICE;
|
||||
$command_string = '';
|
||||
|
||||
return $self->_command($command, $command_string);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ZKLib $self
|
||||
* @return bool|mixed
|
||||
*/
|
||||
public function disable(ZKLib $self)
|
||||
{
|
||||
$self->_section = __METHOD__;
|
||||
|
||||
$command = Util::CMD_DISABLE_DEVICE;
|
||||
$command_string = chr(0) . chr(0);
|
||||
|
||||
return $self->_command($command, $command_string);
|
||||
}
|
||||
}
|
||||
23
zklib/src/Face.php
Normal file
23
zklib/src/Face.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace ZK;
|
||||
|
||||
use ZKLib;
|
||||
|
||||
class Face
|
||||
{
|
||||
/**
|
||||
* @param ZKLib $self
|
||||
* @return bool|mixed
|
||||
*/
|
||||
public function on(ZKLib $self)
|
||||
{
|
||||
$self->_section = __METHOD__;
|
||||
|
||||
$command = Util::CMD_DEVICE;
|
||||
$command_string = 'FaceFunOn';
|
||||
|
||||
return $self->_command($command, $command_string);
|
||||
}
|
||||
}
|
||||
|
||||
162
zklib/src/Fingerprint.php
Normal file
162
zklib/src/Fingerprint.php
Normal file
@ -0,0 +1,162 @@
|
||||
<?php
|
||||
|
||||
namespace ZK;
|
||||
|
||||
use ZKLib;
|
||||
|
||||
class Fingerprint
|
||||
{
|
||||
/**
|
||||
* TODO: Can get data, but don't know how to parse the data. Need more documentation about it...
|
||||
*
|
||||
* @param ZKLib $self
|
||||
* @param integer $uid Unique Employee ID in ZK device
|
||||
* @return array Binary fingerprint data array (where key is finger ID (0-9))
|
||||
*/
|
||||
public function get(ZKLib $self, $uid)
|
||||
{
|
||||
$self->_section = __METHOD__;
|
||||
|
||||
$data = [];
|
||||
//fingers of the hands
|
||||
for ($i = 0; $i <= 9; $i++) {
|
||||
$tmp = $this->_getFinger($self, $uid, $i);
|
||||
if ($tmp['size'] > 0) {
|
||||
$data[$i] = $tmp['tpl'];
|
||||
}
|
||||
unset($tmp);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ZKLib $self
|
||||
* @param integer $uid Unique Employee ID in ZK device
|
||||
* @param integer $finger Finger ID (0-9)
|
||||
* @return array
|
||||
*/
|
||||
private function _getFinger(ZKLib $self, $uid, $finger)
|
||||
{
|
||||
$command = Util::CMD_USER_TEMP_RRQ;
|
||||
$byte1 = chr((int)($uid % 256));
|
||||
$byte2 = chr((int)($uid >> 8));
|
||||
$command_string = $byte1 . $byte2 . chr($finger);
|
||||
|
||||
$ret = [
|
||||
'size' => 0,
|
||||
'tpl' => ''
|
||||
];
|
||||
|
||||
$session = $self->_command($command, $command_string, Util::COMMAND_TYPE_DATA);
|
||||
if ($session === false) {
|
||||
return $ret;
|
||||
}
|
||||
|
||||
$data = Util::recData($self, 10, false);
|
||||
|
||||
if (!empty($data)) {
|
||||
$templateSize = strlen($data);
|
||||
$prefix = chr($templateSize % 256) . chr(round($templateSize / 256)) . $byte1 . $byte2 . chr($finger) . chr(1);
|
||||
$data = $prefix . $data;
|
||||
if (strlen($templateSize) > 0) {
|
||||
$ret['size'] = $templateSize;
|
||||
$ret['tpl'] = $data;
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Still can not set fingerprint. Need more documentation about it...
|
||||
*
|
||||
* @param ZKLib $self
|
||||
* @param int $uid Unique Employee ID in ZK device
|
||||
* @param array $data Binary fingerprint data array (where key is finger ID (0-9) same like returned array from 'get' method)
|
||||
* @return int Count of added fingerprints
|
||||
*/
|
||||
public function set(ZKLib $self, $uid, array $data)
|
||||
{
|
||||
$self->_section = __METHOD__;
|
||||
|
||||
|
||||
$count = 0;
|
||||
foreach ($data as $finger => $item) {
|
||||
$allowSet = true;
|
||||
if ($this->_checkFinger($self, $uid, $finger) === true) {
|
||||
$allowSet = $this->_removeFinger($self, $uid, $finger);
|
||||
}
|
||||
if ($allowSet === true && $this->_setFinger($self, $item) === true) {
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ZKLib $self
|
||||
* @param string $data Binary fingerprint data item
|
||||
* @return bool|mixed
|
||||
*/
|
||||
private function _setFinger(ZKLib $self, $data)
|
||||
{
|
||||
$command = Util::CMD_USER_TEMP_WRQ;
|
||||
$command_string = $data;
|
||||
|
||||
return $self->_command($command, $command_string);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ZKLib $self
|
||||
* @param int $uid Unique Employee ID in ZK device
|
||||
* @param array $data Fingers ID array (0-9)
|
||||
* @return int Count of deleted fingerprints
|
||||
*/
|
||||
public function remove(ZKLib $self, $uid, array $data)
|
||||
{
|
||||
$self->_section = __METHOD__;
|
||||
|
||||
$count = 0;
|
||||
foreach ($data as $finger) {
|
||||
if ($this->_checkFinger($self, $uid, $finger) === true) {
|
||||
if ($this->_removeFinger($self, $uid, $finger) === true) {
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ZKLib $self
|
||||
* @param int $uid Unique Employee ID in ZK device
|
||||
* @param int $finger Finger ID (0-9)
|
||||
* @return bool
|
||||
*/
|
||||
private function _removeFinger(ZKLib $self, $uid, $finger)
|
||||
{
|
||||
$command = Util::CMD_DELETE_USER_TEMP;
|
||||
$byte1 = chr((int)($uid % 256));
|
||||
$byte2 = chr((int)($uid >> 8));
|
||||
$command_string = ($byte1 . $byte2) . chr($finger);
|
||||
|
||||
$self->_command($command, $command_string);
|
||||
|
||||
return !($this->_checkFinger($self, $uid, $finger));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ZKLib $self
|
||||
* @param int $uid Unique Employee ID in ZK device
|
||||
* @param int $finger Finger ID (0-9)
|
||||
* @return bool Returned true if exist
|
||||
*/
|
||||
private function _checkFinger(ZKLib $self, $uid, $finger)
|
||||
{
|
||||
$res = $this->_getFinger($self, $uid, $finger);
|
||||
return (bool)($res['size'] > 0);
|
||||
}
|
||||
}
|
||||
22
zklib/src/Os.php
Normal file
22
zklib/src/Os.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace ZK;
|
||||
|
||||
use ZKLib;
|
||||
|
||||
class Os
|
||||
{
|
||||
/**
|
||||
* @param ZKLib $self
|
||||
* @return bool|mixed
|
||||
*/
|
||||
public function get(ZKLib $self)
|
||||
{
|
||||
$self->_section = __METHOD__;
|
||||
|
||||
$command = Util::CMD_DEVICE;
|
||||
$command_string = '~OS';
|
||||
|
||||
return $self->_command($command, $command_string);
|
||||
}
|
||||
}
|
||||
22
zklib/src/Pin.php
Normal file
22
zklib/src/Pin.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace ZK;
|
||||
|
||||
use ZKLib;
|
||||
|
||||
class Pin
|
||||
{
|
||||
/**
|
||||
* @param ZKLib $self
|
||||
* @return bool|mixed
|
||||
*/
|
||||
public function width(ZKLib $self)
|
||||
{
|
||||
$self->_section = __METHOD__;
|
||||
|
||||
$command = Util::CMD_DEVICE;
|
||||
$command_string = '~PIN2Width';
|
||||
|
||||
return $self->_command($command, $command_string);
|
||||
}
|
||||
}
|
||||
36
zklib/src/Platform.php
Normal file
36
zklib/src/Platform.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace ZK;
|
||||
|
||||
use ZKLib;
|
||||
|
||||
class Platform
|
||||
{
|
||||
/**
|
||||
* @param ZKLib $self
|
||||
* @return bool|mixed
|
||||
*/
|
||||
public function get(ZKLib $self)
|
||||
{
|
||||
$self->_section = __METHOD__;
|
||||
|
||||
$command = Util::CMD_DEVICE;
|
||||
$command_string = '~Platform';
|
||||
|
||||
return $self->_command($command, $command_string);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ZKLib $self
|
||||
* @return bool|mixed
|
||||
*/
|
||||
public function getVersion(ZKLib $self)
|
||||
{
|
||||
$self->_section = __METHOD__;
|
||||
|
||||
$command = Util::CMD_DEVICE;
|
||||
$command_string = '~ZKFPVersion';
|
||||
|
||||
return $self->_command($command, $command_string);
|
||||
}
|
||||
}
|
||||
22
zklib/src/SerialNumber.php
Normal file
22
zklib/src/SerialNumber.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace ZK;
|
||||
|
||||
use ZKLib;
|
||||
|
||||
class SerialNumber
|
||||
{
|
||||
/**
|
||||
* @param ZKLib $self
|
||||
* @return bool|mixed
|
||||
*/
|
||||
public function get(ZKLib $self)
|
||||
{
|
||||
$self->_section = __METHOD__;
|
||||
|
||||
$command = Util::CMD_DEVICE;
|
||||
$command_string = '~SerialNumber';
|
||||
|
||||
return $self->_command($command, $command_string);
|
||||
}
|
||||
}
|
||||
22
zklib/src/Ssr.php
Normal file
22
zklib/src/Ssr.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace ZK;
|
||||
|
||||
use ZKLib;
|
||||
|
||||
class Ssr
|
||||
{
|
||||
/**
|
||||
* @param ZKLib $self
|
||||
* @return bool|mixed
|
||||
*/
|
||||
public function get(ZKLib $self)
|
||||
{
|
||||
$self->_section = __METHOD__;
|
||||
|
||||
$command = Util::CMD_DEVICE;
|
||||
$command_string = '~SSR';
|
||||
|
||||
return $self->_command($command, $command_string);
|
||||
}
|
||||
}
|
||||
43
zklib/src/Time.php
Normal file
43
zklib/src/Time.php
Normal file
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace ZK;
|
||||
|
||||
use ZKLib;
|
||||
|
||||
class Time
|
||||
{
|
||||
/**
|
||||
* @param ZKLib $self
|
||||
* @param string $t Format: "Y-m-d H:i:s"
|
||||
* @return bool|mixed
|
||||
*/
|
||||
public function set(ZKLib $self, $t)
|
||||
{
|
||||
$self->_section = __METHOD__;
|
||||
|
||||
$command = Util::CMD_SET_TIME;
|
||||
$command_string = pack('I', Util::encodeTime($t));
|
||||
|
||||
return $self->_command($command, $command_string);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ZKLib $self
|
||||
* @return bool|mixed
|
||||
*/
|
||||
public function get(ZKLib $self)
|
||||
{
|
||||
$self->_section = __METHOD__;
|
||||
|
||||
$command = Util::CMD_GET_TIME;
|
||||
$command_string = '';
|
||||
|
||||
$ret = $self->_command($command, $command_string);
|
||||
|
||||
if ($ret) {
|
||||
return Util::decodeTime(hexdec(Util::reverseHex(bin2hex($ret))));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
161
zklib/src/User.php
Normal file
161
zklib/src/User.php
Normal file
@ -0,0 +1,161 @@
|
||||
<?php
|
||||
|
||||
namespace ZK;
|
||||
|
||||
use ZKLib;
|
||||
|
||||
class User
|
||||
{
|
||||
/**
|
||||
* @param ZKLib $self
|
||||
* @param int $uid Unique ID (max 65535)
|
||||
* @param int|string $userid (max length = 9, only numbers - depends device setting)
|
||||
* @param string $name (max length = 24)
|
||||
* @param int|string $password (max length = 8, only numbers - depends device setting)
|
||||
* @param int $role Default Util::LEVEL_USER
|
||||
* @param int $cardno Default 0 (max length = 10, only numbers)
|
||||
* @return bool|mixed
|
||||
*/
|
||||
public function set(ZKLib $self, $uid, $userid, $name, $password, $role = Util::LEVEL_USER, $cardno = 0)
|
||||
{
|
||||
$self->_section = __METHOD__;
|
||||
|
||||
if (
|
||||
(int)$uid === 0 ||
|
||||
(int)$uid > Util::USHRT_MAX ||
|
||||
strlen($userid) > 9 ||
|
||||
strlen($name) > 24 ||
|
||||
strlen($password) > 8 ||
|
||||
strlen($cardno) > 10
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$command = Util::CMD_SET_USER;
|
||||
$byte1 = chr((int)($uid % 256));
|
||||
$byte2 = chr((int)($uid >> 8));
|
||||
$cardno = hex2bin(Util::reverseHex(dechex($cardno)));
|
||||
|
||||
$command_string = implode('', [
|
||||
$byte1,
|
||||
$byte2,
|
||||
chr($role),
|
||||
str_pad($password, 8, chr(0)),
|
||||
str_pad($name, 24, chr(0)),
|
||||
str_pad($cardno, 4, chr(0)),
|
||||
str_pad(chr(1), 9, chr(0)),
|
||||
str_pad($userid, 9, chr(0)),
|
||||
str_repeat(chr(0), 15)
|
||||
]);
|
||||
|
||||
return $self->_command($command, $command_string);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ZKLib $self
|
||||
* @return array [userid, name, cardno, uid, role, password]
|
||||
*/
|
||||
public function get(ZKLib $self)
|
||||
{
|
||||
$self->_section = __METHOD__;
|
||||
|
||||
$command = Util::CMD_USER_TEMP_RRQ;
|
||||
$command_string = chr(Util::FCT_USER);
|
||||
|
||||
$session = $self->_command($command, $command_string, Util::COMMAND_TYPE_DATA);
|
||||
if ($session === false) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$userData = Util::recData($self);
|
||||
|
||||
$users = [];
|
||||
if (!empty($userData)) {
|
||||
$userData = substr($userData, 11);
|
||||
|
||||
while (strlen($userData) > 72) {
|
||||
$u = unpack('H144', substr($userData, 0, 72));
|
||||
|
||||
$u1 = hexdec(substr($u[1], 2, 2));
|
||||
$u2 = hexdec(substr($u[1], 4, 2));
|
||||
$uid = $u1 + ($u2 * 256);
|
||||
$cardno = hexdec(substr($u[1], 78, 2) . substr($u[1], 76, 2) . substr($u[1], 74, 2) . substr($u[1], 72, 2)) . ' ';
|
||||
$role = hexdec(substr($u[1], 6, 2)) . ' ';
|
||||
$password = hex2bin(substr($u[1], 8, 16)) . ' ';
|
||||
$name = hex2bin(substr($u[1], 24, 74)) . ' ';
|
||||
$userid = hex2bin(substr($u[1], 98, 72)) . ' ';
|
||||
|
||||
//Clean up some messy characters from the user name
|
||||
$password = explode(chr(0), $password, 2);
|
||||
$password = $password[0];
|
||||
$userid = explode(chr(0), $userid, 2);
|
||||
$userid = $userid[0];
|
||||
$name = explode(chr(0), $name, 3);
|
||||
$name = utf8_encode($name[0]);
|
||||
$cardno = str_pad($cardno, 11, '0', STR_PAD_LEFT);
|
||||
|
||||
if ($name == '') {
|
||||
$name = $userid;
|
||||
}
|
||||
|
||||
$users[$userid] = [
|
||||
'userid' => $userid,
|
||||
'name' => $name,
|
||||
'cardno' => $cardno,
|
||||
'uid' => $uid,
|
||||
'role' => intval($role),
|
||||
'password' => $password
|
||||
];
|
||||
|
||||
$userData = substr($userData, 72);
|
||||
}
|
||||
}
|
||||
|
||||
return $users;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ZKLib $self
|
||||
* @return bool|mixed
|
||||
*/
|
||||
public function clear(ZKLib $self)
|
||||
{
|
||||
$self->_section = __METHOD__;
|
||||
|
||||
$command = Util::CMD_CLEAR_DATA;
|
||||
$command_string = '';
|
||||
|
||||
return $self->_command($command, $command_string);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ZKLib $self
|
||||
* @return bool|mixed
|
||||
*/
|
||||
public function clearAdmin(ZKLib $self)
|
||||
{
|
||||
$self->_section = __METHOD__;
|
||||
|
||||
$command = Util::CMD_CLEAR_ADMIN;
|
||||
$command_string = '';
|
||||
|
||||
return $self->_command($command, $command_string);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ZKLib $self
|
||||
* @param integer $uid
|
||||
* @return bool|mixed
|
||||
*/
|
||||
public function remove(ZKLib $self, $uid)
|
||||
{
|
||||
$self->_section = __METHOD__;
|
||||
|
||||
$command = Util::CMD_DELETE_USER;
|
||||
$byte1 = chr((int)($uid % 256));
|
||||
$byte2 = chr((int)($uid >> 8));
|
||||
$command_string = ($byte1 . $byte2);
|
||||
|
||||
return $self->_command($command, $command_string);
|
||||
}
|
||||
}
|
||||
415
zklib/src/Util.php
Normal file
415
zklib/src/Util.php
Normal file
@ -0,0 +1,415 @@
|
||||
<?php
|
||||
|
||||
namespace ZK;
|
||||
|
||||
use ZKLib;
|
||||
|
||||
class Util
|
||||
{
|
||||
const USHRT_MAX = 65535;
|
||||
|
||||
const CMD_CONNECT = 1000; # Connections requests
|
||||
const CMD_EXIT = 1001; # Disconnection requests
|
||||
const CMD_ENABLE_DEVICE = 1002; # Ensure the machine to be at the normal work condition
|
||||
const CMD_DISABLE_DEVICE = 1003; # Make the machine to be at the shut-down condition, generally demonstrates ‘in the work ...’on LCD
|
||||
|
||||
const CMD_ACK_OK = 2000; # Return value for order perform successfully
|
||||
const CMD_ACK_ERROR = 2001; # Return value for order perform failed
|
||||
const CMD_ACK_DATA = 2002; # Return data
|
||||
const CMD_ACK_UNAUTH = 2005; # Connection unauthorized
|
||||
|
||||
const CMD_PREPARE_DATA = 1500; # Prepares to transmit the data
|
||||
const CMD_DATA = 1501; # Transmit a data packet
|
||||
const CMD_FREE_DATA = 1502; # Clear machines open buffer
|
||||
|
||||
const CMD_USER_TEMP_RRQ = 9; # Read some fingerprint template or some kind of data entirely
|
||||
const CMD_ATT_LOG_RRQ = 13; # Read all attendance record
|
||||
const CMD_CLEAR_DATA = 14; # Clear Data
|
||||
const CMD_CLEAR_ATT_LOG = 15; # Clear attendance records
|
||||
|
||||
const CMD_GET_TIME = 201; # Obtain the machine time
|
||||
const CMD_SET_TIME = 202; # Set machines time
|
||||
|
||||
const CMD_VERSION = 1100; # Obtain the firmware edition
|
||||
const CMD_DEVICE = 11; # Read in the machine some configuration parameter
|
||||
|
||||
const CMD_SET_USER = 8; # Upload the user information (from PC to terminal).
|
||||
const CMD_USER_TEMP_WRQ = 10; # Upload some fingerprint template
|
||||
const CMD_DELETE_USER = 18; # Delete some user
|
||||
const CMD_DELETE_USER_TEMP = 19; # Delete some fingerprint template
|
||||
const CMD_CLEAR_ADMIN = 20; # Cancel the manager
|
||||
|
||||
const LEVEL_USER = 0;
|
||||
const LEVEL_ADMIN = 14;
|
||||
|
||||
const FCT_ATTLOG = 1;
|
||||
const FCT_WORKCODE = 8;
|
||||
const FCT_FINGERTMP = 2;
|
||||
const FCT_OPLOG = 4;
|
||||
const FCT_USER = 5;
|
||||
const FCT_SMS = 6;
|
||||
const FCT_UDATA = 7;
|
||||
|
||||
const COMMAND_TYPE_GENERAL = 'general';
|
||||
const COMMAND_TYPE_DATA = 'data';
|
||||
|
||||
const ATT_STATE_FINGERPRINT = 1;
|
||||
const ATT_STATE_PASSWORD = 0;
|
||||
const ATT_STATE_CARD = 2;
|
||||
|
||||
const ATT_TYPE_CHECK_IN = 0;
|
||||
const ATT_TYPE_CHECK_OUT = 1;
|
||||
const ATT_TYPE_OVERTIME_IN = 4;
|
||||
const ATT_TYPE_OVERTIME_OUT = 5;
|
||||
|
||||
/**
|
||||
* Encode a timestamp send at the timeclock
|
||||
* copied from zkemsdk.c - EncodeTime
|
||||
*
|
||||
* @param string $t Format: "Y-m-d H:i:s"
|
||||
* @return int
|
||||
*/
|
||||
static public function encodeTime($t)
|
||||
{
|
||||
$timestamp = strtotime($t);
|
||||
$t = (object)[
|
||||
'year' => (int)date('Y', $timestamp),
|
||||
'month' => (int)date('m', $timestamp),
|
||||
'day' => (int)date('d', $timestamp),
|
||||
'hour' => (int)date('H', $timestamp),
|
||||
'minute' => (int)date('i', $timestamp),
|
||||
'second' => (int)date('s', $timestamp),
|
||||
];
|
||||
|
||||
$d = (($t->year % 100) * 12 * 31 + (($t->month - 1) * 31) + $t->day - 1) *
|
||||
(24 * 60 * 60) + ($t->hour * 60 + $t->minute) * 60 + $t->second;
|
||||
|
||||
return $d;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a timestamp retrieved from the timeclock
|
||||
* copied from zkemsdk.c - DecodeTime
|
||||
*
|
||||
* @param int|string $t
|
||||
* @return false|string Format: "Y-m-d H:i:s"
|
||||
*/
|
||||
static public function decodeTime($t)
|
||||
{
|
||||
$second = $t % 60;
|
||||
$t = $t / 60;
|
||||
|
||||
$minute = $t % 60;
|
||||
$t = $t / 60;
|
||||
|
||||
$hour = $t % 24;
|
||||
$t = $t / 24;
|
||||
|
||||
$day = $t % 31 + 1;
|
||||
$t = $t / 31;
|
||||
|
||||
$month = $t % 12 + 1;
|
||||
$t = $t / 12;
|
||||
|
||||
$year = floor($t + 2000);
|
||||
|
||||
$d = date('Y-m-d H:i:s', strtotime(
|
||||
$year . '-' . $month . '-' . $day . ' ' . $hour . ':' . $minute . ':' . $second
|
||||
));
|
||||
|
||||
return $d;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $hex
|
||||
* @return string
|
||||
*/
|
||||
static public function reverseHex($hex)
|
||||
{
|
||||
$tmp = '';
|
||||
|
||||
for ($i = strlen($hex); $i >= 0; $i--) {
|
||||
$tmp .= substr($hex, $i, 2);
|
||||
$i--;
|
||||
}
|
||||
|
||||
return $tmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a returned packet to see if it returned self::CMD_PREPARE_DATA,
|
||||
* indicating that data packets are to be sent
|
||||
* Returns the amount of bytes that are going to be sent
|
||||
*
|
||||
* @param ZKLib $self
|
||||
* @return bool|number
|
||||
*/
|
||||
static public function getSize(ZKLib $self)
|
||||
{
|
||||
$u = unpack('H2h1/H2h2/H2h3/H2h4/H2h5/H2h6/H2h7/H2h8', substr($self->_data_recv, 0, 8));
|
||||
$command = hexdec($u['h2'] . $u['h1']);
|
||||
|
||||
if ($command == self::CMD_PREPARE_DATA) {
|
||||
$u = unpack('H2h1/H2h2/H2h3/H2h4', substr($self->_data_recv, 8, 4));
|
||||
$size = hexdec($u['h4'] . $u['h3'] . $u['h2'] . $u['h1']);
|
||||
return $size;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function calculates the chksum of the packet to be sent to the
|
||||
* time clock
|
||||
* Copied from zkemsdk.c
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
static public function createChkSum($p)
|
||||
{
|
||||
$l = count($p);
|
||||
$chksum = 0;
|
||||
$i = $l;
|
||||
$j = 1;
|
||||
while ($i > 1) {
|
||||
$u = unpack('S', pack('C2', $p['c' . $j], $p['c' . ($j + 1)]));
|
||||
|
||||
$chksum += $u[1];
|
||||
|
||||
if ($chksum > self::USHRT_MAX) {
|
||||
$chksum -= self::USHRT_MAX;
|
||||
}
|
||||
$i -= 2;
|
||||
$j += 2;
|
||||
}
|
||||
|
||||
if ($i) {
|
||||
$chksum = $chksum + $p['c' . strval(count($p))];
|
||||
}
|
||||
|
||||
while ($chksum > self::USHRT_MAX) {
|
||||
$chksum -= self::USHRT_MAX;
|
||||
}
|
||||
|
||||
if ($chksum > 0) {
|
||||
$chksum = -($chksum);
|
||||
} else {
|
||||
$chksum = abs($chksum);
|
||||
}
|
||||
|
||||
$chksum -= 1;
|
||||
while ($chksum < 0) {
|
||||
$chksum += self::USHRT_MAX;
|
||||
}
|
||||
|
||||
return pack('S', $chksum);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function puts a the parts that make up a packet together and
|
||||
* packs them into a byte string
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
static public function createHeader($command, $chksum, $session_id, $reply_id, $command_string)
|
||||
{
|
||||
$buf = pack('SSSS', $command, $chksum, $session_id, $reply_id) . $command_string;
|
||||
|
||||
$buf = unpack('C' . (8 + strlen($command_string)) . 'c', $buf);
|
||||
|
||||
$u = unpack('S', self::createChkSum($buf));
|
||||
|
||||
if (is_array($u)) {
|
||||
$u = reset($u);
|
||||
}
|
||||
$chksum = $u;
|
||||
|
||||
$reply_id += 1;
|
||||
|
||||
if ($reply_id >= self::USHRT_MAX) {
|
||||
$reply_id -= self::USHRT_MAX;
|
||||
}
|
||||
|
||||
$buf = pack('SSSS', $command, $chksum, $session_id, $reply_id);
|
||||
|
||||
return $buf . $command_string;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a returned packet to see if it returned Util::CMD_ACK_OK,
|
||||
* indicating success
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
static public function checkValid($reply)
|
||||
{
|
||||
$u = unpack('H2h1/H2h2', substr($reply, 0, 8));
|
||||
|
||||
$command = hexdec($u['h2'] . $u['h1']);
|
||||
/** TODO: Some device can return 'Connection unauthorized' then should check also */
|
||||
if ($command == self::CMD_ACK_OK || $command == self::CMD_ACK_UNAUTH) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get User Role string
|
||||
* @param integer $role
|
||||
* @return string
|
||||
*/
|
||||
static public function getUserRole($role)
|
||||
{
|
||||
switch ($role) {
|
||||
case self::LEVEL_USER:
|
||||
$ret = 'User';
|
||||
break;
|
||||
case self::LEVEL_ADMIN:
|
||||
$ret = 'Admin';
|
||||
break;
|
||||
default:
|
||||
$ret = 'Unknown';
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Attendance State string
|
||||
* @param integer $state
|
||||
* @return string
|
||||
*/
|
||||
static public function getAttState($state)
|
||||
{
|
||||
switch ($state) {
|
||||
case self::ATT_STATE_FINGERPRINT:
|
||||
$ret = 'Fingerprint';
|
||||
break;
|
||||
case self::ATT_STATE_PASSWORD:
|
||||
$ret = 'Password';
|
||||
break;
|
||||
case self::ATT_STATE_CARD:
|
||||
$ret = 'Card';
|
||||
break;
|
||||
default:
|
||||
$ret = 'Unknown';
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Attendance Type string
|
||||
* @param integer $type
|
||||
* @return string
|
||||
*/
|
||||
static public function getAttType($type)
|
||||
{
|
||||
switch ($type) {
|
||||
case self::ATT_TYPE_CHECK_IN:
|
||||
$ret = 'Check-in';
|
||||
break;
|
||||
case self::ATT_TYPE_CHECK_OUT:
|
||||
$ret = 'Check-out';
|
||||
break;
|
||||
case self::ATT_TYPE_OVERTIME_IN:
|
||||
$ret = 'Overtime-in';
|
||||
break;
|
||||
case self::ATT_TYPE_OVERTIME_OUT:
|
||||
$ret = 'Overtime-out';
|
||||
break;
|
||||
default:
|
||||
$ret = 'Undefined';
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive data from device
|
||||
* @param ZKLib $self
|
||||
* @param int $maxErrors
|
||||
* @param bool $first if 'true' don't remove first 4 bytes for first row
|
||||
* @return string
|
||||
*/
|
||||
static public function recData(ZKLib $self, $maxErrors = 10, $first = true)
|
||||
{
|
||||
$data = '';
|
||||
$bytes = self::getSize($self);
|
||||
|
||||
if ($bytes) {
|
||||
$received = 0;
|
||||
$errors = 0;
|
||||
|
||||
while ($bytes > $received) {
|
||||
$ret = @socket_recvfrom($self->_zkclient, $dataRec, 1032, 0, $self->_ip, $self->_port);
|
||||
|
||||
if ($ret === false) {
|
||||
if ($errors < $maxErrors) {
|
||||
//try again if false
|
||||
$errors++;
|
||||
sleep(1);
|
||||
continue;
|
||||
} else {
|
||||
//return empty if has maximum count of errors
|
||||
self::logReceived($self, $received, $bytes);
|
||||
unset($data);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
if ($first === false) {
|
||||
//The first 4 bytes don't seem to be related to the user
|
||||
$dataRec = substr($dataRec, 8);
|
||||
}
|
||||
|
||||
$data .= $dataRec;
|
||||
$received += strlen($dataRec);
|
||||
|
||||
unset($dataRec);
|
||||
$first = false;
|
||||
}
|
||||
|
||||
//flush socket
|
||||
@socket_recvfrom($self->_zkclient, $dataRec, 1024, 0, $self->_ip, $self->_port);
|
||||
unset($dataRec);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ZKLib $self
|
||||
* @param int $received
|
||||
* @param int $bytes
|
||||
*/
|
||||
static private function logReceived(ZKLib $self, $received, $bytes)
|
||||
{
|
||||
self::logger($self, 'Received: ' . $received . ' of ' . $bytes . ' bytes');
|
||||
}
|
||||
|
||||
/**
|
||||
* Write log
|
||||
* @param ZKLib $self
|
||||
* @param string $str
|
||||
*/
|
||||
static private function logger(ZKLib $self, $str)
|
||||
{
|
||||
if (defined('ZK_LIB_LOG')) {
|
||||
//use constant if defined
|
||||
$log = ZK_LIB_LOG;
|
||||
} else {
|
||||
$dir = dirname(dirname(__FILE__));
|
||||
$log = $dir . '/logs/error.log';
|
||||
}
|
||||
|
||||
$row = '<' . $self->_ip . '> [' . date('d.m.Y H:i:s') . '] ';
|
||||
$row .= (empty($self->_section) ? '' : '(' . $self->_section . ') ');
|
||||
$row .= $str;
|
||||
$row .= PHP_EOL;
|
||||
|
||||
file_put_contents($log, $row, FILE_APPEND);
|
||||
}
|
||||
}
|
||||
22
zklib/src/Version.php
Normal file
22
zklib/src/Version.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace ZK;
|
||||
|
||||
use ZKLib;
|
||||
|
||||
class Version
|
||||
{
|
||||
/**
|
||||
* @param ZKLib $self
|
||||
* @return bool|mixed
|
||||
*/
|
||||
public function get(ZKLib $self)
|
||||
{
|
||||
$self->_section = __METHOD__;
|
||||
|
||||
$command = Util::CMD_VERSION;
|
||||
$command_string = '';
|
||||
|
||||
return $self->_command($command, $command_string);
|
||||
}
|
||||
}
|
||||
22
zklib/src/WorkCode.php
Normal file
22
zklib/src/WorkCode.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace ZK;
|
||||
|
||||
use ZKLib;
|
||||
|
||||
class WorkCode
|
||||
{
|
||||
/**
|
||||
* @param ZKLib $self
|
||||
* @return bool|mixed
|
||||
*/
|
||||
public function get(ZKLib $self)
|
||||
{
|
||||
$self->_section = __METHOD__;
|
||||
|
||||
$command = Util::CMD_DEVICE;
|
||||
$command_string = 'WorkCode';
|
||||
|
||||
return $self->_command($command, $command_string);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user