ReadCommand.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  1. <?php
  2. namespace App\Console\Commands;
  3. use App\Jobs\SendDataJob;
  4. use Illuminate\Console\Command;
  5. use Illuminate\Support\Facades\Cache;
  6. use Illuminate\Support\Facades\DB;
  7. use Illuminate\Support\Facades\Redis;
  8. class ReadCommand extends Command
  9. {
  10. /**
  11. * The name and signature of the console command.
  12. *
  13. * @var string
  14. */
  15. protected $signature = 'command:readTXT';
  16. /**
  17. * The console command description.
  18. *
  19. * @var string
  20. */
  21. protected $description = '读取文件';
  22. /**
  23. * Create a new command instance.
  24. *
  25. * @return void
  26. */
  27. public function __construct()
  28. {
  29. parent::__construct();
  30. }
  31. const desktop_port = 9501; //桌面设备端口
  32. const inventory_port = 7880; //盘点设备端口
  33. /**
  34. * Execute the console command.
  35. *
  36. * @return mixed
  37. */
  38. public function handle()
  39. {
  40. $this->tcpServer();
  41. $this->info('Your command executed!');
  42. }
  43. public function tcpServer(){
  44. //本地ipv4地址
  45. $ipv4 = $this->getMyIpV4();
  46. $host = env('HOST_TCP'); // 主机局域网地址
  47. $port = env('HOST_PORT'); // 端口号
  48. if(empty($host)) $host = $ipv4;
  49. if(empty($port)) $port = self::inventory_port;
  50. // 创建一个TCP socket
  51. $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
  52. // 绑定到指定的主机和端口 第二个参数不写 默认局域网ipv4地址
  53. socket_bind($socket, '', $port);
  54. // 监听连接
  55. socket_listen($socket);
  56. // 初始内存使用量
  57. $initialMemoryUsage = memory_get_usage();
  58. echo date("Y-m-d H:i:s") . " 服务器" . $host . ":" . $port . "已启动监听\n";
  59. file_put_contents('C:\Users\Administrator\Desktop\record.txt',date("Y-m-d H:i:s") . "服务器已启动".PHP_EOL,8);
  60. while (true) {
  61. // 接受连接请求并创建新的套接字
  62. $clientSocket = socket_accept($socket);
  63. if ($clientSocket === false) {
  64. // 错误处理
  65. $error = socket_strerror(socket_last_error($socket));
  66. echo "接受连接请求失败:{$error}\n";
  67. continue; // 继续下一次循环
  68. }
  69. // 读取客户端发送的数据
  70. $data = socket_read($clientSocket, 1024);
  71. // file_put_contents('C:\Users\Administrator\Desktop\record2.txt',$data .PHP_EOL,8);
  72. $this->byteParsingInventory($data);
  73. // 发送响应给客户端
  74. // $response = "服务器已接收到您的消息:" . $data;
  75. // socket_write($clientSocket, $response, strlen($response));
  76. $currentMemoryUsage = memory_get_usage();
  77. $memoryDiff = $currentMemoryUsage - $initialMemoryUsage;
  78. echo "内存使用量变化:" . $memoryDiff . " 字节\n";
  79. $initialMemoryUsage = $currentMemoryUsage;
  80. // 关闭当前连接的套接字
  81. socket_close($clientSocket);
  82. gc_collect_cycles();
  83. sleep(5);
  84. }
  85. // 关闭服务器套接字
  86. socket_close($socket);
  87. }
  88. //桌面设备 数据解析发送
  89. public function byteParsing3($data){
  90. $hexData = bin2hex($data);
  91. $hexData = str_replace(' ', '', $hexData);
  92. $toReplace = array("a6a8001300000a00010101001708120012000103b5a5a7", "a6a8000c00000a0003120001037da5a7");
  93. $result = str_replace($toReplace, "", $hexData);
  94. // echo "原数据:" . $hexData . PHP_EOL;
  95. // $memoryUsage = memory_get_usage();
  96. // echo "当前脚本占用的内存量:".$memoryUsage." 字节" . "\n";
  97. //
  98. // $memoryUsage = memory_get_peak_usage();
  99. // echo "PHP程序总内存使用量:" . $memoryUsage . " 字节" . "\n";
  100. if($result){
  101. $last38Chars = substr($result, -38, 32);
  102. echo "替换后:" . $last38Chars . PHP_EOL;
  103. file_put_contents('C:\Users\Administrator\Desktop\record.txt',$last38Chars.PHP_EOL,8);
  104. if(! empty($last38Chars)) {
  105. $this->sendData([$last38Chars]);
  106. echo '发送成功---!' . "\n";
  107. }
  108. }
  109. }
  110. //盘点设备 数据解析发送
  111. // 5a55167fa90d010cbbdd8204000116010a000000000000476a69
  112. // 5a55166dcd0d010cbbdd8204000116010a000000000000596a69
  113. // 5a551679b50d010cbbdd8204000116010a0000000000004d6a69
  114. //
  115. public function byteParsingInventory($data){
  116. $frame = $this->test($data);
  117. // 获取传递的数据
  118. $payload = $frame['payload'];
  119. // 输出传递的数据
  120. // echo bin2hex($payload);die;
  121. // echo "替换后:" . $data . PHP_EOL;
  122. DB::table('test')->insert(['data' => bin2hex($payload)]);
  123. // $hexData = bin2hex($data);
  124. // $hexData = str_replace(' ', '', $hexData);
  125. //// $toReplace = array("5a55167fa90d010cbbdd8204000116010a000000000000476a69", "5a55166dcd0d010cbbdd8204000116010a000000000000596a69","5a551679b50d010cbbdd8204000116010a0000000000004d6a69","5a551673c10d010cbbdd8204000116010a000000000000536a69","5a55167faa0d010cbbdd8204000116010a000000000000486a69","5a551679b60d010cbbdd8204000116010a0000000000004e6a69");
  126. // $toReplace = [];
  127. // $result = str_replace($toReplace, "", $hexData);
  128. //
  129. // if($result){
  130. // echo "替换后:" . $result . PHP_EOL;
  131. //
  132. // file_put_contents('C:\Users\Administrator\Desktop\record.txt',$result.PHP_EOL,8);
  133. // if(! empty($last38Chars)) {
  134. // $this->sendData([$last38Chars]);
  135. // echo '发送成功---!' . "\n";
  136. // }
  137. // }
  138. }
  139. public function test($data){
  140. $frame = array();
  141. // 查找帧头
  142. $start = strpos($data, "\x5A\x55");
  143. if ($start !== false) {
  144. // 查找帧尾
  145. $end = strpos($data, "\x6A\x69", $start);
  146. if ($end !== false) {
  147. // 获取帧头到帧尾之间的数据
  148. $frameData = substr($data, $start + 2, $end - $start - 2);
  149. // 解析帧头子域、帧长度子域等字段
  150. // 获取帧长度子域值
  151. $frameLength = ord($frameData[0]);
  152. // 获取端口子域值
  153. $port = ord($frameData[3]);
  154. // 获取数据载荷子域
  155. $payload = substr($frameData, 6, $frameLength - 7);
  156. // 存储解析结果
  157. $frame['payload'] = $payload;
  158. }
  159. }
  160. return $frame;
  161. }
  162. //获取本机ipv4地址
  163. public function getMyIpV4(){
  164. $ip = exec("ipconfig | findstr /i \"IPv4\"");
  165. $parts = explode(": ", $ip);
  166. $ipAddress = $parts[1];
  167. return $ipAddress;
  168. }
  169. public function sendData($data){
  170. $url = env('CLOUD_ADDRESS',null);
  171. if(empty($url)) return;
  172. $curl = curl_init();
  173. curl_setopt_array($curl, array(
  174. CURLOPT_URL => $url,
  175. CURLOPT_RETURNTRANSFER => true,
  176. CURLOPT_ENCODING => '',
  177. CURLOPT_MAXREDIRS => 10,
  178. CURLOPT_TIMEOUT => 0,
  179. CURLOPT_FOLLOWLOCATION => true,
  180. CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  181. CURLOPT_CUSTOMREQUEST => 'POST',
  182. CURLOPT_POSTFIELDS => $data,
  183. ));
  184. $response = curl_exec($curl);
  185. curl_close($curl);
  186. }
  187. //----------------------暂时没用的代码--------------------------------------------------------
  188. function convertToHex($string) {
  189. $encoding = mb_detect_encoding($string);
  190. switch ($encoding) {
  191. case 'ASCII':
  192. return bin2hex($string);
  193. case 'GBK':
  194. return mb_convert_encoding($string, 'GBK', $encoding);
  195. case 'GB2312':
  196. return mb_convert_encoding($string, 'GBK', $encoding);
  197. case 'UTF-8':
  198. return bin2hex($string);
  199. case 'Unicode':
  200. // 对于Unicode编码,需要使用适当的函数或库来进行转换
  201. // 这里使用PHP的mb_convert_encoding函数将Unicode编码转换为UTF-8编码,然后再转换为十六进制
  202. return bin2hex(mb_convert_encoding($string, 'UTF-8', $encoding));
  203. default:
  204. return 'Unsupported encoding';
  205. }
  206. }
  207. public function byteParsing2($data){
  208. $frame = $data;
  209. // 提取字段值
  210. $frameHeader = bin2hex(substr($frame, 0, 2));
  211. $frameLength = unpack('v', substr($frame, 2, 2))[1];
  212. $frameSequence = unpack('v', substr($frame, 4, 2))[1];
  213. $port = ord(substr($frame, 6, 1));
  214. $communicationType = unpack('v', substr($frame, 7, 2))[1];
  215. $payload = substr($frame, 9, $frameLength - 8);
  216. $checksum = ord(substr($frame, -3, 1));
  217. $frameTail = bin2hex(substr($frame, -2));
  218. $payloadBytes = substr($frame, 9, 4); // 假设帧载荷在通信帧中的偏移量为9,并且长度为4个字节
  219. // 将4个字节转换为无符号整数(根据您的数据编码方式确定是否需要使用符号整数)
  220. $payloadValue = unpack('N', $payloadBytes)[1];
  221. echo "zhen" . $payloadValue . "\n";
  222. $payloadHex = sprintf('%08X', $payloadValue);
  223. echo "帧载荷值: $payloadHex\n";
  224. // 打印字段值
  225. echo "帧头: $frameHeader\n";
  226. echo "帧长度: $frameLength\n";
  227. echo "帧序号: $frameSequence\n";
  228. echo "端口: $port\n";
  229. echo "通信类型: $communicationType\n";
  230. echo "帧载荷: $payload\n";
  231. echo "校验和: $checksum\n";
  232. echo "帧尾: $frameTail\n";
  233. }
  234. public function byteParsing($data){
  235. // 接收到的TCP数据(以字节形式表示)
  236. $tcpData = $data;
  237. // 解析源端口和目标端口
  238. $sourcePort = unpack('n', substr($tcpData, 0, 2))[1];
  239. $destinationPort = unpack('n', substr($tcpData, 2, 2))[1];
  240. // 解析其他TCP头部字段,解析序列号
  241. $sequenceNumber = unpack('N', substr($tcpData, 4, 4))[1];
  242. // 获取TCP头部长度(通过读取数据偏移计算得出)
  243. $dataOffset = ord(substr($tcpData, 12, 1)) >> 4;
  244. $headerLength = $dataOffset * 4;
  245. // 提取数据部分
  246. $data = substr($tcpData, $headerLength);
  247. // 处理数据部分中的控制字符
  248. $data = $this->removeControlCharacters($data);
  249. // 打印解析结果
  250. echo "源端口: $sourcePort\n";
  251. echo "目标端口: $destinationPort\n";
  252. echo "序列号: $sequenceNumber\n";
  253. if(! empty($data)){
  254. echo "数据: $data\n";
  255. }
  256. }
  257. // 去除控制字符的函数
  258. function removeControlCharacters($string) {
  259. $controlChars = array(
  260. '/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/u', // 去除 ASCII 控制字符
  261. // '/\xEF\xBF\xBD/u' // 去除 UTF-8 中的替代字符
  262. );
  263. return preg_replace($controlChars, '', $string);
  264. }
  265. public function readTxt(){
  266. $directory = env('PROCESS_DIR',null);
  267. $directory = 'C:\Users\Administrator\Desktop\\'; // 替换为你的文件所在目录路径
  268. $currentDate = date('Y-m-d'); // 当前日期
  269. $file = $directory . "TesttoolLog" . $currentDate . '.log'; // 拼接文件路径和文件名
  270. $lastModified = filemtime($file); // 获取文件最后修改时间
  271. while (true) {
  272. clearstatcache(); // 清除文件状态缓存
  273. $currentDate = date('Y-m-d'); // 获取当前日期
  274. $currentFile = $directory . "TesttoolLog" . $currentDate . '.log'; // 当前日期对应的文件路径和文件名
  275. if ($file !== $currentFile) {
  276. // 文件已切换,更新文件路径和最后修改时间
  277. $file = $currentFile;
  278. $lastModified = filemtime($file);
  279. }
  280. $currentModified = filemtime($file); // 获取当前文件最后修改时间
  281. if ($currentModified > $lastModified) {
  282. // 文件已被修改,读取新增内容
  283. $handle = fopen($file, 'r');
  284. fseek($handle, -1, SEEK_END); // 定位到文件末尾前两个字节
  285. $data = fread($handle, 2); // 读取新增内容
  286. fclose($handle);
  287. // 处理新增内容
  288. // ...
  289. // 示例:打印新增内容
  290. echo $data;
  291. $lastModified = $currentModified; // 更新最后修改时间
  292. }
  293. sleep(1); // 睡眠一段时间后再次检查文件是否被修改
  294. }
  295. }
  296. //读取数据
  297. public function readTxtForData()
  298. {
  299. $directory = env('PROCESS_DIR',null);
  300. if(! $directory) {
  301. echo '未找到日志文件位置,请确认工具运行位置,再进行配置!';die;
  302. }
  303. $newLogFile = storage_path().'/app/public/record_device.txt';
  304. // $positionFile = storage_path().'/app/public/position_device.txt';
  305. date_default_timezone_set("PRC");
  306. $key = date("Y-m-d",time());
  307. $position = Cache::get($key);
  308. // 读取上次记录的位置
  309. $lastPosition = 0;
  310. if ($position) $lastPosition = $position;
  311. // if (file_exists($positionFile)) {
  312. // $lastPosition = intval(file_get_contents($positionFile));
  313. // }
  314. // 持续监视日志文件的变化
  315. while (true) {
  316. $key = date("Y-m-d",time());
  317. //日志源 文件位置
  318. $logFile = $directory . "/TesttoolLog" . $key . '.log';
  319. // 检查文件是否有更新
  320. clearstatcache(true, $logFile);
  321. $currentFileSize = filesize($logFile);
  322. echo "当前指针位置:$currentFileSize 上一次指针位置:$lastPosition \n";
  323. if ($currentFileSize > $lastPosition) {
  324. // 打开原始日志文件和新的日志文件
  325. $fileHandle = fopen($logFile, 'r');
  326. $newFileHandle = fopen($newLogFile, 'a'); // 使用追加模式打开新的日志文件
  327. // 移动文件指针到上次记录的位置
  328. fseek($fileHandle, $lastPosition);
  329. // 逐行读取并处理新增内容
  330. $read_data = [];
  331. while (($line = fgets($fileHandle)) !== false) {
  332. // 提取Tag数字
  333. $pattern = '/Tag:(\d+)/';
  334. preg_match($pattern, $line, $matches);
  335. if (isset($matches[1])) {
  336. $tagNumber = $matches[1];
  337. echo "接收到的数据:" . $tagNumber . "\n";
  338. $read_data[] = $tagNumber;
  339. // 将Tag数字写入新的日志文件
  340. fwrite($newFileHandle, $tagNumber . PHP_EOL);
  341. }
  342. }
  343. if(! empty($read_data)) {
  344. $this->sendData($read_data);
  345. echo '发送成功---!' . "\n";
  346. }
  347. // 获取新的位置并更新位置文件
  348. $lastPosition = ftell($fileHandle);
  349. Cache::put($key,$lastPosition,86400);
  350. // file_put_contents($positionFile, $lastPosition);
  351. // 关闭文件句柄
  352. fclose($fileHandle);
  353. fclose($newFileHandle);
  354. } else {
  355. echo '暂无新数据...' . "\n";
  356. // 在下一次检查之前休眠一段时间
  357. sleep(2);
  358. }
  359. }
  360. }
  361. public function cs(){
  362. $filePath = public_path('rfidreader-1.1.0.jar');
  363. $command = "java -cp $filePath com.example.MyJavaClass methodName argument1 argument2";
  364. $output = shell_exec($command);
  365. }
  366. }