
本文详解如何通过 php 动态生成 morris bar 图的 labels 数组,替代硬编码字符串,确保悬停提示准确显示数据库中的账户名(account),并避免手动拼接 json 导致的格式错误与安全风险。
本文详解如何通过 php 动态生成 morris bar 图的 labels 数组,替代硬编码字符串,确保悬停提示准确显示数据库中的账户名(account),并避免手动拼接 json 导致的格式错误与安全风险。
Morris.js 是一款轻量级、易集成的数据可视化库,常用于快速渲染条形图、折线图等。但在实际开发中,一个常见痛点是:labels 参数需为 JavaScript 字符串数组(如 ['Alice', 'Bob', 'Charlie']),而开发者常误将其设为字段名字符串(如 'account'),导致悬停提示失效或显示字段名而非真实值。
问题根源在于原始代码中 labels:'account' 的写法——这并非合法的 Morris 配置项(labels 应接收数组,而非字符串键名),且 data 数组也因手动拼接 JSON 字符串存在严重隐患:易产生语法错误(如未转义单引号)、SQL 注入风险、中文乱码及 XSS 漏洞。
✅ 正确解法是:分离数据结构与标签逻辑,用 json_encode() 安全生成标准 JSON,再由 Morris.js 原生支持的 labels 数组参数消费。
步骤一:优化 SQL 查询,统一字段别名
确保子查询返回的员工姓名字段名为 employee(与 Morris 的 xkey 保持一致),同时保留 account 字段用于标签:
SELECT
account,
(SELECT fullname FROM employees AS d WHERE r.emp_id = d.employee_code) AS employee,
COUNT(username) AS total
FROM logins AS r
GROUP BY account
ORDER BY employee ASC -- 注意:原 ORDER BY emp_id ASC 无对应字段,应改为 employee
LIMIT 10;⚠️ 注意:ORDER BY emp_id ASC 在原始 SQL 中引用了不存在的别名 emp_id,已修正为 employee;若需按员工编码排序,请确保子查询中 d.employee_code 可被外层引用,或改用 JOIN 提升可读性与性能。
步骤二:PHP 安全构建数据与标签数组
摒弃字符串拼接,改用关联数组 + json_encode():
<?php
$conn = mysqli_connect("localhost", "root", "", "database_name");
$sql = "SELECT ... "; // 上述优化后的 SQL
$most_link = mysqli_query($conn, $sql);
$data_arr = [];
$labels_arr = [];
while ($row = mysqli_fetch_assoc($most_link)) {
$data_arr[] = $row; // ['account'=>'A001','employee'=>'张三','total'=>24]
$labels_arr[] = $row['account']; // ['A001', 'A002', ...]
}
$data_json = json_encode($data_arr);
$labels_json = json_encode($labels_arr);
?>步骤三:前端 Morris 初始化(关键配置)
在 <script> 中正确注入 JSON 数据,并显式指定 labels:</script>
<div id="most"></div>
<script>
new Morris.Bar({
element: 'most',
data: <?php echo $data_json; ?>,
xkey: 'employee', // X 轴显示员工全名(柱状图横坐标)
ykeys: ['total'], // Y 轴绑定登录次数
labels: <?php echo $labels_json; ?>, // ✅ 动态悬停标签:显示 account 值
hideHover: 'auto',
barColors: ['#F5761A'],
// 可选:增强可读性
xLabelAngle: 45,
resize: true
});
</script>关键注意事项
- labels 必须是与 data 数组长度一致的字符串数组,顺序严格对应每条数据项;
- xkey(如 'employee')控制柱子横坐标文本,labels 控制悬停框顶部标题(即 tooltip header),二者可不同;
- 始终使用 mysqli_fetch_assoc()(非 fetch_array())避免索引混淆;
- 生产环境务必添加错误处理(如 mysqli_connect_error()、mysqli_error($conn));
- 若 account 含特殊字符(如单引号、换行符),json_encode() 自动转义,无需额外处理。
通过此方案,你将获得完全动态、安全可靠且符合 Morris.js 规范的悬停标签系统——既满足业务需求,又筑牢代码质量底线。










