第 6 课:PHP 与 Web 交互

一、学习目标

  1. 理解 HTTP 协议基础与 PHP 的 Web 交互原理
  2. 掌握表单数据的 GET/POST 提交与处理方法
  3. 熟练运用 PHP7 异常处理机制处理 Web 请求错误
  4. 学会数据过滤与安全验证,防范常见 Web 攻击

二、核心知识点

(一)HTTP 协议与 PHP 交互基础
  1. HTTP 请求与响应流程

    • 请求:客户端(浏览器)向服务器发送请求(如访问网页、提交表单)
    • 响应:服务器处理请求后,向客户端返回结果(如 HTML 页面、JSON 数据)
    • PHP 的角色:在服务器端处理请求数据,生成动态响应内容

    流程示意图:

    plaintext

    客户端 → 发送HTTP请求(如GET /index.php) → 服务器 → PHP解析请求并处理 → 生成响应内容 → 客户端接收并显示
    
  2. HTTP 请求方法(PHP 通过$_SERVER['REQUEST_METHOD']获取)

    • GET:从服务器获取资源(如访问网页、搜索),参数附加在 URL 后(可见,有长度限制)
    • POST:向服务器提交资源(如表单提交、上传文件),参数在请求体中(不可见,无长度限制)
    • 其他方法:PUT(更新资源)、DELETE(删除资源)(RESTful API 常用)

    示例(URL 中的 GET 参数):

    <?php
    // 访问URL:http://localhost/user.php?id=1&name=张三
    echo "请求方法:" . $_SERVER['REQUEST_METHOD'] . "<br>"; // 输出:GET
    echo "用户ID:" . $_GET['id'] . "<br>"; // 输出:1
    echo "用户名:" . $_GET['name'] . "<br>"; // 输出:张三
    ?>
  3. PHP 超全局变量(Web 交互核心)

    • $_GET:存储 GET 请求的参数(数组)
    • $_POST:存储 POST 请求的参数(数组)
    • $_REQUEST:合并$_GET$_POST$_COOKIE(不推荐,优先级不固定)
    • $_SERVER:存储服务器和请求相关信息(如REQUEST_METHODPHP_SELF
    • $_FILES:存储上传文件的信息(后续文件上传章节讲解)

    示例($_SERVER常用字段):

    <?php
    echo "当前脚本路径:" . $_SERVER['PHP_SELF'] . "<br>"; // 输出:/index.php
    echo "请求方法:" . $_SERVER['REQUEST_METHOD'] . "<br>"; // 输出:GET或POST
    echo "客户端IP:" . $_SERVER['REMOTE_ADDR'] . "<br>"; // 输出:客户端IP地址
    echo "服务器IP:" . $_SERVER['SERVER_ADDR'] . "<br>"; // 输出:服务器IP地址
    ?>
    
(二)表单处理实战
  1. HTML 表单创建

    • 表单必须包含action(提交目标 URL)和method(请求方法)
    • 表单元素需设置name属性(PHP 通过name获取值)
    • 常用表单元素:input(文本、密码、单选、复选等)、select(下拉框)、textarea(文本域)

    示例(用户注册表单):

    html

    预览

    <!-- register.html -->
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <title>用户注册</title>
    </head>
    <body>
        <h1>用户注册</h1>
        <!-- 表单提交到register.php,使用POST方法 -->
        <form action="register.php" method="post">
            <div>
                <label>用户名:</label>
                <input type="text" name="username" required> <!-- required表示必填 -->
            </div>
            <div>
                <label>密码:</label>
                <input type="password" name="password" required>
            </div>
            <div>
                <label>确认密码:</label>
                <input type="password" name="confirm_password" required>
            </div>
            <div>
                <label>邮箱:</label>
                <input type="email" name="email" required>
            </div>
            <div>
                <label>性别:</label>
                <input type="radio" name="gender" value="male" checked> 男
                <input type="radio" name="gender" value="female"> 女
            </div>
            <div>
                <label>爱好:</label>
                <input type="checkbox" name="hobbies[]" value="basketball"> 篮球
                <input type="checkbox" name="hobbies[]" value="football"> 足球
                <input type="checkbox" name="hobbies[]" value="reading"> 读书
            </div>
            <div>
                <label>城市:</label>
                <select name="city">
                    <option value="">请选择</option>
                    <option value="beijing">北京</option>
                    <option value="shanghai">上海</option>
                    <option value="guangzhou">广州</option>
                </select>
            </div>
            <div>
                <textarea name="intro" placeholder="个人简介"></textarea>
            </div>
            <div>
                <input type="submit" name="submit" value="注册">
                <input type="reset" value="重置">
            </div>
        </form>
    </body>
    </html>
    
  2. PHP 表单数据处理

    • 接收 POST 数据:通过$_POST['name']获取对应表单元素的值
    • 复选框组:name需设为数组形式(如hobbies[]),PHP 接收为数组
    • 数据验证:检查必填项、格式合法性(如密码一致性、邮箱格式)
    • 错误提示:将错误信息存储在数组中,回显到表单页面

    示例(register.php):

    <?php
    // 初始化错误信息数组
    $errors = [];
    $user_data = [];
    
    // 判断是否为POST请求
    if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['submit'])) {
        // 1. 接收表单数据(并去除首尾空白)
        $username = trim($_POST['username'] ?? '');
        $password = trim($_POST['password'] ?? '');
        $confirm_password = trim($_POST['confirm_password'] ?? '');
        $email = trim($_POST['email'] ?? '');
        $gender = $_POST['gender'] ?? '';
        $hobbies = $_POST['hobbies'] ?? []; // 复选框组,默认为空数组
        $city = $_POST['city'] ?? '';
        $intro = trim($_POST['intro'] ?? '');
        
        // 2. 数据验证
        // 用户名验证(长度2-10位)
        if (empty($username)) {
            $errors[] = "用户名不能为空";
        } elseif (mb_strlen($username, 'UTF-8') < 2 || mb_strlen($username, 'UTF-8') > 10) {
            $errors[] = "用户名长度必须为2-10位";
        }
        
        // 密码验证(长度6-20位,且两次输入一致)
        if (empty($password)) {
            $errors[] = "密码不能为空";
        } elseif (strlen($password) < 6 || strlen($password) > 20) {
            $errors[] = "密码长度必须为6-20位";
        } elseif ($password !== $confirm_password) {
            $errors[] = "两次输入的密码不一致";
        }
        
        // 邮箱验证(格式合法)
        if (empty($email)) {
            $errors[] = "邮箱不能为空";
        } elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) { // 使用PHP内置过滤器
            $errors[] = "邮箱格式不正确";
        }
        
        // 城市验证(必须选择)
        if (empty($city)) {
            $errors[] = "请选择城市";
        }
        
        // 3. 验证通过,处理数据(如存入数据库、创建SESSION等)
        if (empty($errors)) {
            $user_data = [
                'username' => $username,
                'email' => $email,
                'gender' => $gender,
                'hobbies' => implode('、', $hobbies), // 数组转为字符串
                'city' => $city,
                'intro' => $intro
            ];
            
            // 这里仅模拟成功,实际项目中会插入数据库
            echo "<h2>注册成功!</h2>";
            echo "<pre>";
            print_r($user_data);
            echo "</pre>";
            exit; // 终止脚本,避免显示表单
        }
    }
    
    // 验证失败或首次访问,显示表单(将错误信息回显)
    ?>
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <title>用户注册</title>
        <style>
            .error { color: red; }
        </style>
    </head>
    <body>
        <h1>用户注册</h1>
        <!-- 显示错误信息 -->
        <?php if (!empty($errors)): ?>
            <div class="error">
                <ul>
                    <?php foreach ($errors as $error): ?>
                        <li><?= $error ?></li>
                    <?php endforeach; ?>
                </ul>
            </div>
        <?php endif; ?>
        
        <!-- 表单(与register.html相同,略作修改以保留已填数据) -->
        <form action="register.php" method="post">
            <div>
                <label>用户名:</label>
                <input type="text" name="username" value="<?= $user_data['username'] ?? '' ?>" required>
            </div>
            <!-- 其他表单元素类似,通过value="<?= $user_data['xxx'] ?? '' ?>"保留已填数据 -->
            <!-- 此处省略其余表单代码,与register.html一致 -->
            <div>
                <input type="submit" name="submit" value="注册">
                <input type="reset" value="重置">
            </div>
        </form>
    </body>
    </html>
    
  3. PHP7 过滤器扩展(数据验证简化)

    • PHP 内置filter扩展,提供常用数据验证和过滤功能
    • 常用过滤器:
      • FILTER_VALIDATE_EMAIL:验证邮箱格式
      • FILTER_VALIDATE_URL:验证 URL 格式
      • FILTER_VALIDATE_INT:验证整数
      • FILTER_SANITIZE_STRING:过滤 HTML 标签和特殊字符

    示例:

    <?php
    // 1. 验证邮箱(使用filter_var)
    $email = "zhangsan@example.com";
    if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
        echo "邮箱格式正确<br>";
    } else {
        echo "邮箱格式错误<br>";
    }
    
    // 2. 验证整数(指定范围1-100)
    $age = 25;
    $options = ["options" => ["min_range" => 1, "max_range" => 100]];
    if (filter_var($age, FILTER_VALIDATE_INT, $options)) {
        echo "年龄格式正确<br>";
    } else {
        echo "年龄必须为1-100之间的整数<br>";
    }
    
    // 3. 过滤HTML标签(防止XSS攻击)
    $html = "<script>alert('攻击')</script> 我是张三";
    $sanitized = filter_var($html, FILTER_SANITIZE_STRING);
    echo "过滤后:{$sanitized}<br>"; // 输出:alert('攻击') 我是张三(script标签被移除)
    ?>
    
