Administrator
发布于 2026-08-19 / 3 阅读
0
0

Web应用架构与PHP开发

一、先建立整体画面:网站像一家餐厅

假设你在网站上点“登录”。

可以把整个过程想象成去餐厅吃饭:

网站里的角色

餐厅里的角色

负责什么

浏览器

顾客

提交请求,比如“我要登录”

前端页面 HTML/JS

菜单和点餐界面

让你输入账号、密码

HTTP 协议

服务员

把请求送到后厨,再把结果端回来

Web 服务器 Nginx/Apache

餐厅前台

接收请求,决定交给谁处理

PHP/Java 后端

厨师

真正处理业务,比如检查密码

MySQL 数据库

仓库

保存用户、留言等数据

响应结果

端上来的菜

登录成功、登录失败或新页面

所以一次登录大概是这样:

你输入账号密码
    ↓
浏览器发送 HTTP 请求
    ↓
Web 服务器接收请求
    ↓
PHP 检查输入是否合法
    ↓
PHP 去 MySQL 查询用户
    ↓
MySQL 返回查询结果
    ↓
PHP 判断密码是否正确
    ↓
浏览器显示“登录成功”或“登录失败”

这篇文章的所有内容,基本都是围绕这条链路展开。


二、全文结构拆分

文章可以分成四大块:

第一部分:网站整体怎么组织

关键词:

  • B/S 架构

  • 前后端分离

  • MVC

  • RESTful API

这一部分回答的是:

一个 Web 应用由哪些角色组成?它们怎么分工?


第二部分:PHP 怎么接收数据、操作数据库

关键词:

  • $_GET

  • $_POST

  • 输入验证

  • PDO

  • 预编译语句

  • 文件上传

  • 密码哈希

这一部分回答的是:

用户提交的数据到了服务器后,PHP 应该怎么安全地处理?


第三部分:做一个真正的留言板

关键词:

  • 注册

  • 登录

  • Session

  • 发布留言

  • 修改留言

  • 删除留言

  • 数据流安全分析

这一部分回答的是:

把前面学的知识组合起来,做一个完整的小网站。


第四部分:网站上线后的服务器与安全

关键词:

  • Apache

  • Nginx

  • Java Web

  • 日志

  • 中间件

  • 安全响应头

  • PHP 框架

这一部分回答的是:

代码写完以后,网站是怎么运行起来的?服务器怎么保护网站?


三、第一部分:Web 应用架构

1. B/S 架构是什么?

B/S 是:

  • B:Browser,浏览器

  • S:Server,服务器

也就是:

浏览器  ←→  服务器  ←→  数据库

我们平时打开网页、登录账号、提交表单,本质上都是:

  1. 浏览器向服务器发请求;

  2. 服务器处理请求;

  3. 服务器把结果返回给浏览器。

传统 B/S 架构

传统方式是:

服务器直接生成完整网页,浏览器只负责显示。

比如你点击“下一页”:

浏览器发请求
    ↓
PHP 查询数据
    ↓
PHP 生成一整张 HTML 页面
    ↓
浏览器重新加载整个页面

这就像你每改一个菜,都要把整张餐桌重新摆一遍。

特点:

  • 简单;

  • 对搜索引擎友好;

  • 但每次操作经常刷新整个页面;

  • 用户体验相对较差。


2. 前后端分离是什么?

现代网站通常会把“页面”和“数据”分开。

前端 React/Vue
    ↓ 请求数据
后端 API
    ↓ 查询
数据库

后端不再直接返回完整 HTML,而是返回 JSON 数据,例如:

{
  "id": 1,
  "username": "admin"
}

前端拿到数据后,再用 JavaScript 把数据显示在页面上。

用餐厅比喻

传统模式:

后厨把菜完全做好、摆盘完成,再端给你。

前后端分离:

后厨把加工好的食材交给前台,前台再根据你的餐桌界面进行摆盘。

优点

  • 页面不用每次整体刷新;

  • 一套后端可以同时支持网页、手机 App、小程序;

  • 前端和后端可以分开开发、分开部署。

