PHP ISBN生成器仅能单次写入数据库,重复存储失败求助
问题原因分析及解决方案
核心原因
SQL注入引发的语法错误
你的generate-isbn.php直接将用户输入的title和author拼接到INSERT语句中,如果输入内容包含单引号(如O'Neil),会破坏SQL语句结构,导致语法错误,插入失败。删除数据库记录后第一次输入的内容可能无特殊字符,所以能成功存储,后续输入带特殊字符的内容就会触发失败。ISBN字段唯一约束+竞态条件
如果books表的isbn字段被设置了唯一约束,当多请求同时生成ISBN时会出现竞态问题:A请求检查ISBN不存在,B请求同时检查同一ISBN也不存在,A插入成功后,B插入就会因唯一约束冲突失败。即使单用户重复操作,若生成逻辑存在极小概率重复,也会触发该问题。缺乏错误反馈机制
代码未对数据库操作结果做校验,插入失败时无法返回错误信息,导致你无法直观得知存储失败的具体原因。
修复步骤
1. 用预处理语句防止SQL注入
修改generate-isbn.php的插入逻辑,使用mysqli预处理语句避免语法错误:
<?php require "isbn.php"; header("Content-Type: application/json"); $title = $_POST["title"]; $author = $_POST["author"]; $isbn = generate_unique_isbn(); $conn = new mysqli("localhost", "root", "", "isbn"); // 预处理语句 $stmt = $conn->prepare("INSERT INTO books (isbn, title, author) VALUES (?, ?, ?)"); $stmt->bind_param("sss", $isbn, $title, $author); $stmt->execute(); // 检查插入结果 if ($stmt->affected_rows === 0) { echo json_encode(["error" => "存储失败:" . $conn->error, "isbn" => $isbn]); } else { echo json_encode(["isbn" => $isbn]); } $stmt->close(); $conn->close(); ?>
2. 修复ISBN校验位计算逻辑
原代码计算校验位时未跳过连字符,导致校验位计算错误,修改isbn.php的校验位计算部分:
function generate_unique_isbn() { do { $isbn = rand(100, 999) . "-"; $isbn .= rand(0, 9) . "-"; $isbn .= bin2hex(random_bytes(4)) . "-"; // 跳过连字符计算校验位 $check_digit = 0; $position = 0; for ($i = 0; $i < strlen($isbn); $i++) { $char = $isbn[$i]; if ($char === '-') continue; $check_digit += $position % 2 === 0 ? (int)$char : 3 * (int)$char; $position++; } $check_digit = 10 - ($check_digit % 10); $check_digit = $check_digit === 10 ? 0 : $check_digit; $isbn .= $check_digit; $conn = new mysqli("localhost", "root", "", "isbn"); $result = $conn->query("SELECT * FROM books WHERE isbn = '$isbn'"); $conn->close(); } while ($result && $result->num_rows > 0); return $isbn; }
3. 添加强制错误检查
在数据库操作关键步骤添加错误判断,比如generate_unique_isbn中:
$conn = new mysqli("localhost", "root", "", "isbn"); if ($conn->connect_error) { die("数据库连接失败:" . $conn->connect_error); } $result = $conn->query("SELECT * FROM books WHERE isbn = '$isbn'"); if (!$result) { die("ISBN重复检查失败:" . $conn->error); }
内容的提问来源于stack exchange,提问作者Gutsy Creatives
相关产品推荐
相关产品推荐

