PHP CLI增删改查需手动初始化PDO连接、解析$argv参数、强制使用预处理语句防注入、区分STDERR/STDOUT输出并规范exit码。

PHP 在 CLI 模式下做增删改查,核心不是换写法,而是换环境适配——你要手动加载数据库连接、处理命令行参数、避免 Web 环境的自动行为(比如 $_GET、$_POST、自动输出头信息),同时注意 CLI 的错误报告和退出码。
怎么建立 CLI 可用的数据库连接
Web 环境里常把连接逻辑藏在框架或配置文件中,CLI 下得显式初始化。PDO 是最稳妥的选择,它不依赖扩展模块(如 mysql_connect 已废弃),且支持异常模式便于调试。
关键点:
- 必须设置
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,否则 SQL 错误静默失败 - CLI 下没有
php.ini的display_errors=On保障,要手动开ini_set('display_errors', '1') - 密码等敏感信息不要硬编码,建议用
getenv()或读取.env文件(可用vlucas/phpdotenv)
#!/usr/bin/env php
PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);
} catch (PDOException $e) {
fwrite(STDERR, "数据库连接失败: " . $e->getMessage() . "\n");
exit(1);
}
怎么解析命令行参数执行不同操作
PHP CLI 脚本通过 $argv 接收参数,但直接手撕容易出错(比如空值、顺序错乱)。推荐用轻量方案:symfony/console(功能全)、或干脆用 array_slice($argv, 1) + 简单 switch(适合小工具)。
立即学习“PHP免费学习笔记(深入)”;
常见结构:
php script.php insert --name="张三" --email="z@x.com"php script.php select --id=5php script.php delete --id=3
注意:CLI 下没有表单验证,所有输入都不可信,--id 必须强制转为整型,--name 要用 htmlspecialchars() 或直接走预处理语句(更安全)。
为什么增删改查必须用预处理语句
CLI 脚本常被用来批量处理数据,一旦拼接 SQL 字符串(如 "INSERT INTO user VALUES ('$name')"),遇到含单引号的用户名(如 O'Connor)就直接报错,甚至引发 SQL 注入——而 CLI 环境没人盯着日志,问题会潜伏很久。
正确做法只有一条:所有用户输入进 SQL 的地方,一律走 $pdo->prepare() + $stmt->execute()。
// ✅ 安全写法
$stmt = $pdo->prepare("INSERT INTO users (name, email) VALUES (?, ?)");
$stmt->execute([$name, $email]);
// ❌ 危险写法(哪怕只是测试也别这么干)
$sql = "INSERT INTO users (name, email) VALUES ('$name', '$email')";
$pdo->exec($sql);
怎么让脚本支持退出码和标准输出流
CLI 工具要能被其他程序调用(比如 shell 脚本、CI 流程),就必须按 POSIX 规范返回退出码:exit(0) 表示成功,exit(1) 表示一般错误,exit(2) 表示用法错误。同时,错误信息必须输出到 STDERR,正常结果输出到 STDOUT,否则管道(|)和重定向(> file.txt)会混乱。
示例:
- 查不到记录时,
echo json_encode($row) . "\n";→ 输出到STDOUT - 连接失败时,
fwrite(STDERR, "连接超时\n"); exit(1); - 参数缺失时,
fwrite(STDERR, "用法: php script.php select --id=123\n"); exit(2);
真正麻烦的从来不是写几行 SQL,而是让每个 exit 都有意义、每条 echo 都去对地方、每次 prepare 都覆盖边界输入——这些细节在 Web 里被框架兜底了,CLI 下得自己扛。











