十天学会php实战方法:提示词、素材与细节优化

SEO教程8小时前发布 jdkjadmin
0 00
十天学会php实战方法:提示词、素材与细节优化

十天学会php实战方法:提示词、素材与细节优化

十天足以完成一个小型 PHP 项目,并建立一套继续练习的方法;但不足以掌握 PHP 的全部语法、框架和生产运维。本文把目标定得务实一些:用十天做出一个可运行的任务清单 API,练习需求拆解、AI 提示词、素材准备、编码、测试和安全检查。学完后,你应能读懂基础 PHP 程序,独立改动小功能,并知道哪些部分不能未经验证就交给 AI 或直接上线。

一、先确定适用场景和边界

PHP 适合开发服务端网站、管理后台、内容系统、表单处理和 JSON API。它部署普遍,入门资料丰富;配合 PDO、SQLite 或 MySQL,可以较快做出数据读写功能。本文示例选择 PHP 8.2 及以上版本、PDO_SQLITE 扩展和 PHP 内置开发服务器。SQLite 适合本地练习、小型工具和低并发场景,不代表所有生产项目都该使用 SQLite。

如果项目需要复杂权限、多节点高并发、支付结算、个人敏感信息处理,或有明确的审计与可用性要求,十天练习项目不能直接充当生产方案。应评估数据库、身份认证、备份、监控、部署方式和安全测试,必要时采用成熟框架及专业审查。下面的 API 为了易读,没有用户认证、速率限制、跨域策略和 CSRF 防护,不应直接暴露在公网,也不适合接收真实用户数据。

二、十天学习路线

  1. 第 1 天:搭建环境。安装 PHP 8.2 或更新版本,确认命令行可用;了解 PHP 文件、变量、数组、条件和循环。运行 php -v 检查版本。
  2. 第 2 天:函数与错误。练习函数、类型声明、异常和数组处理。把需求中的重复逻辑写成函数,并学会阅读报错中的文件名与行号。
  3. 第 3 天:HTTP 基础。了解请求方法、路径、状态码、请求头和 JSON。区分浏览器页面与 API:前者通常返回 HTML,后者通常交换结构化数据。
  4. 第 4 天:数据库。认识表、主键、查询和参数绑定。使用 PDO 连接 SQLite,理解预处理语句为什么能降低 SQL 注入风险。
  5. 第 5 天:整理需求与素材。写出 API 的输入、输出和失败情况,准备几组测试数据,明确 PHP 版本、扩展和运行命令。
  6. 第 6 天:完成创建接口。实现 JSON 解码、标题校验、数据库插入和错误状态码。
  7. 第 7 天:完成列表接口。实现查询和 JSON 响应,区分合法空列表与服务器错误。
  8. 第 8 天:测试边界。测试缺字段、空标题、过长标题、无效 JSON、错误路径及数据库不可用等情形。
  9. 第 9 天:整理与安全检查。检查输出转义、异常信息、数据权限、日志与配置文件,不把密钥写进代码仓库。
  10. 第 10 天:复盘交付。补上运行说明、已知限制和下一步计划;在干净环境中重新运行,确认示例不依赖未说明的本地文件。

三、提示词写清楚,AI 才能帮上忙

AI 适合辅助拆需求、解释报错、生成测试用例和检查代码遗漏;它不是 PHP 解释器、数据库专家或安全审计的替代品。提示词要交代目标、环境、输入输出、禁止事项和验收条件。不要只说“帮我写一个安全的 PHP 项目”,因为“安全”没有具体验收标准。

你是 PHP 代码审查助手。请为 PHP 8.2 编写一个最小 JSON API:
- 功能:创建任务与列出任务,数据保存在 SQLite。
- 环境:PDO_SQLITE 已启用,不使用第三方框架。
- 输入:POST /api/tasks,JSON 对象含 title 字符串。
- 约束:title 去除首尾空白后不能为空,最多 200 个 UTF-8 字节。
- 输出:成功返回 JSON 和 201;输入错误返回 400;未知路由返回 404。
- 安全:使用 PDO 预处理语句;不把异常详情返回客户端。
- 请提供完整可运行代码、启动命令、curl 测试命令和已知限制。
- 不要声称示例包含认证、CSRF 防护或生产级部署能力。
生成后请逐项检查代码与运行条件是否一致。

把任务拆成小步,通常比一次生成整站更可靠。先让 AI 总结需求并列出不确定点,再要求生成一个文件或一个功能;运行后贴出完整错误信息和相关代码,让它提出可验证的修复方案。不要上传密码、访问令牌、客户资料或未公开的生产代码。即使代码看起来合理,也要在本地运行、读懂关键逻辑,并核对 PHP 版本和扩展要求。

四、素材准备:先准备可验证的信息