安全重点

前后端分离以后,前端页面只是“皮肤”。

真正重要的是后端 API,因为数据都通过 API 进出。

所以安全测试时重点看:

  • API 是否验证身份;

  • API 是否检查权限;

  • API 是否过滤输入;

  • API 是否返回了不该返回的数据。


3. MVC 是什么?

MVC 是一种“分工方式”,把后端代码分成三类。

名称

中文理解

餐厅类比

主要职责

Model

数据层

仓库管理员

操作数据库

View

视图层

摆盘师

显示页面

Controller

控制器

调度员

接收请求,安排工作

用户请求进来后:

用户请求
  ↓
Controller 接收请求
  ↓
调用 Model 查询或修改数据
  ↓
Controller 拿到结果
  ↓
交给 View 生成页面
  ↓
返回给用户

举个例子

用户要查看自己的留言:

  1. Controller 接收请求:“用户想看留言”;

  2. Model 去数据库查询留言;

  3. View 把留言排版成 HTML;

  4. 浏览器显示出来。

为什么要分 MVC?

因为混在一起会很乱。

如果接收请求、查询数据库、显示页面都写在一个文件里,项目小还能看,项目大以后就很难维护。


4. RESTful API 是什么?

RESTful API 可以理解为:

前后端之间约定好的一套“访问规则”。

例如用户资源叫:

/api/users

不同操作通过 HTTP 方法区分:

操作

方法

示例

查询用户

GET

GET /api/users

新增用户

POST

POST /api/users

修改用户

PUT

PUT /api/users/42

删除用户

DELETE

DELETE /api/users/42

可以把它理解成:

  • URL 表示“操作什么东西”;

  • HTTP 方法表示“要做什么”。

例如:

DELETE /api/users/42

意思不是访问一个叫 DELETE 的页面,而是:

删除编号为 42 的用户。


四、第二部分:PHP 如何处理用户数据

这一部分最重要,因为很多安全问题都发生在这里。

1. $_GET 和 $_POST 是什么?

它们是 PHP 用来接收用户数据的“收件箱”。

$_GET

通常接收 URL 后面的数据。

例如:

search.php?keyword=test&page=2

其中:

  • keyword = test

  • page = 2

PHP 可以这样拿:

$keyword = $_GET["keyword"];
$page = $_GET["page"];

可以理解为:

用户把参数写在“快递单外面”,一眼就能看到。


$_POST

通常接收表单提交的数据,比如:

  • 登录密码;

  • 注册信息;

  • 留言内容。

PHP 可以这样拿:

$username = $_POST["username"];
$password = $_POST["password"];

可以理解为:

用户把数据放进“包裹里面”提交给服务器。

但注意:

POST 只是不像 GET 那样直接显示在地址栏,并不代表它绝对安全。

攻击者仍然可以修改 POST 数据。


2. 为什么“永远不要相信用户输入”?

因为用户提交给你的不一定是正常内容。

比如正常用户输入用户名:

zhangsan

攻击者可能输入:

<script>alert(1)</script>

或者:

admin' OR '1'='1

所以服务器必须先检查:

  • 长度对不对;

  • 类型对不对;

  • 格式对不对;

  • 是否在允许范围内;

  • 是否包含危险内容。

生活类比

别人寄给你一个包裹,你不能直接打开使用,而要先检查:

  • 是不是你期待的东西;

  • 尺寸是否正常;

  • 有没有危险物品;

  • 寄件信息是否可信。

用户输入也一样。


3. 输入验证是做什么的?

文章里列了几种验证方式。

类型验证

比如年龄必须是数字:

$age = filter_input(INPUT_POST, "age", FILTER_VALIDATE_INT);

如果用户输入的是:

abc

那就不能接受。


长度验证

比如用户名必须在 3 到 20 个字符之间:

if (strlen($username) < 3 || strlen($username) > 20) {
    die("用户名长度必须在 3-20 之间");
}

防止用户提交特别短、特别长或者无意义的数据。


白名单验证

白名单的意思是:

只允许明确列出来的值,其他全部拒绝。