(三)PHP7 异常处理机制
  1. 异常的概念

    • 异常:程序执行过程中出现的意外情况(如数据库连接失败、文件不存在)
    • PHP7 + 支持通过try-catch-finally捕获和处理异常,替代传统的错误判断(if-else
  2. 异常处理语法

    <?php
    try {
        // 可能抛出异常的代码
        if (条件不满足) {
            throw new Exception("异常信息", 错误代码); // 手动抛出异常
        }
    } catch (Exception $e) {
        // 捕获异常并处理
        echo "捕获到异常:" . $e->getMessage() . "<br>";
        echo "错误代码:" . $e->getCode() . "<br>";
        echo "错误文件:" . $e->getFile() . "<br>";
        echo "错误行号:" . $e->getLine() . "<br>";
    } finally {
        // 无论是否抛出异常,都会执行(可选)
        echo "无论是否异常,我都会执行<br>";
    }
    ?>
    
  3. Web 开发中的异常处理场景

    • 表单数据验证失败(自定义异常)
    • 数据库操作错误(如连接失败、查询错误)
    • 文件读写错误(如文件不存在、权限不足)

    示例(自定义表单验证异常):

    <?php
    // 自定义异常类(继承自Exception)
    class FormValidationException extends Exception {
        // 可添加自定义方法(如获取错误列表)
        private $errorList;
        
        public function __construct(array $errors, $message = "表单验证失败", $code = 0, Exception $previous = null) {
            $this->errorList = $errors;
            parent::__construct($message, $code, $previous);
        }
        
        // 获取错误列表
        public function getErrorList(): array {
            return $this->errorList;
        }
    }
    
    // 表单处理函数
    function processForm(array $postData): array {
        $errors = [];
        $username = trim($postData['username'] ?? '');
        
        if (empty($username)) {
            $errors[] = "用户名不能为空";
        } elseif (mb_strlen($username) < 2) {
            $errors[] = "用户名长度不能少于2位";
        }
        
        // 验证失败,抛出自定义异常
        if (!empty($errors)) {
            throw new FormValidationException($errors);
        }
        
        // 验证通过,返回用户数据
        return ['username' => $username];
    }
    
    // 处理表单请求
    try {
        if ($_SERVER['REQUEST_METHOD'] === 'POST') {
            $userData = processForm($_POST);
            echo "表单处理成功:" . $userData['username'];
        }
    } catch (FormValidationException $e) {
        // 捕获表单验证异常
        echo "<h3>表单验证失败</h3>";
        echo "<ul>";
        foreach ($e->getErrorList() as $error) {
            echo "<li style='color: red;'>{$error}</li>";
        }
        echo "</ul>";
    } catch (Exception $e) {
        // 捕获其他异常(如系统错误)
        echo "系统错误:" . $e->getMessage();
        // 实际项目中可记录日志
        error_log("系统异常:" . $e->getMessage() . " " . $e->getFile() . ":" . $e->getLine());
    }
    ?>
    

三、注意事项

  1. 表单安全问题

    • XSS 攻击:提交包含 HTML/JS 代码的内容,需用htmlspecialchars()转义输出(如echo htmlspecialchars($username)
    • CSRF 攻击:跨站请求伪造,需添加 CSRF 令牌(如表单中加入随机 token,验证请求来源)
    • 数据过滤:所有用户输入的数据都不可信,必须验证和过滤(如用filter_var或自定义规则)
  2. 请求方法与参数安全

    • 敏感操作(如登录、注册、支付)必须用 POST 方法(避免参数暴露在 URL 中)
    • 避免使用$_REQUEST(混合 GET/POST/COOKIE,易被篡改)
    • 验证$_POST['submit']是否存在(防止直接访问处理脚本)
  3. 错误信息展示

    • 开发环境:可显示详细错误信息(便于调试)
    • 生产环境:隐藏详细错误信息(避免泄露系统信息),仅显示友好提示(如 “系统繁忙,请稍后再试”)
    • 错误日志:生产环境将错误信息记录到日志文件(通过error_log()函数)

四、实战练习

  1. 创建day6文件夹,新建login.phpcheck_login.php文件:

    • login.php:创建登录表单(包含用户名、密码输入框,提交按钮),支持显示错误提示
    • check_login.php:处理登录请求,实现以下功能:
      • 验证请求方法为 POST,否则跳转回登录页
      • 验证用户名和密码不为空,用户名长度 2-10 位,密码长度 6-20 位
      • 模拟验证逻辑:用户名 “admin” 且密码 “123456” 为合法(实际项目中需查询数据库)
      • 使用 PHP7 异常处理机制,自定义LoginException处理登录错误(如用户名不存在、密码错误)
      • 登录成功则显示 “欢迎,[用户名]!”,失败则返回登录页并显示错误信息
  2. 新建search.php文件:

    • 实现一个简单的搜索功能,支持 GET 请求传递搜索关键词(参数名keyword
    • 功能需求:
      • 若未传递keyword,显示搜索表单(输入框 + 搜索按钮)
      • 若传递keyword,验证关键词长度 1-50 位,否则提示 “搜索关键词长度无效”
      • 模拟搜索结果:返回包含关键词的 “文章列表”(数组形式,至少 3 条模拟数据)
      • 对搜索结果中的关键词进行标红处理(使用str_replace或正则表达式)
      • 防范 XSS 攻击:对关键词和搜索结果进行htmlspecialchars()转义输出
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