如何将调用存储过程的MySQLi PHP代码迁移至PDO?
把MySQLi存储过程调用迁移到PDO的完整方案
我来帮你把这些MySQLi调用存储过程的代码改成PDO版本,同时彻底摆脱手动转义的麻烦——PDO的预处理语句能完美替代mysqli_escape_string,更安全也更简洁。
第一步:重构数据库连接文件(conn.php)
原代码每次include都新建连接,PDO推荐复用连接,同时要设置正确的错误模式和字符集,避免乱码和调试困难:
<?php // conn.php $dsn = 'mysql:host=localhost;dbname=你的数据库名;charset=utf8mb4'; $username = '你的数据库用户名'; $password = '你的数据库密码'; try { $pdo = new PDO($dsn, $username, $password); // 设置错误模式为抛出异常,方便调试和捕获错误 $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // 默认返回关联数组,和mysqli_fetch_array(MYSQLI_ASSOC)行为一致 $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); } catch(PDOException $e) { die("数据库连接失败: " . $e->getMessage()); } ?>
第二步:重构function.php的存储过程调用函数
PDO用预处理语句替代手动转义,自动处理参数的安全问题。下面是改造后的每个函数:
<?php // function.php require_once("conn.php"); // 用require_once避免重复加载连接 function AddWords($word, $meaning, $synonym, $antonym) { global $pdo; // 用占位符替代手动拼接SQL,避免注入 $stmt = $pdo->prepare("CALL AddWords(:word, :meaning, :synonym, :antonym)"); // 直接传参数数组,PDO自动转义 $stmt->execute([ ':word' => $word, ':meaning' => $meaning, ':synonym' => $synonym, ':antonym' => $antonym ]); // 返回是否执行成功(影响行数大于0表示成功) return $stmt->rowCount() > 0; } function GetWords($word) { global $pdo; $stmt = $pdo->prepare("CALL GetWords(:word)"); $stmt->execute([':word' => $word]); // 返回所有查询结果(关联数组格式) return $stmt->fetchAll(); } function GetAdminWords() { global $pdo; // 无参数的存储过程可以直接用query $stmt = $pdo->query("CALL GetAdminWords()"); return $stmt->fetchAll(); } function GetWordsByID($id) { global $pdo; $stmt = $pdo->prepare("CALL GetWordsById(:id)"); $stmt->execute([':id' => $id]); // 返回单条记录 return $stmt->fetch(); } function DeleteWords($id) { global $pdo; $stmt = $pdo->prepare("CALL DeleteWords(:id)"); $stmt->execute([':id' => $id]); return $stmt->rowCount() > 0; } function UpdateWords($word, $meaning, $synonym, $antonym, $id) { global $pdo; $stmt = $pdo->prepare("CALL UpdateWords(:word, :meaning, :synonym, :antonym, :id)"); $stmt->execute([ ':word' => $word, ':meaning' => $meaning, ':synonym' => $synonym, ':antonym' => $antonym, ':id' => $id ]); return $stmt->rowCount() > 0; } function SortContent() { global $pdo; $stmt = $pdo->query("CALL SortContent()"); return $stmt->fetchAll(); } function SortContent2() { global $pdo; $stmt = $pdo->query("CALL SortContent2()"); return $stmt->fetchAll(); } ?>
第三步:改造主调用文件的逻辑
去掉所有mysqli_escape_string调用,直接传递原始参数给PDO函数即可,同时调整结果处理的代码:
<?php require_once("conn.php"); require_once("function.php"); // 处理表单提交 if(isset($_POST['btn_submit'])){ $word = $_POST['word']; $meaning = $_POST['meaning']; $antonym = $_POST['antonym']; $synonym = $_POST['synonym']; if(!isset($_GET['id1'])){ // 直接传参数,PDO自动处理转义 $success = AddWords($word, $meaning, $synonym, $antonym); if($success){ echo "<script type='text/javascript'>alert('Saved Successfully!!')</script>"; echo "<script type='text/javascript'>window.location='view.php'</script>"; } else { echo "<script type='text/javascript'>alert('Save failed!')</script>"; } } else { $id = $_GET['id1']; $success = UpdateWords($word, $meaning, $synonym, $antonym, $id); if($success){ echo "<script type='text/javascript'>alert('Saved Successfully!!')</script>"; echo "<script type='text/javascript'>window.location='view.php'</script>"; } else { echo "<script type='text/javascript'>alert('Update failed!')</script>"; } } } ?> <?php $word = $meaning = $synonym = $antonym = ''; if(isset($_GET['id1'])){ $id = $_GET['id1']; // 获取单条记录,直接用PDO返回的关联数组 $row = GetWordsByID($id); if($row){ $word = $row['word']; $meaning = $row['meaning']; $synonym = $row['synonym']; $antonym = $row['antonym']; } } ?> <form method="post"> <div class="container container-fluid"> <div class="form-group"> <div class="col-xs-4"> <label for="inputdefault">Add Word</label> <input class="form-control" id="inputdefault" type="text" name="word" value="<?php echo htmlspecialchars($word); ?>"> <label for="inputdefault">Add Meaning</label> <input class="form-control" id="inputdefault" type="text" name="meaning" value="<?php echo htmlspecialchars($meaning); ?>"> <label for="inputdefault">Add Synonym</label> <input class="form-control" id="inputdefault" type="text" name="synonym" value="<?php echo htmlspecialchars($synonym); ?>"> <label for="inputdefault">Add Antonym</label> <input class="form-control" id="inputdefault" type="text" name="antonym" value="<?php echo htmlspecialchars($antonym); ?>"><br> <button type="submit" class="btn btn-primary" name="btn_submit" >Submit</button> </div> </div> </div> </form>
关键说明
- 替代
mysqli_escape_string:PDO的预处理语句会自动对参数进行转义,完全不需要手动调用转义函数,从根源上避免SQL注入。 - 结果处理:PDO默认设置为关联数组,和原MySQLi的行为一致,迁移成本很低。
- 错误处理:设置
PDO::ERRMODE_EXCEPTION后,数据库错误会抛出异常,生产环境建议添加try-catch块来捕获和处理异常。 - 连接复用:用
require_once加载连接文件,避免重复创建数据库连接,提升性能。
内容的提问来源于stack exchange,提问作者Raju Ghosh
相关产品推荐
相关产品推荐