这里的“素材”不只是图片,而是实现功能所需的事实和样本。动手前准备以下内容,能减少反复猜测:

  • 环境信息:PHP 版本、操作系统、已启用扩展、启动方式及数据库类型。
  • 需求清单:每个路由做什么、接收哪些字段、成功和失败时返回什么。
  • 测试样本:正常标题、空字符串、超长字符串、缺字段和格式错误的 JSON。
  • 资料来源:优先参考 PHP 官方手册和所用数据库驱动文档;复制代码前检查版本、许可证和上下文。
  • 运行记录:保存命令、报错、预期结果和实际结果,方便复现,而不是仅凭“似乎能跑”判断。

素材也可能包含用户提供的文本、文件名或网页内容。它们都是不可信输入,不能因为来自内部表格或 AI 生成就跳过校验。图片上传、文件解析和富文本渲染涉及额外攻击面,本文没有实现这些功能;不要把下面的简单 API 改几行就当作安全上传服务。

五、动手:创建一个最小任务 API

新建空目录,创建 index.php,放入下面代码。它提供两个接口:GET /api/tasks 列出任务,POST /api/tasks 创建任务。首次请求时会建立 SQLite 数据库文件 tasks.sqlite。

<?php
declare(strict_types=1);

header('Content-Type: application/json; charset=utf-8');

function respond(int $status, array $data): void
{
    http_response_code($status);
    echo json_encode(
        $data,
        JSON_UNESCAPED_UNICODE | JSON_INVALID_UTF8_SUBSTITUTE
    );
    exit;
}

try {
    $pdo = new PDO('sqlite:' . __DIR__ . '/tasks.sqlite');
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $pdo->exec(
        'CREATE TABLE IF NOT EXISTS tasks (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            title TEXT NOT NULL,
            created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
        )'
    );

    $method = $_SERVER['REQUEST_METHOD'] ?? '';
    $path = parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH);

    if ($path !== '/api/tasks') {
        respond(404, ['error' => 'Not found']);
    }

    if ($method === 'GET') {
        $statement = $pdo->query(
            'SELECT id, title, created_at FROM tasks ORDER BY id DESC'
        );
        respond(200, ['tasks' => $statement->fetchAll(PDO::FETCH_ASSOC)]);
    }

    if ($method === 'POST') {
        $raw = file_get_contents('php://input');
        try {
            $input = json_decode($raw, true, 512, JSON_THROW_ON_ERROR);
        } catch (JsonException $e) {
            respond(400, ['error' => 'Invalid JSON']);
        }

        if (!is_array($input) || !isset($input['title']) ||
            !is_string($input['title'])) {
            respond(400, ['error' => 'title must be a string']);
        }

        $title = trim($input['title']);
        if ($title === '' || strlen($title) > 200) {
            respond(400, ['error' => 'title must be 1 to 200 bytes']);
        }

        $statement = $pdo->prepare(
            'INSERT INTO tasks (title) VALUES (:title)'
        );
        $statement->execute(['title' => $title]);

        respond(201, [
            'id' => (int) $pdo->lastInsertId(),
            'title' => $title
        ]);
    }

    header('Allow: GET, POST');
    respond(405, ['error' => 'Method not allowed']);
} catch (Throwable $e) {
    error_log((string) $e);
    respond(500, ['error' => 'Internal server error']);
}

标题限制是 1 到 200 个字节,不是 200 个汉字。PHP 的 strlen() 返回字节数;UTF-8 中文字符通常占多个字节,因此 200 字节容纳的汉字数量会更少。这里没有依赖 mbstring 扩展。若业务规则要求限制字符数,应明确“字符”的定义,并确认扩展与输入编码;可以使用 mb_strlen($title, 'UTF-8'),但前提是已安装并启用 mbstring。不要把字节限制误写成字符限制。

创建表的语句在请求时执行,借助 IF NOT EXISTS 避免重复建表。正式项目通常会使用迁移工具管理表结构。异常详情通过 error_log() 写入服务器日志,客户端只得到通用错误;日志也要控制访问权限,避免记录密码、令牌和不必要的个人信息。

六、启动与验证

先确认环境支持 PDO_SQLITE,再在项目目录运行开发服务器:

php -m
php -S 127.0.0.1:8000

在另一个终端创建任务:

curl -i -X POST http://127.0.0.1:8000/api/tasks \
  -H 'Content-Type: application/json' \
  -d '{"title":"检查 PHP 项目"}'

预期响应状态为 201,响应体中包含新任务的编号和标题。接着查看列表:

curl -i http://127.0.0.1:8000/api/tasks

还可以验证失败情况:

curl -i -X POST http://127.0.0.1:8000/api/tasks \
  -H 'Content-Type: application/json' \
  -d '{"title":"   "}'

