Repository: raihanafroz/zkteco Branch: master Commit: 6487ac5dfab3 Files: 20 Total size: 45.4 KB Directory structure: gitextract__pwo6lda/ ├── CHANGELOG.md ├── README.md ├── composer.json └── src/ ├── Lib/ │ ├── Helper/ │ │ ├── Attendance.php │ │ ├── Connect.php │ │ ├── Device.php │ │ ├── Face.php │ │ ├── Fingerprint.php │ │ ├── Os.php │ │ ├── Pin.php │ │ ├── Platform.php │ │ ├── SerialNumber.php │ │ ├── Ssr.php │ │ ├── Time.php │ │ ├── User.php │ │ ├── Util.php │ │ ├── Version.php │ │ └── WorkCode.php │ └── ZKTeco.php └── Providers/ └── ZktecoServiceProvider.php ================================================ FILE CONTENTS ================================================ ================================================ FILE: CHANGELOG.md ================================================ ================================================ FILE: README.md ================================================ # ZKTeco - Laravel Library # [![Issues](https://img.shields.io/github/issues/raihanafroz/zkteco?style=flat-square)](https://github.com/raihanafroz/zkteco/issues) [![Forks](https://img.shields.io/github/forks/raihanafroz/zkteco?style=flat-square)](https://github.com/raihanafroz/zkteco/network/members) [![Stars](https://img.shields.io/github/stars/raihanafroz/zkteco?style=flat-square)](https://github.com/raihanafroz/zkteco/stargazers) [![Total Downloads](https://img.shields.io/packagist/dt/rats/zkteco?style=flat-square)](https://packagist.org/packages/rats/zkteco) [![License](https://poser.pugx.org/rats/zkteco/license.svg)](https://packagist.org/packages/rats/zkteco) The `rats/zkteco` package provides easy to use functions to ZKTeco Device activities. __Requires:__ **Laravel** >= **6.0** __License:__ MIT or later ## Installation: You can install the package via composer: ``` bash composer require rats/zkteco ``` The package will automatically register itself. You have to enable your php socket if it is not enable. ## Usage 1. Create a object of ZKTeco class. ```php use Rats\Zkteco\Lib\ZKTeco; // 1 s't parameter is string $ip Device IP Address // 2 nd parameter is integer $port Default: 4370 $zk = new ZKTeco('192.168.1.201'); // or you can use with port // $zk = new ZKTeco('192.168.1.201', 8080); ``` 2. Call ZKTeco methods * __Connect__ ```php // connect // this return bool $zk->connect(); ``` * __Disconnect__ ```php // disconnect // this return bool $zk->disconnect(); ``` * __Enable Device__ ```php // enable // this return bool/mixed $zk->enableDevice(); ``` > **NOTE**: You have to call after read/write any info of Device. * __Disable Device__ ```php // disable // this return bool/mixed $zk->disableDevice(); ``` > **NOTE**: You have to call before read/write any info of Device. * __Device Version__ ```php // get device version // this return bool/mixed $zk->version(); ``` * __Device Os Version__ ```php // get device os version // this return bool/mixed $zk->osVersion(); ``` * __Power Off__ ```php // turn off the device // this return bool/mixed $zk->shutdown(); ``` * __Restart__ ```php // restart the device // this return bool/mixed $zk->restart(); ``` * __Sleep__ ```php // sleep the device // this return bool/mixed $zk->sleep(); ``` * __Resume__ ```php // resume the device from sleep // this return bool/mixed $zk->resume(); ``` * __Voice Test__ ```php // voice test of the device "Thank you" // this return bool/mixed $zk->testVoice(); ``` * __Platform__ ```php // get platform // this return bool/mixed $zk->platform(); ``` * __Firmware Version__ ```php // get firmware version // this return bool/mixed $zk->fmVersion(); ``` * __Work Code__ ```php // get work code // this return bool/mixed $zk->workCode(); ``` * __SSR__ ```php // get SSR // this return bool/mixed $zk->ssr(); ``` * __Pin Width__ ```php // get Pin Width // this return bool/mixed $zk->pinWidth(); ``` * __Serial Number__ ```php // get device serial number // this return bool/mixed $zk->serialNumber(); ``` * __Device Name__ ```php // get device name // this return bool/mixed $zk->deviceName(); ``` * __Get Device Time__ ```php // get device time // return bool/mixed bool|mixed Format: "Y-m-d H:i:s" $zk->getTime(); ``` * __Set Device Time__ ```php // set device time // parameter string $t Format: "Y-m-d H:i:s" // return bool/mixed $zk->setTime(); ``` * __Get Users__ ```php // get User // this return array[] $zk->getUser(); ``` * __Set Users__ ```php // set user // 1 s't parameter int $uid Unique ID (max 65535) // 2 nd parameter int|string $userid ID in DB (same like $uid, max length = 9, only numbers - depends device setting) // 3 rd parameter string $name (max length = 24) // 4 th parameter int|string $password (max length = 8, only numbers - depends device setting) // 5 th parameter int $role Default Util::LEVEL_USER // 6 th parameter int $cardno Default 0 (max length = 10, only numbers // return bool|mixed $zk->setUser(); ``` * __Clear All Admin__ ```php // remove all admin // return bool|mixed $zk->clearAdmin(); ``` * __Clear All Users__ ```php // remove all users // return bool|mixed $zk->clearAdmin(); ``` * __Remove A User__ ```php // remove a user by $uid // parameter integer $uid // return bool|mixed $zk->removeUser(); ``` * __Get Attendance Log__ ```php // get attendance log // return array[] // like as 0 => array:5 [▼ // "uid" => 1 /* serial number of the attendance */ // "id" => "1" /* user id of the application */ // "state" => 1 /* the authentication type, 1 for Fingerprint, 4 for RF Card etc */ // "timestamp" => "2020-05-27 21:21:06" /* time of attendance */ // "type" => 255 /* attendance type, like check-in, check-out, overtime-in, overtime-out, break-in & break-out etc. if attendance type is none of them, it gives 255. */ // ] $zk->getAttendance(); ``` * __Clear Attendance Log__ ```php // clear attendance log // return bool/mixed $zk->clearAttendance(); ``` # end ================================================ FILE: composer.json ================================================ { "name": "rats/zkteco", "description": "ZKTeco Laravel Library", "type": "library", "license": "MIT", "authors": [ { "name": "Raihan Afroz", "email": "raihanafroz9@gmail.com" } ], "autoload": { "psr-4":{ "Rats\\Zkteco\\": "src" } }, "minimum-stability": "dev", "require": {} } ================================================ FILE: src/Lib/Helper/Attendance.php ================================================ _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 ))); $attendance[] = [ 'uid' => $uid, 'id' => $id, 'state' => $state, 'timestamp' => $timestamp, 'type' => $type ]; $attData = substr($attData, 40); } } return $attendance; } /** * @param ZKTeco $self * @return bool|mixed */ static public function clear(ZKTeco $self) { $self->_section = __METHOD__; $command = Util::CMD_CLEAR_ATT_LOG; $command_string = ''; return $self->_command($command, $command_string); } } ================================================ FILE: src/Lib/Helper/Connect.php ================================================ _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 ZKTeco $self * @return bool */ static public function disconnect(ZKTeco $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; } } } ================================================ FILE: src/Lib/Helper/Device.php ================================================ _section = __METHOD__; $command = Util::CMD_DEVICE; $command_string = '~DeviceName'; return $self->_command($command, $command_string); } /** * @param ZKTeco $self * @return bool|mixed */ static public function enable(ZKTeco $self) { $self->_section = __METHOD__; $command = Util::CMD_ENABLE_DEVICE; $command_string = ''; return $self->_command($command, $command_string); } /** * @param ZKTeco $self * @return bool|mixed */ static public function disable(ZKTeco $self) { $self->_section = __METHOD__; $command = Util::CMD_DISABLE_DEVICE; $command_string = chr(0) . chr(0); return $self->_command($command, $command_string); } /** * @param ZKTeco $self * @return bool|mixed *** this will turn off the device */ public static function powerOff(ZKTeco $self) { $self->_section = __METHOD__; $command = Util::CMD_POWEROFF; $command_string = chr(0) . chr(0); return $self->_command($command, $command_string); } /** * @param ZKTeco $self * @return bool|mixed *** this will restart the device */ public static function restart(ZKTeco $self) { $self->_section = __METHOD__; $command = Util::CMD_RESTART; $command_string = chr(0) . chr(0); return $self->_command($command, $command_string); } /** * @param ZKTeco $self * @return bool|mixed *** this will sleep the device */ public static function sleep(ZKTeco $self) { $self->_section = __METHOD__; $command = Util::CMD_SLEEP; $command_string = chr(0) . chr(0); return $self->_command($command, $command_string); } /** * @param ZKTeco $self * @return bool|mixed *** this will resume the device from sleep */ public static function resume(ZKTeco $self) { $self->_section = __METHOD__; $command = Util::CMD_RESUME; $command_string = chr(0) . chr(0); return $self->_command($command, $command_string); } /** * @param ZKTeco $self * @return bool|mixed *** this will play voice "Thank you" */ public static function testVoice(ZKTeco $self) { $self->_section = __METHOD__; $command = Util::CMD_TESTVOICE; $command_string = chr(0) . chr(0); return $self->_command($command, $command_string); } /** * @param ZKTeco $self * @return bool|mixed *** this will clear the LCD screen */ public static function clearLCD(ZKTeco $self) { $self->_section = __METHOD__; $command = Util::CMD_CLEAR_LCD; return $self->_command($command, ''); } /** * @param ZKTeco $self * @param $rank *** Line number of text * @param $text *** Text which will display in the LCD screen * @return bool|mixed *** this will write text into the LCD */ public static function writeLCD(ZKTeco $self, $rank, $text) { $self->_section = __METHOD__; $command = Util::CMD_WRITE_LCD; $byte1 = chr((int)($rank % 256)); $byte2 = chr((int)($rank >> 8)); $byte3 = chr(0); $command_string = $byte1.$byte2.$byte3.' '.$text; return $self->_command($command, $command_string); } } ================================================ FILE: src/Lib/Helper/Face.php ================================================ _section = __METHOD__; $command = Util::CMD_DEVICE; $command_string = 'FaceFunOn'; return $self->_command($command, $command_string); } } ================================================ FILE: src/Lib/Helper/Fingerprint.php ================================================ _section = __METHOD__; $data = []; //fingers of the hands for ($i = 0; $i <= 9; $i++) { $finger = new Fingerprint(); $tmp = $finger->_getFinger($self, $uid, $i); if ($tmp['size'] > 0) { $data[$i] = $tmp['tpl']; } unset($tmp); } return $data; } /** * @param ZKTeco $self * @param integer $uid Unique Employee ID in ZK device * @param integer $finger Finger ID (0-9) * @return array */ private function _getFinger(ZKTeco $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 ZKTeco $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 */ static public function set(ZKTeco $self, $uid, array $data) { $self->_section = __METHOD__; $count = 0; foreach ($data as $finger => $item) { $allowSet = true; $fingerPrint = new Fingerprint(); if ($fingerPrint->_checkFinger($self, $uid, $finger) === true) { $allowSet = $fingerPrint->_removeFinger($self, $uid, $finger); } if ($allowSet === true && $fingerPrint->_setFinger($self, $item) === true) { $count++; } } return $count; } /** * @param ZKTeco $self * @param string $data Binary fingerprint data item * @return bool|mixed */ private function _setFinger(ZKTeco $self, $data) { $command = Util::CMD_USER_TEMP_WRQ; $command_string = $data; return $self->_command($command, $command_string); } /** * @param ZKTeco $self * @param int $uid Unique Employee ID in ZK device * @param array $data Fingers ID array (0-9) * @return int Count of deleted fingerprints */ static public function remove(ZKTeco $self, $uid, array $data) { $self->_section = __METHOD__; $count = 0; foreach ($data as $finger) { $fingerPrint = new Fingerprint(); if ($fingerPrint->_checkFinger($self, $uid, $finger) === true) { if ($fingerPrint->_removeFinger($self, $uid, $finger) === true) { $count++; } } } return $count; } /** * @param ZKTeco $self * @param int $uid Unique Employee ID in ZK device * @param int $finger Finger ID (0-9) * @return bool */ private function _removeFinger(ZKTeco $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); $fingerPrint = new Fingerprint(); return !($fingerPrint->_checkFinger($self, $uid, $finger)); } /** * @param ZKTeco $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(ZKTeco $self, $uid, $finger) { $fingerPrint = new Fingerprint(); $res = $fingerPrint->_getFinger($self, $uid, $finger); return (bool)($res['size'] > 0); } } ================================================ FILE: src/Lib/Helper/Os.php ================================================ _section = __METHOD__; $command = Util::CMD_DEVICE; $command_string = '~OS'; return $self->_command($command, $command_string); } } ================================================ FILE: src/Lib/Helper/Pin.php ================================================ _section = __METHOD__; $command = Util::CMD_DEVICE; $command_string = '~PIN2Width'; return $self->_command($command, $command_string); } } ================================================ FILE: src/Lib/Helper/Platform.php ================================================ _section = __METHOD__; $command = Util::CMD_DEVICE; $command_string = '~Platform'; return $self->_command($command, $command_string); } /** * @param ZKTeco $self * @return bool|mixed */ static public function getVersion(ZKTeco $self) { $self->_section = __METHOD__; $command = Util::CMD_DEVICE; $command_string = '~ZKFPVersion'; return $self->_command($command, $command_string); } } ================================================ FILE: src/Lib/Helper/SerialNumber.php ================================================ _section = __METHOD__; $command = Util::CMD_DEVICE; $command_string = '~SerialNumber'; return $self->_command($command, $command_string); } } ================================================ FILE: src/Lib/Helper/Ssr.php ================================================ _section = __METHOD__; $command = Util::CMD_DEVICE; $command_string = '~SSR'; return $self->_command($command, $command_string); } } ================================================ FILE: src/Lib/Helper/Time.php ================================================ _section = __METHOD__; $command = Util::CMD_SET_TIME; $command_string = pack('I', Util::encodeTime($t)); return $self->_command($command, $command_string); } /** * @param ZKTeco $self * @return bool|mixed */ static public function get(ZKTeco $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; } } } ================================================ FILE: src/Lib/Helper/User.php ================================================ _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) ]); // die($command_string); return $self->_command($command, $command_string); } /** * @param ZKTeco $self * @return array [userid, name, cardno, uid, role, password] */ static public function get(ZKTeco $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] = [ 'uid' => $uid, 'userid' => $userid, 'name' => $name, 'role' => intval($role), 'password' => $password, 'cardno' => $cardno, ]; $userData = substr($userData, 72); } } return $users; } /** * @param ZKTeco $self * @return bool|mixed */ static public function clear(ZKTeco $self) { $self->_section = __METHOD__; $command = Util::CMD_CLEAR_DATA; $command_string = ''; return $self->_command($command, $command_string); } /** * @param ZKTeco $self * @return bool|mixed */ static public function clearAdmin(ZKTeco $self) { $self->_section = __METHOD__; $command = Util::CMD_CLEAR_ADMIN; $command_string = ''; return $self->_command($command, $command_string); } /** * @param ZKTeco $self * @param integer $uid * @return bool|mixed */ static public function remove(ZKTeco $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); } } ================================================ FILE: src/Lib/Helper/Util.php ================================================ (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 ZKTeco $self * @return bool|number */ static public function getSize(ZKTeco $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 ZKTeco $self * @param int $maxErrors * @param bool $first if 'true' don't remove first 4 bytes for first row * @return string */ static public function recData(ZKTeco $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 ZKTeco $self * @param int $received * @param int $bytes */ static private function logReceived(ZKTeco $self, $received, $bytes) { self::logger($self, 'Received: ' . $received . ' of ' . $bytes . ' bytes'); } /** * Write log * @param ZKTeco $self * @param string $str */ static private function logger(ZKTeco $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); } } ================================================ FILE: src/Lib/Helper/Version.php ================================================ _section = __METHOD__; $command = Util::CMD_VERSION; $command_string = ''; return $self->_command($command, $command_string); } } ================================================ FILE: src/Lib/Helper/WorkCode.php ================================================ _section = __METHOD__; $command = Util::CMD_DEVICE; $command_string = 'WorkCode'; return $self->_command($command, $command_string); } } ================================================ FILE: src/Lib/ZKTeco.php ================================================ _ip = $ip; $this->_port = $port; $this->_zkclient = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); $timeout = array('sec' => 60, 'usec' => 500000); socket_set_option($this->_zkclient, SOL_SOCKET, SO_RCVTIMEO, $timeout); } /** * Create and send command to device * * @param string $command * @param string $command_string * @param string $type * @return bool|mixed */ public function _command($command, $command_string, $type = Util::COMMAND_TYPE_GENERAL) { $chksum = 0; $session_id = $this->_session_id; $u = unpack('H2h1/H2h2/H2h3/H2h4/H2h5/H2h6/H2h7/H2h8', substr($this->_data_recv, 0, 8)); $reply_id = hexdec($u['h8'] . $u['h7']); $buf = Util::createHeader($command, $chksum, $session_id, $reply_id, $command_string); socket_sendto($this->_zkclient, $buf, strlen($buf), 0, $this->_ip, $this->_port); try { @socket_recvfrom($this->_zkclient, $this->_data_recv, 1024, 0, $this->_ip, $this->_port); $u = unpack('H2h1/H2h2/H2h3/H2h4/H2h5/H2h6', substr($this->_data_recv, 0, 8)); $ret = false; $session = hexdec($u['h6'] . $u['h5']); if ($type === Util::COMMAND_TYPE_GENERAL && $session_id === $session) { $ret = substr($this->_data_recv, 8); } else if ($type === Util::COMMAND_TYPE_DATA && !empty($session)) { $ret = $session; } return $ret; } catch (ErrorException $e) { return false; } catch (Exception $e) { return false; } } /** * Connect to device * * @return bool */ public function connect() { return Connect::connect($this); } /** * Disconnect from device * * @return bool */ public function disconnect() { return Connect::disconnect($this); } /** * Get device version * * @return bool|mixed */ public function version() { return Version::get($this); } /** * Get OS version * * @return bool|mixed */ public function osVersion() { return Os::get($this); } /** * Get platform * * @return bool|mixed */ public function platform() { return Platform::get($this); } /** * Get firmware version * * @return bool|mixed */ public function fmVersion() { return Platform::getVersion($this); } /** * Get work code * * @return bool|mixed */ public function workCode() { return WorkCode::get($this); } /** * Get SSR * * @return bool|mixed */ public function ssr() { return Ssr::get($this); } /** * Get pin width * * @return bool|mixed */ public function pinWidth() { return Pin::width($this); } /** * @return bool|mixed */ public function faceFunctionOn() { return Face::on($this); } /** * Get device serial number * * @return bool|mixed */ public function serialNumber() { return SerialNumber::get($this); } /** * Get device name * * @return bool|mixed */ public function deviceName() { return Device::name($this); } /** * Disable device * * @return bool|mixed */ public function disableDevice() { return Device::disable($this); } /** * Enable device * * @return bool|mixed */ public function enableDevice() { return Device::enable($this); } /** * Get users data * * @return array [userid, name, cardno, uid, role, password] */ public function getUser() { return User::get($this); } /** * Set user data * * @param int $uid Unique ID (max 65535) * @param int|string $userid ID in DB (same like $uid, 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 setUser($uid, $userid, $name, $password, $role = Util::LEVEL_USER, $cardno = 0) { return User::set($this, $uid, $userid, $name, $password, $role, $cardno); } /** * Remove All users * * @return bool|mixed */ public function clearUsers() { return User::clear($this); } /** * Remove admin * * @return bool|mixed */ public function clearAdmin() { return User::clearAdmin($this); } /** * Remove user by UID * * @param integer $uid * @return bool|mixed */ public function removeUser($uid) { return User::remove($this, $uid); } /** * Get fingerprint data array by UID * TODO: Can get data, but don't know how to parse the data. Need more documentation about it... * * @param integer $uid Unique ID (max 65535) * @return array Binary fingerprint data array (where key is finger ID (0-9)) */ public function getFingerprint($uid) { return Fingerprint::get($this, $uid); } /** * Set fingerprint data array * TODO: Still can not set fingerprint. Need more documentation about it... * * @param integer $uid Unique ID (max 65535) * @param array $data Binary fingerprint data array (where key is finger ID (0-9) same like returned array from 'getFingerprint' method) * @return int Count of added fingerprints */ public function setFingerprint($uid, array $data) { return Fingerprint::set($this, $uid, $data); } /** * Remove fingerprint by UID and fingers ID array * * @param integer $uid Unique ID (max 65535) * @param array $data Fingers ID array (0-9) * @return int Count of deleted fingerprints */ public function removeFingerprint($uid, array $data) { return Fingerprint::remove($this, $uid, $data); } /** * Get attendance log * * @return array [uid, id, state, timestamp] */ public function getAttendance() { return Attendance::get($this); } /** * Clear attendance log * * @return bool|mixed */ public function clearAttendance() { return Attendance::clear($this); } /** * Set device time * * @param string $t Format: "Y-m-d H:i:s" * @return bool|mixed */ public function setTime($t) { return Time::set($this, $t); } /** * Get device time * * @return bool|mixed Format: "Y-m-d H:i:s" */ public function getTime() { return Time::get($this); } /** * turn off the device * * @return bool|mixed */ public function shutdown() { return Device::powerOff($this); } /** * restart the device * * @return bool|mixed */ public function restart() { return Device::restart($this); } /** * make sleep mood the device * * @return bool|mixed */ public function sleep() { return Device::sleep($this); } /** * resume the device from sleep * * @return bool|mixed */ public function resume() { return Device::resume($this); } /** * voice test Sound will "Thank you" * * @return bool|mixed */ public function testVoice() { return Device::testVoice($this); } public function clearLCD() { return Device::clearLCD($this); } public function writeLCD() { return Device::writeLCD($this, 2, "RAIHAN Afroz Topu"); } } ================================================ FILE: src/Providers/ZktecoServiceProvider.php ================================================