<?php
$role = $_POST["role"] ?? "";
$allowed_roles = ["user", "editor", "moderator"];
if (!in_array($role, $allowed_roles)) {
    die("无效的角色");
}
>

例如用户角色只能是:

["user", "editor", "moderator"]

如果用户提交:

admin

但系统不允许用户自己选择 admin,就拒绝。

这比“只禁止某些危险值”更安全。


正则验证

正则表达式就是“格式检查器”。

$phone = $_POST["phone"] ?? "";
if (!preg_match('/^1[3-9]\d{9}$/', $phone)) {
    die("手机号格式不正确");
}

例如检查手机号:

/^1[3-9]\d{9}$/

意思是:

  • 必须以 1 开头;

  • 第二位必须是 3 到 9;

  • 后面还有 9 位数字;

  • 总共 11 位。

你不用一开始背正则,先知道它是“检查格式”的工具即可。


4. PDO 是什么?

PDO 是 PHP 连接数据库的一种标准方式。

PDO(PHP Data Objects)是 PHP 操作数据库的标准接口,支持预编译语句(Prepared Statements),是防御 SQL 注入的正确方式。

你可以把它理解成:

PHP 和 MySQL 之间的“翻译器”和“通信管道”。

PHP 不直接摸数据库,而是通过 PDO:

PHP → PDO → MySQL

PDO 可以做这些事:

  • 连接数据库;

  • 查询数据;

  • 新增数据;

  • 修改数据;

  • 删除数据。


5. SQL 注入是什么?

先看危险写法:

$sql = "SELECT * FROM users WHERE username = '$username'";

这相当于把用户输入直接拼进 SQL 句子里。

如果用户输入:

admin' OR '1'='1

最终可能变成:

SELECT * FROM users WHERE username = 'admin' OR '1'='1'

数据库就会理解为:

只要用户名是 admin,或者 1 等于 1。

而 1=1 永远成立,所以攻击者可能绕过登录。

生活类比

原本 SQL 是一句固定命令:

请帮我找到名字叫“张三”的人。

正常名字应该只是填空。

但 SQL 注入相当于用户在空格里面写:

张三,顺便把保险柜也打开。

如果服务器直接照搬,就会出大问题。


6. 预编译语句为什么安全?

安全写法是:

$stmt = $pdo->prepare("SELECT * FROM users WHERE username = :username");
$stmt->execute([":username" => $username]);

它的核心思想是:

SQL 结构和用户数据分开发送。

可以理解为给数据库一张固定表格:

查询用户名 = ______

用户只能往空格里填“值”,不能修改表格本身。

即使用户填的是:

admin' OR '1'='1

数据库也只会把它当成一个普通字符串,而不是 SQL 命令。

小白记住一句话

不要把用户输入直接拼进 SQL,要用 PDO 预编译。


7. password_hash() 是什么?

注册时,绝对不能把密码明文存进数据库。

错误做法:

用户名:zhangsan
密码:123456

如果数据库泄露,所有用户密码都会直接暴露。

正确做法是哈希:

$hash = password_hash($password, PASSWORD_DEFAULT);

哈希像什么?

像把肉放进绞肉机:

原始密码 → 哈希结果

但是你很难从绞肉恢复成原来的肉。

所以哈希是一种“不容易逆向”的处理方式。

登录时用:

password_verify($password, $user["password_hash"]);

它会判断:

用户这次输入的密码,和数据库里的密码哈希是否匹配。


8. Session 是什么?

HTTP 本身记性不好。

你访问登录页面和访问首页,对服务器来说可能是两次完全独立的请求。

Session 就像健身房发给你的手环:

  1. 你登录成功;

  2. 服务器给你一个身份标识;

  3. 之后你每次访问页面都带着它;

  4. 服务器一看,就知道你已经登录了。

代码里:

$_SESSION["user_id"] = $user["id"];

意思是:

在服务器端记录“当前这个用户是谁”。

登录成功以后还要执行:

session_regenerate_id(true);

相当于换一个新的手环,防止别人提前塞给你一个旧手环冒充登录状态。


