From 8dfa79d63685b3050ef454b0d0b410c1b0ce5f56 Mon Sep 17 00:00:00 2001 From: wanghongjun <1445693971@qq.com> Date: Thu, 6 Aug 2026 10:42:53 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AE=BE=E7=BD=AE=E9=A1=B9=E7=9B=AE=E6=97=B6?= =?UTF-8?q?=E5=8C=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Console/Commands/VehicleEntryAndExit.php | 9 +- app/Services/Device/CameraDeviceService.php | 30 +++++++ app/Services/Device/CommonService.php | 90 ++++++++++++++++++++ 3 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 app/Services/Device/CommonService.php diff --git a/app/Console/Commands/VehicleEntryAndExit.php b/app/Console/Commands/VehicleEntryAndExit.php index 789d327..ac52e2e 100644 --- a/app/Console/Commands/VehicleEntryAndExit.php +++ b/app/Console/Commands/VehicleEntryAndExit.php @@ -34,8 +34,14 @@ class VehicleEntryAndExit extends Command $data = []; foreach ($list as $item) { $ip = $item['camera_ip']; + $ParkingNo = ''; + $imageData = ''; try { - $ParkingNo = CameraDeviceService::query($ip)->getParkingNo(); + $MNPRData = CameraDeviceService::query($ip)->getTrafficMNPR(); + if ($MNPRData['licensePlate']) { + $ParkingNo = $MNPRData['licensePlate']; + $imageData = $MNPRData['images_data']; + } } catch (\Exception $e) { continue; } @@ -43,6 +49,7 @@ class VehicleEntryAndExit extends Command 'camera_ip' => $ip, 'number' => $item['number'], 'license_plate_number' => $ParkingNo, + 'image_data' => $imageData, 'date_time' => date('Y-m-d H:i:s', time()), ]; } diff --git a/app/Services/Device/CameraDeviceService.php b/app/Services/Device/CameraDeviceService.php index a9822d7..f99b859 100644 --- a/app/Services/Device/CameraDeviceService.php +++ b/app/Services/Device/CameraDeviceService.php @@ -8,6 +8,7 @@ class CameraDeviceService extends BaseService protected string $MULTI_PARKING_SPACES_LAMP = '/ISAPI/Parking/parkingSpace/multiParkingSpacesLamp'; protected string $SYSTEM_STATUS = '/ISAPI/System/status'; protected string $PARKING_STATUS = '/ISAPI/Parking/channels/?/ParkingStatus'; + protected string $TRAFFIC_MNPR = '/ISAPI/Traffic/MNPR/channels/'; /** * @param $ip @@ -82,6 +83,7 @@ class CameraDeviceService extends BaseService return $body; } + // 获取车位状态 public function getStatus(): bool { $url = $this->getUrl($this->SYSTEM_STATUS); @@ -104,4 +106,32 @@ class CameraDeviceService extends BaseService } return ''; } + + // 抓拍车位车牌及现场图片 + public function getTrafficMNPR($channels_id = 1) + { + $url = $this->getUrl($this->TRAFFIC_MNPR . $channels_id); + $response = $this->getHttp($url); + $body = $response->body(); + $parsed = CommonService::parseMultipart($body); + $data = [ + 'licensePlate' => '', + 'images_data' => '' + ]; + if ($parsed['xml'] && is_array($parsed['xml'])) { + if (isset($parsed['xml']['ANPR']['licensePlate'])) { + $licensePlate = $parsed['xml']['ANPR']['licensePlate']; + if ($licensePlate != '无车牌') { + $data['licensePlate'] = $licensePlate; + } + } + } + if ($data['licensePlate'] && $parsed['images'] && is_array($parsed['images'])) { + $endData = end($parsed['images']); + if (isset($endData['data'])) { + $data['images_data'] = $endData['data']; + } + } + return $data; + } } diff --git a/app/Services/Device/CommonService.php b/app/Services/Device/CommonService.php new file mode 100644 index 0000000..570e111 --- /dev/null +++ b/app/Services/Device/CommonService.php @@ -0,0 +1,90 @@ + $xml ? json_decode(json_encode($xml), true) : null, + 'images' => [] + ]; + } + $boundary = $matches[1]; + + // 2. 按边界分割(保留空块) + $blocks = explode("--$boundary", $raw); + $result = ['xml' => null, 'images' => []]; + + foreach ($blocks as $block) { + $block = trim($block); + if ($block === '' || $block === '--') { + continue; // 跳过空块和结束标记 + } + + // 3. 分离头部和内容(分隔符:\r\n\r\n 或 \n\n) + $sepPos = strpos($block, "\r\n\r\n"); + if ($sepPos === false) { + $sepPos = strpos($block, "\n\n"); + } + if ($sepPos === false) { + continue; // 未找到分隔,跳过 + } + + $headers = substr($block, 0, $sepPos); + $body = substr( + $block, + $sepPos + 4 + ); // 跳过 \r\n\r\n,如果是 \n\n 这里会多一个字符,但后续 trim 会处理 + + // 4. 根据头部判断类型 + $isXml = strpos($headers, 'filename="mnpr.xml"') !== false + || strpos($headers, 'text/xml') !== false; + + $isImage = strpos($headers, 'image/') !== false + || preg_match( + '/\.(jpg|jpeg|png|gif|bmp|webp)/i', + $headers + ); + + if ($isXml) { + // 清理可能残留的尾部边界标记 + $xmlString = trim($body); + // 移除尾部可能出现的 -- 或空白 + $xmlString = preg_replace('/\s*--\s*$/', '', $xmlString); + + // 尝试解析 XML + libxml_use_internal_errors(true); + $xmlObj = simplexml_load_string($xmlString); + if ($xmlObj !== false) { + $result['xml'] = json_decode(json_encode($xmlObj), true); + } else { + // 如果解析失败,将原始字符串保留(可记录错误) + $result['xml'] = $xmlString; // 或 null + } + } + + if ($isImage) { + // 提取文件名(可选) + preg_match('/filename="([^"]+)"/', $headers, $fname); + $filename = $fname[1] ?? 'image.jpg'; + + // 清除可能残留的尾部边界标记(二进制数据不要 trim!) + $imageData = preg_replace('/\s*--\s*$/', '', $body); + + $result['images'][] = [ + 'filename' => $filename, + 'data' => $imageData // 原始二进制 + ]; + } + } + + return $result; + } +}