curl -i -X POST http://127.0.0.1:8000/api/tasks \
  -H 'Content-Type: application/json' \
  -d '{"title":'

curl -i http://127.0.0.1:8000/not-found

第一条应得到 400,因为标题去掉首尾空白后为空;第二条应得到 400,因为 JSON 格式无效;第三条应得到 404。PHP 内置服务器用于开发和测试,不是面向公网的生产 Web 服务器。SQLite 数据库文件会留在项目目录,练习结束后可删除;生产环境要单独设计数据持久化、备份和权限。

七、安全细节:看清示例做了什么、没做什么

SQL 参数绑定不等于输入验证

示例用 PDO 预处理语句写入标题,避免把用户输入直接拼进 SQL,从而降低 SQL 注入风险。但参数绑定不会自动检查字段是否为空、长度是否符合业务规则,也不能替代权限控制。列名、排序方向等 SQL 结构通常不能像值一样直接绑定,需要使用固定白名单。

JSON 输出不等于 HTML 转义

API 使用 json_encode() 返回 JSON。调用方若把标题插入网页,仍要按 HTML 上下文转义,不能将用户文本直接拼进 HTML。传统 PHP 页面输出文本时,可使用:

<?php
function escapeHtml(string $value): string
{
    return htmlspecialchars(
        $value,
        ENT_QUOTES | ENT_SUBSTITUTE,
        'UTF-8'
    );
}

echo escapeHtml($title);

转义应发生在输出位置,并按输出上下文选择方式;HTML 属性、JavaScript、CSS 和 URL 的安全处理规则并不完全相同。不要把 HTML 转义当作 SQL 防注入方案,也不要对所有输入盲目重复转义后再存入数据库。

接口没有身份认证和访问控制

当前任何能访问服务的人都可以读取任务并创建任务。示例不验证用户身份,也不隔离不同用户的数据。加入登录后,还需在每次读写时检查当前用户是否有权操作对应记录;仅隐藏页面按钮不构成权限保护。若用浏览器 Cookie 携带身份状态,还要评估 CSRF 防护、Cookie 属性和会话管理。使用令牌的 API 也必须安全保存令牌、验证权限并防止泄露。

异常处理要兼顾排错和信息泄露

开发期间可查看本地错误日志;生产响应不应向陌生客户端泄露文件路径、SQL、堆栈和配置内容。部署时应关闭面向用户的详细错误显示,设置可访问受控的日志与告警。不要为了“方便调试”把 $e->getMessage() 原样返回给客户端。

八、常见错误及排查办法

  • 命令找不到或版本不符:确认安装的是命令行 PHP,检查 php -v,不要只看编辑器插件显示的版本。
  • 提示找不到 SQLite 驱动:查看 php -m 是否包含 PDO 和 pdo_sqlite,并确认 CLI 使用的配置文件与 Web 环境一致。
  • 请求总是 404:核对请求路径是否为 /api/tasks。本例严格匹配路径,末尾多一个斜杠也不相同。
  • 中文长度和预期不同:strlen() 按字节计算;先确认需求限制的是字节还是字符,再选对应函数和扩展。
  • 把字符串拼进 SQL:改用 PDO 预处理语句。对用户输入做长度校验不能取代参数绑定。
  • 发现空标题仍被接受:检查是否对输入调用了 trim(),以及校验是否发生在写入数据库之前。
  • 代码生成后无法运行:先核对 PHP 版本、扩展、文件名和启动目录,再逐条执行测试请求。要求 AI 给出可复现步骤,不要只让它“再写一遍”。
  • 把开发服务器部署到公网:停止这样做。内置服务器面向开发测试,生产部署应使用适合的 Web 服务器、PHP 运行环境与安全配置。

九、如何持续优化项目

每增加一个功能,都补齐四类信息:正常输入、边界输入、失败响应和授权要求。比如增加删除任务时,先确定用什么 HTTP 方法、找不到记录返回什么状态、谁有权删除、是否需要保留审计记录,再动代码。不要只追求文件更短;拆函数、配置管理和测试应该服务于可读性与可验证性。

完成练习后,可按次序扩展:增加按编号查询和更新接口;为数据库读写编写测试;把数据库路径移出源码并从环境配置读取;再考虑用户认证、权限、请求频率限制和结构化日志。每一步都应同步更新运行说明和边界声明。涉及文件上传、密码重置、支付或敏感信息时,先查阅当前 PHP 与依赖库的官方文档,并进行专门威胁建模和测试,不要仅凭模型生成的代码判断安全。

十天实战的价值不在于背完语法,而在于形成闭环:把需求写清楚,准备真实可验证的素材,让工具辅助生成小块代码,亲自运行并测试边界,再记录系统的能力与限制。只要每一步都能复现,项目就不只是“看上去能用”,而是能继续维护和改进的起点。

© 版权声明

相关文章