五、第三部分:留言板项目到底在做什么?

文章中的留言板项目包含:

  • 注册;

  • 登录;

  • 发布留言;

  • 查看留言;

  • 修改留言;

  • 删除留言。

这就是所谓的 CRUD:

缩写

英文

中文

示例

C

Create

新增

发布留言

R

Read

查询

查看留言

U

Update

修改

编辑留言

D

Delete

删除

删除留言

几乎大部分网站都是在做这四件事:

  • 用户系统:新增用户、查看用户、修改资料、删除账号;

  • 电商系统:新增商品、查看商品、修改商品、下架商品;

  • 留言板:新增留言、查看留言、修改留言、删除留言。


项目文件可以理解为一栋小房子

guestbook/
├── config.php
├── db.php
├── auth.php
├── index.php
├── register.php
├── login.php
├── logout.php
├── post.php
├── edit.php
├── delete.php
└── templates/

简单理解:

文件

作用

config.php

放配置,比如数据库账号、网站名称

db.php

专门负责连接数据库

auth.php

处理登录、退出、权限判断

index.php

首页,显示留言列表

register.php

注册页面

login.php

登录页面

logout.php

退出登录

post.php

发布留言

edit.php

修改留言

delete.php

删除留言

templates/

页面公共部分,比如头部和底部

这样做的目的是:

不要把所有代码都塞进一个文件,而是让每个文件负责一件事。


注册功能的完整逻辑

注册不是简单地“把用户名密码存起来”,而是:

接收用户名和密码
    ↓
检查用户名长度和格式
    ↓
检查密码长度
    ↓
检查两次密码是否一致
    ↓
检查用户名是否已经存在
    ↓
对密码进行哈希
    ↓
存入数据库

也就是:

先检查,再处理,最后才入库。


登录功能的完整逻辑

登录流程是:

接收用户名和密码
    ↓
根据用户名查询数据库
    ↓
判断用户是否存在
    ↓
用 password_verify 验证密码
    ↓
成功后创建 Session
    ↓
跳转到首页

注意文章中的一个细节:

用户名或密码错误

它不会明确告诉你:

  • 用户名不存在;

  • 还是密码错误。

因为如果提示太具体,攻击者就可以判断哪些用户名存在。

例如:

  • 提示“用户不存在”:说明账号没注册;

  • 提示“密码错误”:说明账号存在,只是密码不对。

这会给攻击者提供信息。


修改和删除为什么要检查权限?

假设每条留言都有 ID。

你登录后可以删除自己的留言:

delete.php?id=10

但如果系统只检查“你有没有登录”,不检查“这条留言是不是你的”,那么你可能把地址改成:

delete.php?id=11

然后删掉别人的留言。

这就是典型的越权问题。

所以正确逻辑应该是:

  1. 检查用户是否登录;

  2. 查询这条留言;

  3. 判断留言作者是不是当前用户;

  4. 只有作者是本人,才允许修改或删除。


六、数据流安全分析:全文最核心的思想

文章最重要的图其实是这一条:

用户输入
  ↓
前端验证
  ↓
HTTP 请求
  ↓
PHP 接收数据
  ↓
服务端验证
  ↓
SQL 查询
  ↓
数据库执行
  ↓
PHP 生成页面
  ↓
浏览器显示

这条路径上的每一步都可能出问题。


1. 前端验证为什么不安全?

前端验证就是浏览器里的 JavaScript 检查,比如:

  • 密码必须 6 位;

  • 邮箱格式必须正确;

  • 用户名不能为空。

它主要是为了让用户体验更好。

但攻击者可以:

  • 禁用 JavaScript;

  • 用工具直接构造请求;

  • 修改浏览器提交的数据。

所以:

前端验证只能提升体验,不能作为真正的安全防线。

真正的安全检查必须放在服务器端。


2. SQL 注入发生在哪里?

发生在:

Text

PHP 接收输入 → 拼接 SQL → MySQL 执行

防御方式:

使用 PDO 预编译,不直接拼接用户输入。


3. XSS 是什么?

