如何将ESP32CAM视频流嵌入PHP网站实现车位状态管理
ESP32CAM停车场监控嵌入+状态更新实现方案
视频流嵌入与浮层实现
ESP32CAM默认输出MJPEG格式视频流,无需引入第三方播放器,直接用<img>标签即可拉流播放。通过CSS定位就能实现操作表格浮在视频上层的效果,参考代码如下:
<!-- 视频与浮层外层容器,用相对定位做定位上下文 --> <div style="position: relative; width: 100%; max-width: 1280px; margin: 0 auto;"> <!-- 替换成你自己的ESP32CAM实际IP,默认流路径为/stream --> <img src="http://192.168.x.x/stream" alt="停车场实时监控" style="width: 100%; display: block;"> <!-- 浮层操作区,绝对定位叠在视频上方 --> <div style="position: absolute; top: 20px; right: 20px; background: rgba(255,255,255,0.92); padding: 16px; border-radius: 6px; box-shadow: 0 2px 8px rgba(0,0,0,0.15);"> <table style="border-collapse: collapse;"> <thead> <tr> <th style="padding: 6px 12px; text-align: left; border-bottom: 1px solid #eee;">车位编号</th> <th style="padding: 6px 12px; text-align: left; border-bottom: 1px solid #eee;">状态操作</th> </tr> </thead> <tbody> <?php // 从数据库读取全量车位信息,循环生成表格行 // 以下为示例逻辑,替换成你自己的数据库查询代码即可 $db = mysqli_connect('你的数据库地址', '数据库账号', '数据库密码', '停车场库名'); $res = mysqli_query($db, "SELECT id, status FROM parking_spots ORDER BY id ASC"); while ($spot = mysqli_fetch_assoc($res)) { $currentStatus = $spot['status'] ? '占用' : '空闲'; $btnText = $spot['status'] ? '标记为空闲' : '标记为占用'; echo "<tr> <td style='padding: 8px 12px; border-bottom: 1px solid #f5f5f5;'>车位{$spot['id']}({$currentStatus})</td> <td style='padding: 8px 12px; border-bottom: 1px solid #f5f5f5;'> <button class='status-btn' data-spot-id='{$spot['id']}' style='padding: 4px 10px; cursor: pointer;'>{$btnText}</button> </td> </tr>"; } mysqli_close($db); ?> </tbody> </table> </div> </div>
浮层的位置、透明度、大小可以根据摄像头实际取景范围调整,不要遮挡车位线、车牌等关键监控区域即可。
按钮点击更新车位状态逻辑
用异步请求实现无刷新更新,避免打断视频流播放,分前端交互和后端接口两部分实现:
前端交互逻辑
在页面底部加如下JS代码,绑定按钮点击事件,向后端接口传对应车位ID:
document.querySelectorAll('.status-btn').forEach(btn => { btn.addEventListener('click', async function() { const spotId = this.dataset.spotId; // 临时禁用按钮防止重复提交 this.disabled = true; try { const resp = await fetch('update_spot_status.php', { method: 'POST', headers: {'Content-Type': 'application/x-www-form-urlencoded'}, body: `spot_id=${spotId}` }); const result = await resp.json(); if (result.code === 0) { // 更新成功后重载页面同步状态,也可以改成局部更新按钮文字减少刷新 window.location.reload(); } else { alert(`操作失败:${result.msg}`); this.disabled = false; } } catch (err) { alert('网络异常,请重试'); this.disabled = false; } }) })
后端更新接口
新建update_spot_status.php文件,处理状态更新逻辑,必须加权限校验和SQL注入防护:
<?php session_start(); // 替换成你自己的管理员登录态校验逻辑,未登录直接拒绝请求 if (empty($_SESSION['admin_login']) || $_SESSION['admin_login'] !== true) { echo json_encode(['code' => 403, 'msg' => '无操作权限']); exit; } $spotId = isset($_POST['spot_id']) ? intval($_POST['spot_id']) : 0; if ($spotId <= 0) { echo json_encode(['code' => 1, 'msg' => '参数非法']); exit; } // 连接数据库 $conn = mysqli_connect('你的数据库地址', '数据库账号', '数据库密码', '停车场库名'); if (!$conn) { echo json_encode(['code' => 2, 'msg' => '数据库连接失败']); exit; } // 查询当前状态做翻转,不需要前端传状态值,避免篡改 $stmt = mysqli_prepare($conn, "SELECT status FROM parking_spots WHERE id = ?"); mysqli_stmt_bind_param($stmt, "i", $spotId); mysqli_stmt_execute($stmt); mysqli_stmt_bind_result($stmt, $currentStatus); mysqli_stmt_fetch($stmt); mysqli_stmt_close($stmt); $newStatus = $currentStatus ? 0 : 1; // 预处理语句更新,避免SQL注入 $stmt = mysqli_prepare($conn, "UPDATE parking_spots SET status = ?, update_time = NOW() WHERE id = ?"); mysqli_stmt_bind_param($stmt, "ii", $newStatus, $spotId); $updateResult = mysqli_stmt_execute($stmt); mysqli_stmt_close($stmt); mysqli_close($conn); if ($updateResult) { echo json_encode(['code' => 0, 'msg' => '更新成功']); } else { echo json_encode(['code' => 3, 'msg' => '数据库更新失败']); } exit; ?>
常见问题注意点
- 如果你的PHP站部署在HTTPS协议下,直接嵌入HTTP的ESP32CAM流会被浏览器拦截混合内容,可在服务器端做一层流代理转发,或者内部场景直接用HTTP协议部署站点
- ESP32CAM性能有限,如果出现流卡顿,可适当降低摄像头分辨率、帧率,停车场监控场景800*600分辨率、10帧即可满足需求
- 不要把ESP32CAM的流地址直接暴露在公网,如果需要远程访问,务必给摄像头配置访问密码,同时做好端口访问控制
- 浮层可根据需求扩展,比如加实时车位占用统计、异常事件上报按钮等功能
内容的提问来源于stack exchange,提问作者RaccoonFromHell
相关产品推荐
相关产品推荐

