PHP+MySQL跨两库校验Artist+Title匹配获取文件路径结果异常问题
问题原因
- 未限制Database2的匹配返回条数:如果Database2中同一个
Artist+Title+active=1存在多条匹配记录(比如同一首歌对应多个文件路径、重复入库的冗余记录),你的while循环会把所有匹配的路径全部输出,导致结果变多。按照你的需求,单条Database1记录只要找到匹配项输出1条即可,不需要遍历所有匹配结果。 - Database1存在重复的
Artist+Title记录:如果Database1里完全相同的Artist+Title组合出现多次,每次都会触发一次查询并输出对应路径,如果你预期是去重后的结果,就会出现实际数量超出预期的情况。 - 字符串匹配规则问题:如果你的数据库字符集排序规则是大小写不敏感、或者忽略末尾空格的,会出现你认为不匹配的记录被判断为匹配的情况,也会导致结果增多。
- 额外风险:你直接拼接
$artist和$title到SQL语句中,存在严重的SQL注入漏洞,一旦字段内容包含单引号会导致SQL语法错误,甚至被恶意注入拖库。
修复方案
方案1:修复原有逻辑的问题
改为用预处理语句避免注入,同时限制单条查询最多返回1条结果:
<?php include("config.php"); // 开启PDO错误模式方便排查问题 $con->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // 可选:如果需要对Database1的结果去重,把下面SQL的SELECT改为SELECT DISTINCT artist, title $query = $con->query("SELECT * FROM database1 WHERE scheduled = 0 ORDER BY added ASC"); // 提前预处理查询语句,避免循环内重复编译,同时防止SQL注入 $stmt2 = $con->prepare("SELECT path FROM database2 WHERE artist = ? AND title = ? AND active = 1 LIMIT 1"); foreach($query as $row) { $artist = $row['artist']; $title = $row['title']; // 执行预处理查询 $stmt2->execute([$artist, $title]); $data2 = $stmt2->fetch(PDO::FETCH_ASSOC); if ($data2) { echo $data2['path']; } } ?>
如果需要精确匹配字符串,可以把查询条件改为:
SELECT path FROM database2 WHERE TRIM(LOWER(artist)) = TRIM(LOWER(?)) AND TRIM(LOWER(title)) = TRIM(LOWER(?)) AND active = 1 LIMIT 1
方案2:更高性能的连表查询(推荐)
不需要在循环里反复查询数据库,直接用JOIN一次性查出所有匹配结果:
<?php include("config.php"); $con->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // 连表查询直接获取所有符合条件的路径 // 可选:如果需要去重,在SELECT后面加DISTINCT $sql = "SELECT d2.path FROM database1 d1 INNER JOIN database2 d2 ON d1.artist = d2.artist AND d1.title = d2.title WHERE d1.scheduled = 0 AND d2.active = 1 ORDER BY d1.added ASC"; $stmt = $con->query($sql); while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { echo $row['path']; } ?>
内容的提问来源于stack exchange,提问作者user3130478
相关产品推荐
相关产品推荐