XSS 可以理解为:

攻击者把一段恶意脚本当作普通内容提交给网站,网站又把它显示给其他用户。

例如攻击者提交留言:

<script>alert(1)</script>

如果网站直接显示,其他用户打开页面时,浏览器会把它当成代码执行。

防御方式:

htmlspecialchars($content, ENT_QUOTES, "UTF-8");

它会把特殊符号转换成普通文本。

比如:

<script>

变成类似:

&lt;script&gt;

浏览器就会把它当文字显示,而不是当脚本执行。

小白记住

进数据库前防 SQL 注入,显示到页面前防 XSS。


4. 文件上传为什么危险?

如果网站允许用户上传头像,但不检查文件类型,攻击者可能上传:

shell.php

如果服务器把它当 PHP 文件执行,攻击者就可能控制网站。

所以上传文件时应该:

  • 限制文件类型;

  • 限制文件大小;

  • 不使用用户原始文件名;

  • 重新生成随机文件名;

  • 上传目录尽量不要允许执行 PHP。


七、第四部分:服务器、中间件和日志

1. Apache 和 Nginx 是什么?

它们是 Web 服务器。

可以理解为:

网站门口的接待员。

浏览器访问网站时,请求先到 Nginx 或 Apache,再由它们决定:

  • 请求的是静态文件,直接返回;

  • 请求的是 PHP 页面,就交给 PHP 处理;

  • 请求的是后端接口,就转发给后端服务。

简单分工:

浏览器
  ↓
Nginx / Apache
  ↓
PHP
  ↓
MySQL

2. 安全响应头是什么?

安全响应头可以理解为:

服务器告诉浏览器:“请遵守这些安全规则。”

例如:

X-Frame-Options: DENY

意思是:

不允许别人把本网站嵌入 iframe 中,降低点击劫持风险。

还有:

X-Content-Type-Options: nosniff

意思是:

浏览器不要自作主张猜测文件类型,防止把文本误当成脚本执行。

以及:

Content-Security-Policy: default-src 'self'

意思是:

默认只允许加载本站资源,减少恶意脚本来源。

你可以把安全响应头理解成网站贴在门口的规章制度。


3. 为什么要隐藏服务器版本?

比如服务器返回:

Apache/2.4.49

攻击者看到后,就可能搜索:

Apache 2.4.49 有什么已知漏洞?

所以要尽量隐藏详细版本信息,减少给攻击者的提示。


4. 日志是什么?

日志就像网站的监控录像。

它会记录:

  • 谁访问了网站;

  • 什么时间访问的;

  • 访问了哪个地址;

  • 使用了什么浏览器或工具;

  • 请求是否成功。

例如安全人员可以通过日志发现:

  • 某个 IP 访问特别频繁;

  • 有人尝试 SQL 注入;

  • 有人使用扫描工具;

  • 有人频繁访问不存在的路径。

例子

统计访问次数最多的 IP:

awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -10

你不用先背命令,只需要理解它在做:

提取 IP
  ↓
排序
  ↓
统计每个 IP 出现次数
  ↓
按次数从高到低排列
  ↓
取前 10 名

5. 中间件是什么?

中间件是位于用户和后端服务之间的“中间层”。

中间件

小白理解

主要作用

CDN

分布在各地的分店

加速静态资源访问

负载均衡

分流员

把访问分配给多台服务器

WAF

安检门

拦截恶意请求

反向代理

前台代办

隐藏真实后端服务器

API 网关

总入口

管理认证、限流和路由

它们不是业务代码本身,但会影响网站安全和稳定性。


6. Java Web 部分需要掌握什么?

这部分不用一开始深入 Java。

只需要知道:

  • Java 也能开发 Web 后端;

  • Servlet 类似“处理某个 URL 请求的程序”;

  • Spring Boot 是常见 Java Web 框架;

  • Java 项目也会分成 Controller、Service、Repository、Model。

它和 PHP 的对应关系大概是:

PHP 项目

Java 项目

login.php 接收请求

Controller

自定义业务函数

Service

PDO 查询数据库

