文档教程【免费下载链接】php-the-right-wayAn easy-to-read, quick reference for PHP best practices, accepted coding standards, and links to authoritative tutorials around the Web项目地址https://gitcode.com/gh_mirrors/ph/php-the-right-way点击查看免费下载php-the-right-way 项目本仓库是一份面向 PHP 开发者的最佳实践速查手册每个章节与子章节都以_posts/目录下的 Markdown 文件组织。本文以其中 MySQL 扩展Databases_MySQL 一节为核心骨架完整梳理旧版mysql扩展被淘汰的来龙去脉、代码中残留mysql_*调用的排查方法以及如何平滑迁移到mysqli或PDO并规避常见的一键替换陷阱。读完本文你将掌握一套可落地的 MySQL 数据库接入迁移方案并学会用参数绑定从根源上防御 SQL 注入。为什么mysql扩展必须被淘汰在 PHP 的历史演进中mysqlmysql_*系列函数曾是与 MySQL 交互的主流扩展但它已经是高龄组件。本仓库 Databases_MySQL.md 明确指出mysql扩展极其古老早已被另外两个扩展取代mysqli与PDO该扩展的开发在很久以前就已停止它已于 PHP 7.0 正式移除见 PHP 手册 Removed Extensions and SAPIs 迁移说明。换句话说任何运行在 PHP 7.0 及以上版本的环境都已经无法再调用mysql_connect()这类函数——一旦调用脚本会直接报致命错误。即便你的应用当前仍停留在 PHP 5.x也绝不能心存侥幸拖延升级只会让后续 PHP 版本升级变得更加痛苦。如何快速定位代码中残留的mysql_*调用迁移的第一步是全面盘点。与其逐个翻阅php.ini猜测当前加载了哪个模块不如直接在代码库里做一次文本检索。在任意编辑器或命令行工具中搜索mysql_*模式即可grep -rn mysql_\|mysql_query\|mysql_connect --include*.php .只要搜索结果显示出了mysql_connect()、mysql_query()、mysql_fetch_array()等函数名就说明该项目仍然在使用mysql扩展。这类函数通常包括但不限于mysql_connect()/mysql_pconnect()mysql_select_db()mysql_query()/mysql_unbuffered_query()mysql_fetch_assoc()/mysql_fetch_array()/mysql_fetch_row()mysql_num_rows()/mysql_insert_id()mysql_real_escape_string()mysql_error()/mysql_errno()mysql_close()检测的同时还应确认运行环境本身是否已加载旧扩展在 PHP 5.x 的php.ini中检查是否存在extensionphp_mysql.dllWindows或extensionmysql.soLinux/macOS之类的配置项并将其一并移除。迁移目标选择mysqli还是PDO原文档给出的建议很明确用mysqli或PDO替换mysql的用法并尽量安排在自有的开发排期内完成避免日后被版本升级逼着仓促改造。两个替代方案各有适用场景可按下表权衡维度mysqliPDO定位MySQL 专用扩展提供面向过程与面向对象两套 API数据库连接抽象层内置自 PHP 5.1.0支持数据库仅 MySQLMySQL、PostgreSQL、SQLite、MSSQL、Oracle 等连接方式原生驱动直接绑定 MySQL 协议通过统一的 DSN 连接字符串适配不同数据库参数绑定支持mysqli_stmt::bind_param支持PDOStatement::bindParam/bindValue多库切换换库需重学新 API同一套代码可对接多种数据库在项目总览章节 Databases.md 中还阐述了另一个关键视角原生驱动mysqli、pgsql、mssql等在应用只使用单一数据库时非常合适但如果应用同时对接 MySQL 与 MSSQL或需要连接 Oracle就必须为每种数据库学习一套全新 API而PDO用几乎相同的代码即可对接多种数据库。以下是mysqli面向对象风格与PDO的等价连接示例?php // mysqli 面向对象风格仅 MySQL $mysqli new mysqli(example.com, user, password, database); $result $mysqli-query(SELECT some_field FROM some_table); $row $result-fetch_assoc(); echo htmlentities($row[some_field]); // PDO MySQL $pdo new PDO(mysql:hostexample.com;dbnamedatabase, user, password); $statement $pdo-query(SELECT some_field FROM some_table); $row $statement-fetch(PDO::FETCH_ASSOC); echo htmlentities($row[some_field]); // PDO SQLite —— 几乎相同的代码仅 DSN 不同 $pdo new PDO(sqlite:/path/db/foo.sqlite); $statement $pdo-query(SELECT some_field FROM some_table); $row $statement-fetch(PDO::FETCH_ASSOC); echo htmlentities($row[some_field]);需要说明的是PDO不会翻译你的 SQL也不会模拟某个数据库缺失的特性它纯粹提供统一的连接 API真正意义上的数据库抽象如跨库特性模拟属于 ORM / 抽象层框架的范畴详见仓库中的 Abstraction Layers抽象层 一节。警惕一键替换式的偷懒迁移指南在 Databases_MySQL.md 中有一条醒目的警告如果打算从mysql升级到mysqli请警惕那些声称只需把mysql_*全局替换成mysqli_*的偷懒教程。这不仅是一种严重的过度简化还会错过mysqli带来的关键优势——例如参数绑定parameter binding而这一能力PDO同样提供。直接机械替换存在多重风险函数签名并不一一对应。mysql_connect($host, $user, $pass)与mysqli_connect($host, $user, $pass, $dbname)的形参顺序与含义不同mysql_query($query)与mysqli_query($link, $query)的调用约定也不同mysqli面向过程风格需要显式传入连接对象。返回类型与错误处理语义变化。mysqli引入了更严格的返回值约定新旧代码混用极易引入隐性 bug。错失安全红利。mysql时代普遍依赖mysql_real_escape_string()手工转义而mysqli与PDO都支持预处理语句与参数绑定能从机制上隔离 SQL 注入这是单纯改名完全无法获得的收益。用预处理与参数绑定根治 SQL 注入迁移的真正价值在于安全架构升级。本仓库 Databases_PDO.md 用一个经典反例说明了不做绑定的后果。错误示范直接把外部输入拼进 SQL 字符串?php $pdo new PDO(sqlite:/path/db/users.db); $pdo-query(SELECT name FROM users WHERE id . $_GET[id]); // -- NO!攻击者只需构造一个 URL 如http://domain.com/?id1%3BDELETEFROMusers$_GET[id]就会变成1;DELETE FROM users从而清空整张 users 表。这正是 SQL 注入攻击的典型手法。正确示范使用 PDO 预处理语句与绑定参数?php $pdo new PDO(sqlite:/path/db/users.db); $stmt $pdo-prepare(SELECT name FROM users WHERE id :id); $id filter_input(INPUT_GET, id, FILTER_SANITIZE_NUMBER_INT); // 先过滤外部数据详见下方数据过滤 $stmt-bindParam(:id, $id, PDO::PARAM_INT); // PDO 会自动针对 SQL 进行转义 $stmt-execute();这段代码先将外部 ID 过滤为整数再通过命名占位符:id绑定参数由PDO完成转义后才交给数据库从根本上杜绝注入。这里有一个易被忽视的边界PDO 只负责对 SQL 的转义并不负责对应用的净化。对于INSERT、UPDATE等写操作仍然必须先用过滤函数清洗数据例如去除 HTML 标签、脚本等防止 XSS 等应用层攻击。这一点在仓库 Data Filtering数据过滤 一节中有完整展开外部输入绝不可信filter_var()与filter_input()可用于净化文本与校验格式输出到 HTML 前还应使用htmlentities()/htmlspecialchars()转义。迁移中的工程化要点连接管理与分层设计正确释放数据库连接数据库连接会占用资源。使用PDO时可通过销毁对象隐式关闭连接——删除对该对象的所有引用例如置为NULL?php $pdo new PDO(mysql:hostexample.com;dbnamedatabase, user, password); // ... 使用 $pdo ... $pdo null; // 隐式关闭连接如果你不显式处理PHP 也会在脚本结束时自动关闭连接——除非你使用了持久连接persistent connections。持久连接的生命周期与进程绑定需要结合具体部署环境谨慎评估。分离数据库交互与表现层逻辑新手常把数据库查询与 HTML 输出混写在同一个foreach里例如ul ?php foreach ($db-query(SELECT * FROM table) as $row) { echo li.$row[field1]. - .$row[field1]./li; } ? /ulInteracting with Databases与数据库交互 一节指出这种写法难以调试、难以测试、难以阅读还会在无LIMIT时输出海量字段。该文档给出的最小分层方案是把查询封装成函数进而提升为类即Model把表现逻辑放进独立的.php视图文件即View形成接近 MVC 的结构foo.php控制器脚本?php $db new PDO(mysql:hostlocalhost;dbnametestdb;charsetutf8mb4, username, password); // 引入模型 include models/FooModel.php; // 创建实例并获取数据 $fooModel new FooModel($db); $fooList $fooModel-getAllFoos(); // 渲染视图 include views/foo-list.php;models/FooModel.php模型?php class FooModel { public function __construct(protected PDO $db) { } public function getAllFoos() { return $this-db-query(SELECT * FROM table); } }views/foo-list.php视图?php foreach ($fooList as $row): ? li? $row[field1] ? - ? $row[field1] ?/li ?php endforeach ?这与主流现代框架的做法本质相同只是更手动化。迁移到PDO/mysqli的同时顺势做一次分层重构会让后续的单元测试仓库 Testing 章节有专门讲解变得可行。迁移时一并落实 utf8mb4 字符集在 PHP and UTF-8 一节中强调即便 PHP 侧全部遵循了 UTF-8 处理规范数据库侧仍可能把字符串按非 UTF-8 存储。正确做法是数据库与所有表都设置为utf8mb4字符集与排序规则注意必须用utf8mb4而非utf8才能获得完整 Unicode 支持PDO 连接字符串中显式声明charsetutf8mb4。?php $link new PDO( mysql:hostyour-hostname;dbnameyour-db;charsetutf8mb4, your-username, your-password, array( PDO::ATTR_ERRMODE PDO::ERRMODE_EXCEPTION, PDO::ATTR_PERSISTENT false ) );在从mysql_*迁移时这是一个顺手但至关重要的配置点尤其对多语言、emoji 等场景影响巨大。制定自己的迁移排期原文档给出的行动建议总结如下尽早排查通过全局搜索mysql_*确认受影响范围并核验运行环境php.ini是否仍加载旧扩展尽早规划即使当前还不用 PHP 7.x也应在自己的开发排期内完成替换避免 PHP 大版本升级到来时手忙脚乱选择目标 API仅使用 MySQL 可选mysqli需要多数据库兼容或更统一的抽象选PDO拒绝机械替换逐函数重构同步引入预处理语句与参数绑定、utf8mb4字符集、连接释放与分层设计等最佳实践先过滤后绑定对INSERT/UPDATE等写操作先做应用层数据过滤再用PDO/mysqli参数绑定完成 SQL 安全转义。延伸阅读本仓库相关章节以下仓库内章节与本文主题直接相关可继续深入Databases数据库总览原生驱动与抽象层的取舍背景Databases_PDOPDO 扩展PDO连接抽象、参数绑定与连接生命周期Interacting-via-Code与数据库交互Model/View 分层示例Abstraction-Layers抽象层基于 PDO 的 ORM/DBAL 生态Data-Filtering数据过滤外部输入的净化与校验PHP-and-UTF8UTF-8 处理utf8mb4连接配置详解官方层面的进一步参考包括PHP 手册的 Choosing an API for MySQL帮助在mysqli与PDO之间决策以及mysqli预处理语句相关文档——结合上表与本文示例即可完成从技术选型到落地改造的完整闭环。赞分享文档教程【免费下载链接】php-the-right-wayAn easy-to-read, quick reference for PHP best practices, accepted coding standards, and links to authoritative tutorials around the Web项目地址https://gitcode.com/gh_mirrors/ph/php-the-right-way点击查看免费下载相关推荐Gas Town Phase 4 最小修复批次验收指南e2e 容器测试与角色路径回归验证Gas Town Phase 4 最小修复批次验收指南e2e 容器测试与角色路径回归验证 本文是 Gas Townmulti agent workspace文档教程QMK 固件调试 FAQ 实战指南从调试开关到矩阵扫描性能分析QMK 固件调试 FAQ 实战指南从调试开关到矩阵扫描性能分析 本文围绕 QMK Firmware 官方调试 FAQ 展开系统讲解如何开启键盘调试输出、使用文档教程CVAT Python SDK 使用指南分层架构、安装配置与标注工作流自动化CVAT Python SDK 使用指南分层架构、安装配置与标注工作流自动化 导读 本文围绕 CVAT 官方 Python SDK cvat sdk 展文档教程上一篇gh_mirrors/ca/cash文件系统操作cp、mv、rm命令的ES6实现下一篇告别GPU依赖Gemma-4-12B-Coder本地部署完整指南环境配置代码示例常见问题创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考