Repository / MyBatis / JPA

用户数据

Model

配置文件

application.properties

安全思路类似:

  • 是否参数化查询;

  • 是否验证输入;

  • 是否编码输出;

  • 是否检查权限;

  • 是否暴露调试信息。


八、把全文压缩成一张“小白地图”

你可以把整篇文章理解成下面这张图:

一、先知道网站怎么组成
浏览器 → Web 服务器 → 后端程序 → 数据库

二、再知道后端怎么分工
Controller 管请求
Model 管数据库
View 管页面展示

三、然后学习 PHP 如何处理请求
GET/POST 接收数据
输入验证过滤危险内容
PDO 预编译操作数据库
password_hash 保存密码
Session 记住登录状态

四、接着做一个留言板
注册、登录、发留言、改留言、删留言

五、最后把网站放到服务器上
Nginx/Apache 接收访问
配置安全响应头
分析访问日志
使用 WAF、CDN 等中间件

九、最值得你优先掌握的 10 个概念

如果你是完全小白,可以按这个顺序学:

第一组:网站运行基础

1. 浏览器

负责展示页面、提交请求。

2. 服务器

负责接收请求、运行后端代码。

3. 数据库

负责长期保存数据。

4. HTTP

浏览器和服务器之间的通信规则。


第二组:代码分工

5. 前端

负责用户看到的界面。

6. 后端

负责业务逻辑,比如登录、注册、查询留言。

7. MVC

把后端代码分成 Controller、Model、View,方便维护。


第三组:安全核心

8. 输入验证

不直接相信用户提交的数据。

9. 预编译语句

防止用户输入被当成 SQL 命令执行。

10. 输出编码

防止用户输入被浏览器当成脚本执行。


十、用一句话记住每个安全点

安全点

一句话记忆

前端验证

只能优化体验,不能真正防攻击

SQL 注入

不要把用户输入拼进 SQL

预编译

先固定 SQL 模板,再往里面填值

XSS

用户输入显示到页面前要编码

密码存储

不存明文密码,要存哈希

Session

登录成功后给用户发“身份手环”

文件上传

不轻信文件名和文件类型

权限检查

登录了不代表可以操作别人的数据

错误提示

不要向用户暴露数据库和服务器细节

日志

出事后靠日志还原发生了什么


十一、建议你这样学这份内容

第一步:先画请求流程

不要急着看代码,先把这个流程画熟:

浏览器输入数据
→ HTTP 请求
→ Web 服务器
→ PHP
→ MySQL
→ PHP
→ HTTP 响应
→ 浏览器显示

第二步:理解注册和登录

注册重点看:

  1. 输入是否合法;

  2. 用户名是否重复;

  3. 密码是否哈希;

  4. 是否用预编译插入数据库。

登录重点看:

  1. 根据用户名查询;

  2. 用 password_verify 验证密码;

  3. 登录成功后写 Session;

  4. 错误提示不要暴露具体原因。


第三步:理解增删改查

重点回答四个问题:

  • 新增留言时,用户输入怎么进数据库?

  • 查询留言时,数据怎么从数据库到页面?

  • 修改留言时,怎么确认只能改自己的?

  • 删除留言时,怎么防止删除别人的?


第四步:最后看服务器配置

先知道 Nginx/Apache 是“接待员”,再学习:

  • 如何隐藏版本;

  • 如何添加安全响应头;

  • 如何禁止访问隐藏文件;

  • 如何分析日志。


十二、最简版总结

这份内容可以浓缩成五句话:

  1. Web 应用就是浏览器、服务器和数据库之间不断交换数据。

  2. 前端负责展示,后端负责处理,数据库负责保存。

  3. 用户输入不能直接相信,必须验证、过滤和编码。

  4. 操作数据库要用 PDO 预编译,保存密码要用哈希。

  5. Web 安全的核心,是检查数据从输入到输出的每一步是否处理正确。

如果你刚开始学,不用先死磕所有命令和配置。先牢牢掌握这条主线:

用户输入从哪里来,经过哪些代码,最后去了数据库还是页面。


评论