多仔 https://www.duox.dev/ zh-CN 用最初的心,走最远的路。 Thu, 29 Jan 2026 02:44:38 +0000 Thu, 29 Jan 2026 02:44:38 +0000 PHP 基础案例教程之 07-PHP 操作 MySQL 数据库 https://www.duox.dev/post/178.html https://www.duox.dev/post/178.html Thu, 29 Jan 2026 02:44:38 +0000 多仔

AI 摘要

文章系统讲解 PHP 操作 MySQL 的三种扩展:已淘汰的 mysql、专精 MySQL 的 mysqli 与跨库兼容的 PDO。重点演示 mysqli 的连接、字符集、查询、结果集遍历及预处理防注入,并给出订单表示例;随后详解 PDO 的 DSN 构建、异常模式、命名占位符预处理与增删改查完整流程,强调其现代框架首选地位与更高安全性。

PHP 操作数据库

PHP 中的数据库扩展

在 PHP 应用中要和 MySQL 数据库进行交互,需要借助 PHP 提供的数据库扩展。

  • MySQL 扩展:PHP 与 MySQL 数据库交互的早期扩展,在 PHP 7 中已经彻底被淘汰。
  • MySQLi 扩展:专为 MySQL 设计,是 MySQL 扩展的增强版,包含所有 MySQL 扩展的功能函数和 MySQL 高级特性。
  • PDO 扩展:解决了早期 PHP 中不同数据库扩展的 API 接口互不兼容的问题,是现代 PHP 框架和需要跨数据库的应用首选。

MySQLi

MySQLi 概述

MySQLi 扩展提供了大量的函数操作 MySQL,使得在 PHP 程序中操作数据库变得轻松便捷。

MySQLi 扩展默认已经安装,在使用时需要在 PHP 配置文件(php.ini)中开启。

PHP 配置文件(php.ini):

extension=mysqli

MySQLi 函数

MySQLi 扩展不仅为 PHP 连接数据库、执行 SQL 语句提供了函数,而且提供了很多简化开发的其他常用操作函数。

MySQLi 扩展的基本函数:

名称描述
mysqli_connect()连接 MySQL 服务器
mysqli_connect_error()获取连接服务器时的错误信息
mysqli_select_db()选择数据库
mysqli_set_charset()设置客户端字符集
mysqli_query()执行 SQL 语句
mysqli_insert_id()获取上一次插入操作时产生的 id
mysqli_affected_rows()获取上一次操作时受影响的行数
mysqli_errno()返回上一个 MySQL 操作中的错误信息的错误码
mysqli_error()返回上一个 MySQL 操作产生的错误信息
mysqli_close()关闭数据库连接

连接数据库

PHP 访问 MySQL 数据库之前,需要连接数据库。

mysqli_connect 函数的基本用法:

$数据库连接对象 = mysqli_connect(主机地址, 用户名, 密码, 数据库名, 主机端口号);

在使用 PHP 连接数据库时,还需要设置字符集,确保 PHP 与 MySQL 的连接使用相同的字符集 UTF8。

mysqli_set_charset 函数的基本用法:

mysqli_set_charset(数据库连接对象, 字符集编码);

MySQL 连接成功后,执行完操作,需要在适当的时候关闭数据库连接。

mysqli_close 函数的基本用法:

mysqli_close(数据库连接对象);

示例:连接数据库

SQL 脚本:

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for order
-- ----------------------------
DROP TABLE IF EXISTS `order`;
CREATE TABLE `order` (
  `id` int NOT NULL AUTO_INCREMENT COMMENT '主键id',
  `orderId` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '订单编号',
  `productName` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '产品名称',
  `price` decimal(10,2) DEFAULT NULL COMMENT '产品价格',
  `userName` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '买家姓名',
  `phone` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '买家电话',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

-- ----------------------------
-- Records of order
-- ----------------------------
BEGIN;
INSERT INTO `order` (`id`, `orderId`, `productName`, `price`, `userName`, `phone`) VALUES (1, 'No.001', '智能手机', 14999.00, '张三', '13888888888');
INSERT INTO `order` (`id`, `orderId`, `productName`, `price`, `userName`, `phone`) VALUES (2, 'No.002', '笔记本电脑', 8999.00, '李四', '15788888888');
INSERT INTO `order` (`id`, `orderId`, `productName`, `price`, `userName`, `phone`) VALUES (3, 'No.003', '无线蓝牙耳机', 129.00, '王五', '18988888888');
COMMIT;

SET FOREIGN_KEY_CHECKS = 1;

入口页面(index.php):

<?php
// 连接数据库
$mysql = mysqli_connect("localhost", "root", "123456..", "demo", "3306");

if(!$mysql) {
    // 连接失败,输出错误信息
    exit(mysqli_error($mysql));
}

// 设置字符集编码
mysqli_set_charset($mysql, "utf8");

print_r("数据库连接成功");

// 关闭数据库连接
mysqli_close($mysql);

示例效果:


执行 SQL 语句

数据库连接成功后,就可以执行 SQL 语句进行数据操作。

mysqli_query 函数的基本用法:

mysqli_query(数据库连接对象, SQL语句, 结果集模式);

当函数执行写操作时,函数返回值为 boolean。

当函数执行读操作时,函数根据结果集模式返回查询结果集。

  • MYSQLI_STORE_RESULT:默认模式,会将结果集全部读取到 PHP。
  • MYSQLI_USE_RESULT:仅初始化结果集检索,在处理结果集时进行数据读取。

处理结果集

使用 mysqli_query 函数执行读操作时,返回的是一个资源类型的结果集,需要对结果集作进一步处理,获取结果集中的数据。

MySQLi 扩展处理结果集的基本函数:

名称描述
mysqli_num_rows(结果集对象)获取结果中行的数量
mysqli_fetch_all(结果集对象, 数组形式)获取所有结果并以数组方式返回
数组形式:MYSQL_ASSOC(关联数组)/ MYSQL_NUM(索引数组)
mysqli_fetch_array(结果集对象)获取一行结果并以数组方式返回
mysqli_fetch_assoc(结果集对象)获取一行结果并以关联数组返回
mysqli_fetch_row(结果集对象)获取一行结果并以索引数组返回
mysqli_free_result(结果集对象)释放结果集

示例:处理结果集

入口页面(index.php):

<?php
// 连接数据库
$mysql = mysqli_connect("localhost", "root", "123456..", "demo", "3306");

if(!$mysql) {
    // 连接失败,输出错误信息
    exit(mysqli_error($mysql));
}

// 设置字符集编码
mysqli_set_charset($mysql, "utf8");

print_r("数据库连接成功");

// 执行SQL语句
$result = mysqli_query($mysql, "SELECT * FROM `order`");

// 获取结果集数组
print_r("<pre>");
print_r(mysqli_fetch_all($result, MYSQLI_ASSOC));
print_r("</pre>");

// 关闭数据库连接
mysqli_close($mysql);

示例效果:


预处理操作

使用 MySQLi 扩展执行增删改操作时,需要拼接 SQL 语句,效率低,安全性差,容易导致 SQL 注入问题。

MySQLi 扩展预处理提供了预处理方式,实现 SQL 语句和数据的分离,执行 SQL 语句运行效率高,无须考虑数据中包含特殊字符导致的 SQL 注入问题。

预处理的实现过程:

  • 定义一个 SQL 语句模板。
  • 为该模板进行参数绑定。
  • 将用户提交的数据内容发送给 MySQL 执行。

mysqli_prepare 函数用于预处理 SQL 模板,在编写 SQL 模板时,使用 ? 号占位符代替数据部分,且占位符两边无须使用引号包裹。

mysqli_prepare 函数的基本用法:

$预处理对象 = mysqli_prepare(数据库连接对象, SQL模板);

mysqli_stmt_bind_param 函数用于将变量作为参数绑定到预处理语句中。

mysqli_stmt_bind_param 函数的基本用法:

mysqli_stmt_bind_param(预处理对象, 数据类型, 绑定变量1, 绑定变量2...);

使用 mysqli_stmt_bind_param 函数进行参数绑定时,可以指定数据类型,且与绑定变量一一对应,绑定变量使用引用传参。

参数绑定时可以指定的基本数据类型:

名称描述
i整型
d浮点型
s字符串型
b二进制对象

mysqli_stmt_execute 函数用于执行预处理语句。

mysqli_stmt_execute 函数的基本用法:

mysqli_stmt_execute(预处理对象);

示例:预处理操作

入口页面(index.php):

<?php
// 连接数据库
$mysql = mysqli_connect("localhost", "root", "123456..", "demo", "3306");

if(!$mysql) {
    // 连接失败,输出错误信息
    exit(mysqli_error($mysql));
}

// 设置字符集编码
mysqli_set_charset($mysql, "utf8");

print_r("数据库连接成功");

// 定义预处理对象
$stmt = mysqli_prepare($mysql, "UPDATE `order` SET productName = ?, price = ? WHERE id = ?");

// 绑定参数
$productName = "HUAWEI手机";
$price = 7999.0;
$id = 1;
mysqli_stmt_bind_param($stmt, "sdi", $productName, $price, $id);

// 执行预处理语句
$result = mysqli_stmt_execute($stmt);

print_r($result ? "执行成功" : "执行失败");

// 关闭数据库连接
mysqli_close($mysql);

示例效果:


PDO

PDO 概述

PDO(PHP Data Objects)是 PHP 官方提供的数据库抽象层扩展,从 PHP 5.1 开始内置支持,PHP 7/8 成为操作数据库的主流标准,也是所有主流 PHP 框架(如 Laravel、ThinkPHP、Yii 等)的底层数据库驱动。

PDO 是一套统一的数据库操作接口,封装了不同数据库的底层实现差异,让开发者能用同一套代码语法操作 MySQL、PostgreSQL、SQLite、Oracle 等几十种数据库,同时提供了完善的防 SQL 注入方案,是现代 PHP 开发中操作数据库的首选方案。

PDO 与 mysqli、mysqli 对比:

特性PDOmysqlimysql
支持数据库跨库兼容仅 MySQL/MariaDB仅 MySQL/MariaDB
防注入支持原生预处理(推荐)原生预处理(仅问号占位)无,需手动转义
占位符类型命名占位符 + 问号占位符仅问号占位符无占位符,需拼接 SQL
错误处理支持异常抛出,高效需手动判断,繁琐需手动判断,繁琐
语法风格统一面向对象语法面向对象 + 过程化(双套)仅过程化语法

PHP 7/8 已默认启用 PDO,无需额外安装,如未默认启用,需要在 PHP 配置文件(php.ini)中开启。

PHP 配置文件(php.ini):

extension=pdo_mysql

连接数据库

PDO 通过构造函数创建连接对象。

PDO 构造函数的基本用法:

// 构建 DSN
$dsn = "mysql:host=主机地址:主机端口号;dbname=数据库名;charset=编码";

// 构建 PDO核心配置项
$options = [
    // 错误时抛出异常,替代手动判断
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    // 关闭模拟预处理,使用MySQL原生预处理,防SQL注入核心
    PDO::ATTR_EMULATE_PREPARES => false,
    // 默认返回关联数组
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
];

try {
    // 构建 PDO
    $pdo = new PDO($dsn, 用户名, 密码, $options);
} catch (PDOException $e) {
    // 捕获异常
    die("数据库连接失败:".$e->getMessage());
}

示例:连接数据库

入口页面(index.php):

<?php
$dsn = "mysql:host=localhost:3306;dbname=demo;charset=utf8mb4";
$options = [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_EMULATE_PREPARES => false,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
];

try {
    $pdo = new PDO($dsn, "root", "123456..", $options);
    echo "数据库连接成功";
} catch (PDOException $e) {
    die("数据库连接失败:".$e->getMessage());
}

示例效果:


预处理操作

PDO 执行 SQL 分两种场景:

  • 所有带动态参数的 SQL(如用户输入、变量),必须用「预处理语句」,这是防 SQL 注入的唯一有效方式。
  • 无参数的固定 SQL(如查所有数据),可直接执行。

预处理语句分为 prepare 预处理 和 execute 执行两步:

  • 先将带占位符的 SQL 发送给 MySQL 编译,编译后可重复执行。
  • 再将参数值发送给 MySQL,参数值会被当作纯数据处理,不会被解析为 SQL 语句,从根本上避免注入。

PDO 支持两种占位符:

  • 命名占位符::变量名(如:id、:name),执行时用关联数组传参,推荐使用命名占位符。
  • 问号占位符:?,执行时用索引数组传参,参数顺序必须和 SQL 中一致。

预处理操作的基本用法:

// 定义带命名占位符的SQL(字段名和占位符对应)
$sql = "INSERT INTO user (name, age, email) VALUES (:name, :age, :email)";

// prepare 预处理
$stmt = $pdo->prepare($sql);

// 定义参数数组(键=占位符,值=实际数据)
$params = [
    ':name' => '张三',
    ':age' => 20,
    ':email' => '[email protected]'
];

// execute 执行
$stmt->execute($params);

CRUD

PDO CRUD 中的基本函数:

名称描述
lastInsertId()获取新增数据的自增 ID
fetch()获取单条数据,适用于按 ID 查、查一条记录
fetchAll()获取所有数据,适用于查列表、多条记录
rowCount()获取查询结果的行数
增删改时返回操作影响的行数

PDO 操作数据库的核心流程:

  • 创建 PDO 连接对象:配置数据库地址、库名、账号密码及核心参数,建立与数据库的连接。PDO 对象全局唯一,一个项目只需一个连接,可设计为单例。
  • 预处理 SQL 语句:通过 prepare 函数编译带占位符的 SQL,返回语句对象。
  • 执行并传参:通过 execute 函数传递参数,执行预处理后的 SQL。
  • 获取执行结果:通过 CRUD 基本半数获取执行结果。

示例:CRUD

入口页面(index.php):

<?php
$dsn = "mysql:host=localhost:3306;dbname=demo;charset=utf8mb4";
$options = [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_EMULATE_PREPARES => false,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
];

try {
    $pdo = new PDO($dsn, "root", "123456..", $options);
    echo "数据库连接成功";
} catch (PDOException $e) {
    die("数据库连接失败:".$e->getMessage());
}

// 新增数据
echo "【新增数据】<br>";
$insertSql = "INSERT INTO `order` (orderId, productName, price, userName, phone) VALUES (:orderId, :productName, :price, :userName, :phone)";
$insertStmt = $pdo->prepare($insertSql);
$insertStmt->execute([
    ':orderId' => 'No.004',
    ':productName' => '华为Mate80 Pro',
    ':price' => 9999.00,
    ':userName' => '张三',
    ':phone' => '13800138000'
]);
$newOrderId = $pdo->lastInsertId();
echo "新增成功!自增ID:{$newOrderId}<br><hr>";

// 查询数据
echo "【查询数据】<br>";
$listSql = "SELECT id, orderId, productName, price, userName FROM `order` ORDER BY id DESC";
$listStmt = $pdo->query($listSql);
$orderList = $listStmt->fetchAll();
echo "所有数据(共{$listStmt->rowCount()}条):<br>";
foreach ($orderList as $item) {
    echo "ID:{$item['id']} | 订单号:{$item['orderId']} | 商品:{$item['productName']} | 价格:{$item['price']}元<br>";
}
echo "<hr>";

// 修改数据
echo "【修改数据】<br>";
$updateSql = "UPDATE `order` SET productName = :productName, price = :price, phone = :phone WHERE id = :id";
$updateStmt = $pdo->prepare($updateSql);
$updateStmt->execute([
    ':productName' => '华为Mate60 Pro+',
    ':price' => 7999.00,
    ':phone' => '13900139000',
    ':id' => $newOrderId
]);
$updateRow = $updateStmt->rowCount();
if ($updateRow > 0) {
    echo "修改成功!共修改{$updateRow}条数据<br>";
} else {
    echo "修改失败<br>";
}
echo "<hr>";

echo "【删除数据】<br>";
$deleteSql = "DELETE FROM `order` WHERE id = :id";
$deleteStmt = $pdo->prepare($deleteSql);
$deleteStmt->execute([':id' => 1]);
$deleteRow = $deleteStmt->rowCount();
if ($deleteRow > 0) {
    echo "删除成功!已删除ID为{$newOrderId}的数据<br>";
} else {
    echo "删除失败<br>";
}

示例效果:


]]>
2 https://www.duox.dev/post/178.html#comments https://www.duox.dev/feed/post/178.html
PHP 基础案例教程之 06-Web 前后端数据交互 https://www.duox.dev/post/177.html https://www.duox.dev/post/177.html Wed, 28 Jan 2026 07:05:41 +0000 多仔

AI 摘要

本文系统梳理 PHP 前后端数据交互核心:从 HTTP/HTTPS 原理、请求与响应报文结构,到 $_SERVER 获取环境信息;详解 form 表单各类控件及 GET/POST/$_REQUEST 接收,演示 header 自定义响应;剖析 Cookie 与 Session 的创建、读取、删除及安全限制;最后给出 cURL 模拟请求完整代码,覆盖初始化、选项设置、执行与关闭,帮助开发者快速掌握 Web 数据通信全流程。

HTTP

HTTP 概述

HTTP(Hyper Text Transfer Protocol,超文本传输协议) 是浏览器与 Web 服务器之间进行数据交互时需要遵循的一种协议,用于定义浏览器与 Web 服务器之间数据交换的格式。

HTTP 的特点:

  • 简单快速:客户端向服务器发送请求时,只需要传送请求方式和请求路径等简单信息。
  • 灵活:HTTP 允许传输任意类型的数据。
  • 无连接:限制每次连接只处理一个请求,服务器处理完客户端的请求,并收到客户端的应答后,就会断开连接,节省传输时间。
  • 无状态:协议对于事物处理没有记忆能力,如果后续的处理需要使用前面请求的数据,则必须重新传递,这样可能导致每次连接发送的数据量增大,但当在服务器不需要前面的请求数据时,应答就比较快。

HTTPS(Hyper Text Transfer Protocol over SecureSocket Layer,超文本传输安全协议)解决了 HTTP 明文传输不安全的问题,它在 HTTP 基础上通过加密和身份认证保证数据传输过程中的安全性。主要应用于对安全性要求比较高的通讯中。

HTTPS 和 HTTP 的区别:

  • 安全性:HTTP 数据都是未加密的,明文传输,安全性较差,HTTPS 数据传输过程是加密的,安全性较好。
  • 页面响应速度:HTTP 页面响应速度比 HTTPS 快,HTTPS 协议包含了传输加密和身份认证,比 HTTP 更耗费服务器资源。
  • 端口:HTTP 默认使用 80 端口,HTTPS 默认使用 443 端口。

HTTP/1.0

基于 HTTP/1.0 版本的客户端与服务器在交互过程中需要经历 :

  • 建立 TCP 连接:基于 TCP(Transmission Control Protocol,传输控制协议),由操作系统实现。
  • 发送 HTTP 请求:客户端(如浏览器)按照 HTTP 规定的格式向 Web 服务器发送 HTTP 请求,Web 服务器(如 Nginx)接收到请求后按照 HTTP 解析出具体的内容进行处理。
  • 回送 HTTP 响应:Web 服务器处理完成后,为了告知浏览器处理结果,再按照 HTTP 回送响应消息,从而完成整个交互过程。
  • 关闭 TCP 连接:由操作系统实现。

使用 HTTP/1.0 每次建立 TCP 连接后,只能处理一个 HTTP 请求,这种通信方式对于内容越来越丰富的网页来说,效率十分低下。

HTTP/1.1

HTTP/1.1 支持持久连接,能够在一个 TCP 连接上传送多个 HTTP 请求和响应,从而避免多次建立和关闭 TCP 连接导致网页加载延时的问题。

当客户端与服务器建立连接后,客户端可以发送多个 HTTP 请求,并且在发送下一个请求时无须等待上次请求的返回结果,服务器必须按照接收请求的先后顺序依次返回响应结果,以保证客户端区分每次的响应内容,因此 HTTP/1.1 有效提高了交互效率。

请求消息

当用户通过浏览器访问网站时,浏览器会向服务器发送请求数据,这些请求数据被称为请求消息。

POST /index.php HTTP/1.1
Host: localhost
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64)
Accept: text/html,application/xhtml+xml,application/xml
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
 
a=1&b=2

请求消息包含:

  • 请求行:位于请求消息的第一行,其包含请求方式、请求资源路径和 HTTP 协议版本。
  • 请求头:位于请求行之后,用于向服务器传递附加消息。
  • 空行:用于分隔请求头和请求体。
  • 请求体:通过 POST 方式提交表单时,浏览器会将用户填写的数据放在请求体中发送。

请求头的基本参数:

名称描述
Accept客户端接受的数据类型
Accept-Charset客户端接受的字符集
Accept-Encoding客户端接受的数据编码格式
Accept-Language客户端接受的语言,可以指定多个
Host客户端想要访问的服务器主机
If-Modified-Since客户端拥有资源的有效时间
Referer客户端的原始资源 URI
User-Agent客户端的系统信息,包括操作系统、浏览器版本号等
Cookie客户端需要带给服务器的数据
Cache-Control客户端的缓存控制
Connection请求完成后,客户端希望是保持连接还是关闭连接
Content-Type客户端发送的请求体的数据类型
Content-Length客户端发送的请求体的长度

在浏览器的开发者工具中,可以查看请求标头。

$_SERVER

超全局数组变量 $_SERVER 是一个关联数组,可以查看服务器的相关信息和 PHP 运行环境的相关信息,这些信息由 Web 服务器创建,对于不同的 Web 服务器,获取到的内容也会有所不同。

超全局数组变量 $_SERVER 中的基本参数:

名称描述
HTTP_HOST当前请求头中 Host 字段的内容
HTTP_USER_AGENT当前请求头中 User-Agent 字段的内容
HTTP_ACCEPT当前请求头中 Accept 字段的内容
HTTP_ACCEPT_ENCODING当前请求头中 Accept-Encoding 字段的内容
HTTP_ACCEPT_LANGUAGE当前请求头中 Accept-Language 字段的内容
HTTP_REFERER当前请求头中 Referer 字段的内容
SERVER_NAME服务器名称
SERVER_ADDR服务器地址
SERVER_PORT服务器端口
REMOTE_ADDR来源地址
REMOTE_PORT来源端口
DOCUMENT_ROOT服务器文档根目录
SERVER_ADMIN服务器管理员邮箱地址
SCRIPT_FILENAME脚本文件的绝对路径
SCRIPT_NAME脚本文件的相对路径
SERVER_PROTOCOLHTTP 版本
REQUEST_METHOD请求方式
QUERY_STRING“?”后面的 URL 参数
REQUEST_URI请求 URI
PHP_SELF脚本文件的相对路径
REQUEST_TIME客户端发出请求的时间戳

示例:$_SERVER

入口页面(index.php):

<?php
print_r("请求头中的Host:".$_SERVER["HTTP_HOST"]."<br>");
print_r("请求头中的User-Agent:".$_SERVER["HTTP_USER_AGENT"]."<br>");
print_r("服务器名称:".$_SERVER["SERVER_NAME"]."<br>");
print_r("服务器端口:".$_SERVER["SERVER_PORT"]."<br>");
print_r("请求方式:".$_SERVER["REQUEST_METHOD"]."<br>");

示例效果:


响应消息

服务器接收到客户端发送的请求数据后,将处理后的数据返回给客户端,这些数据被称为响应消息。

HTTP/1.1 200 OK
Date: Wed, 26 Oct 2016 01:15:33 GMT
Server: Apache/2.2.25 (Win32) mod_fcgid/2.3.6
Vary: Accept-Encoding,Cookie
Cache-Control: max-age=3, must-revalidate
Content-Length: 18327
Content-Type: text/html; charset=UTF-8

<!DOCTYPE html>
<html><body></body></html>

响应消息包含:

  • 响应行:位于 HTTP 响应消息的第一行,用于告知客户端本次响应的状态。
  • 响应头:告知浏览器本次响应的基本信息。
  • 空行:用于分隔响应头和响应体。
  • 响应体:服务器给浏览器返回的数据,浏览器对不同类型的响应体会有不同的处理方式。

响应头的基本参数:

名称描述
Server服务器的类型和版本信息
Date服务器的响应时间
Expires控制缓存的过期时间
Location控制浏览器显示哪个页面,重定向到新的 URL
Accept-Ranges服务器是否支持分段请求,以及请求范围
Content-Disposition服务器控制浏览器以下载方式打开文件
Content-Encoding实体内容的编码格式
Content-Length实体内容的长度
Content-Language实体内容的语言和国家名
Content-Type实体内容的类型
Last-Modified请求文档的最后一次修改时间
Transfer-Encoding文件传输编码
Set-Cookie发送 Cookie 相关的信息
Connection是否需要持久连接

在浏览器的开发者工具中,可以查看响应标头。

header 函数

有时开发者需要手动更改一些响应消息头,以满足网站项目的特殊需求,通过 header 函数可以自定义响应头。


示例:header 函数

入口页面(index.php):

<?php
header("Location: https://www.duox.dev");

表单

表单组成

一个完整的表单是由 form 标签和表单控件标签组成的。

form 标签的基本用法:

<form action="..." method="..." enctype="...">
    <!-- ... -->
</form>

form 标签的基本属性:

名称描述
action指定接收表单数据的服务器程序的地址
method设置表单数据的提交方式,可选 GET/POST ,默认值为 GET
enctype设置表单数据发送到服务器前对表单数据的编码方式
application/x-www-form-urlencoded:默认值,在发送表单数据前对所有字符编码 multipart/form-data:不进行字符编码,通常含有文件上传的表单使用该值 text/plain:传输普通文本,不对特殊字符编码

input 表单控件标签的基本用法:

<!-- 文本框 -->
<input type="text" name="user" value="test">
<!-- 密码框 -->
<input type="password" name="pwd" value="">
<!-- 文件上传域 -->
<input type="file" name="upload">
<!-- 隐藏域 -->
<input type="hidden" name="id" value="2">
<!-- 重置按钮 -->
<input type="reset"  value="重置">
<!-- 提交按钮 -->
<input type="submit" value="提交">
<!-- 单选按钮 -->
<input type="radio" name="gender" value="m" checked> 男
<input type="radio" name="gender" value="w"> 女
<!-- 复选按钮 -->
<input type="checkbox" name="hobby[]" value="reading" checked> 读书
<input type="checkbox" name="hobby[]" value="running"> 跑步

textarea 表单控件标签的基本用法:

<textarea name="introduce" cols="5" rows="10">
    <!-- ... --> 
</textarea>

select 表单控件标签的基本用法:

<select name="area">
    <option selected>--请选择--</option>
    <option value="xiamen">厦门</option>
    <option value="quanzhou">泉州</option>
    <!-- ... --> 
</select>

表单数据交互

表单数据提交后,在 PHP 中可以使用不同的超全局数组变量接收数据。

接收表单数据的基本超全局数组变量:

名称描述
$_GET["key"]接收 GET 方式提交的数据
$_POST["key"]接收 POST 方式提交的数据
$_REQUEST["key"]接收 GET 或 POST 方式提交的数据

示例:表单数据交互

入口页面(index.php):

<?php
var_dump($_REQUEST);
?>
<form method="post" action="index.php?a=param1">
    <input type="text" name="b" value="param2">
    <input type="submit" value="提交">
</form>

示例效果:


Cookie

Cookie 概述

Cookie 是网站为了辨别用户身份而存储在用户本地终端(浏览器)上的数据。

当用户第一次访问 Web 服务器时,服务器会返回给用户一些信息,这些信息都保存在浏览器的 Cookie 中,当用户再次访问服务器时,浏览器会在请求头中将 Cookie 数据发送给服务器。

服务器接收到浏览器的请求后,根据请求头中的 Cookie 数据,判断用户是否访问过,进而识别用户的身份。

尽管 Cookie 实现了浏览器与 Web 服务器之间的信息交互,但也存在缺点:

  • Cookie 被附加在 HTTP 消息中,无形中增加了数据量。
  • Cookie 在 HTTP 消息中是明文传输的,所以安全性不高,容易被窃取。
  • Cookie 存储于浏览器,可以被篡改,服务器接收到数据后必须先验证数据的合法性。
  • 浏览器限制 Cookie 的数量和大小,通常限制为 50 个,每个不超过 4KB,对于复杂的存储需求来说是不够用的。

Cookie 基本使用

使用 setcookie 函数可以创建或修改 Cookie。

setcookie 函数的基本用法:

setcookie(Cookie键, Cookie值, 有效时间戳, 生效路径, 生效域名, 是否需要在HTTPS传输);

任何从客户端发送的 Cookie 数据都会被自动存入到 $_COOKIE 超全局数组变量中,通过 $_COOKIE 变量可以获取 Cookie 数据。

$_COOKIE 超全局数组变量的基本用法:

$_COOKIE[Cookie键];

第一次使用 setcookie 函数创建 Cookie 时,$_COOKIE 超全局数组变量中没有 Cookie 数据,只有当浏览器下次请求并携带 Cookie 时,才能通过 $_COOKIE 超全局数组变量获取到 Cookie 数据。


示例:Cookie

入口页面(index.php):

<?php
// 设置Cookie
setcookie("userName", "多仔");

// 获取指定Cookie
echo $_COOKIE["userName"];

// 立即过期,删除Cookie
setcookie("userName", "", time() - 1);

// 获取所有Cookie
var_dump($_COOKIE);

示例效果:


Cookie 保存方式

Cookie 在浏览器中是根据域名分开保存的,每个 Cookie 都具有名字、值、域名、路径等信息,浏览器在发送 Cookie 时,不同主机和不同路径之间都是隔离的,路径可以向下继承。

setcookie 函数可以设置 Cookie 的访问路径和有效域名。

一个浏览器、一个域名下最多可以存放 Cookie 的数量、大小都会受到浏览器的限制,不同版本的浏览器限制不同,不建议在 Cookie 中存放太多的数据。

Session

Session 概述

Session 存储在服务器端,是用于实现数据跨脚本共享的会话技术,它的生命周期从用户访问页面开始,到与网站断开连接时结束,保存用户连续访问 Web 服务器时的相关数据。

Session 技术的实现依赖于 Cookie 技术。

当通过浏览器访问服务器时,服务器会设置 Cookie 给浏览器,同时服务器会创建一个 Session 文件来存储核心数据。

浏览器再次访问服务器时,服务器会根据 Cookie 数据打开对应的 Session 文件,获取存储的内容信息。

PHP 程序启动 Session 后,服务器会为每个浏览器创建一个供其独享的 Session 文件,每一个 Session 文件都具有唯一的会话 ID,用于标识不同的用户,会话 ID 分别保存在客户端和服务器端,客户端通过 Cookie 保存,服务器端则以文件的形式保存。

Session 基本使用

使用 session_start 函数可以启动 Session。

session_start 函数的基本用法:

session_start();

Session 启动后,可以使用 $_SESSION 全局数组操作 Session。

$_SESSION 全局数组的基本用法:

$_SESSION[Session键];

$_SESSION[Session键] = 值;

示例:Session

入口页面(index.php):

<?php
// 开启Session
session_start();

// 设置Session
$_SESSION["userName"] = "多仔";

// 获取Session
echo $_SESSION["userName"];

// 删除Session
unset($_SESSION["username"]);

// 清空Session
$_SESSION = [];

// 结束Session
session_destroy();

示例效果:


cURL

cURL 概述

cURL 扩展是一个基于 libcurl 库开发的扩展,其可以像浏览器一样完成与服务器的连接和通信,cURL 扩展支持多种传输协议,如 HTTP、HTTPS、FTP 等。

cURL 的基本函数:

名称描述
curl_init()初始化一个 cURL 会话
curl_setopt ($ch, $option, $value)设置一个 cURL 传输选项
curl_exec($ch)执行一个 cURL 会话
curl_close($ch)关闭一个 cURL 会话

cURL 的基本传输选项:

名称描述
CURLOPT_URL需要获取的 URL 地址
CURLOPT_HEADER启用时会将头文件的信息作为数据流输出
CURLOPT_HTTPHEADER设置 HTTP 头字段数组
CURLOPT_SSL_VERIFYPEER禁用后 cURL 将终止从服务端进行 SSL 验证
CURLOPT_SSL_VERIFYHOST禁用后 cURL 将终止从服务端进行 SSL 验证
CURLOPT_POST启用时会发送一个常规的 POST 请求,类似于表单
CURLOPT_POSTFIELDS使用 POST 发送的数据数组
CURLOPT_RETURNTRANSFER将 cURL 获取的响应结果直接返回,而不是直接输出
CURLOPT_REFERER设置 HTTP 请求头 Referer

cURL 基本使用

使用 cURL 可以模拟浏览器发送请求、自定义请求头、模拟表单提交等。


示例:cURL

入口页面(index.php):

<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://www.duox.dev/");
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
$respData = curl_exec($ch);
curl_close($ch);

print_r($respData);

示例效果:


]]>
0 https://www.duox.dev/post/177.html#comments https://www.duox.dev/feed/post/177.html
PHP 基础案例教程之 05-错误处理及调试 https://www.duox.dev/post/175.html https://www.duox.dev/post/175.html Sun, 25 Jan 2026 01:11:00 +0000 多仔

AI 摘要

本文系统梳理 PHP 错误处理机制:先分类解析语法、运行、逻辑、环境四类错误,再详解 E_ERROR、E_WARNING 等九种级别;继而演示通过 php.ini 或 error_reporting、ini_set 控制显示,借助 error_log 记录日志,使用 trigger_error 手动触发,以及 set_error_handler 自定义处理流程;最后介绍 Xdebug 的安装与彩色追踪调试技巧,帮助开发者快速定位问题,提升线上稳定性与开发效率。

错误处理概述

常见的错误类型

PHP 的基本错误类型:

名称描述
语法错误程序代码不符合语法规则而发生的错误,会阻止 PHP 脚本的执行
运行错误程序运行时出现的错误
逻辑错误编写程序时实现思路出现错误,不会阻止 PHP 脚本的执行,也不会显示具体的错误信息
环境错误PHP 开发环境配置问题引发的错误

常见的错误级别

PHP 中的错误分为多种类型,每种错误类型都对应不同的错误级别。

错误级别通常用常量来表示,每个错误级别对应的值都是一个整型数据,错误级别常量用于表示当前的错误等级。

PHP 的基本错误级别:

名称描述
E_ERROR1运行时的致命错误,会导致 PHP 脚本停止运行
E_WARNING2运行时警告,仅给出提示信息,PHP 脚本不会停止运行
E_PARSE4编译时语法解析错误,程序无法执行
E_NOTICE8运行时通知,表示 PHP 脚本可能会表现为错误的情况
E_STRICT2048严格语法检查,确保代码具有互用性和向前兼容性
E_ALL32767表示所有的错误和警告信息
PHP 5.4 之前不包含 E_STRICT
E_USER_ERROR256类似 E_ERROR,由用户使用 trigger_error 触发的错误
E_USER_WARNING512类似 E_WARNING,由用户使用 trigger_error 触发的错误
E_USER_NOTICE1024类似 E_NOTICE,由用户使用 trigger_error 触发的错误

错误处理方式

显示错误报告

当 PHP 脚本发生错误时,默认情况下,PHP 程序会报告错误发生的原因,并将错误信息显示到页面中。

在实际开发中,有时候需要控制是否显示错误报告,以及报告哪些级别的错误,可以通过修改 PHP 配置文件或使用错误报告函数进行控制。

通过修改 PHP 配置文件(php.ini)可以控制错误报告的显示和关闭。

PHP 配置中控制错误报告的基本配置项:

名称描述
error_reporting设置错误报告的级别
E_ALL & ~E_NOTICE 表示显示除了 E_NOTICE 级别之外的所有的错误
display_errors设置是否显示错误报告,可选 On/Off
一般情况下,在开发模式中将该配置项设置为 On,在生产模式中将该配置项设置为 Off

PHP 提供的 error_reporting 函数和 init_set 函数也可以控制错误报告的显示和关闭。


示例:显示错误报告

入口页面(index.php):

<?php
// 显示错误报告
ini_set('display_errors', 1);

// 显示所有级别的错误报告
error_reporting(E_ALL);
echo $info;

// 显示除E_WARNING之外的错误报告
error_reporting(E_ALL & ~E_WARNING);
echo $info;

示例效果:


记录错误日志

在生产环境中,一般不会将错误报告直接显示出来。

在 PHP 中,可以通过 PHP 配置文件配置日志记录,或使用错误日志记录函数来记录错误日志。

通过修改 PHP 配置文件(php.ini)可以记录错误日志。

PHP 配置中记录错误日志的基本配置项:

名称描述
log_error设置是否记录日志,可选 On/Off
error_log指定错误报告日志文件的路径

PHP 提供的 error_log 函数也可以用于记录错误日志。


示例:记录错误日志

入口页面(index.php):

<?php
error_log('error message', 3, '/Users/duozai/Desktop/php.log');

示例效果:


手动触发错误

在 PHP 中,开发者可以根据不同的需求手动触发错误。

手动触发错误的基本用法:

trigger_error(错误信息, [, E_USER_XXX错误级别]);

示例:手动触发错误

入口页面(index.php):

<?php
function divide($num1, $num2) {
    if ($num2 == 0) {
        trigger_error("除数不能为0");
        return false;
    }
    return $num1 / $num2;
}

echo divide(100, 0);

示例效果:


自定义错误处理函数

在 PHP 中,除了将错误报告记录到日志文件,还可以自定义错误处理函数,自行处理错误。

自定义错误处理的基本用法:

function 错误处理函数(错误级别, 错误信息) {
    // ...
}

set_error_handler(错误处理函数, 错误级别);

示例:自定义错误处理函数

入口页面(index.php):

<?php
function customError($errno, $errstr) {
    echo "<b>Error:</b> [$errno] $errstr";
}

set_error_handler('customError');

echo $student;

示例效果:


Xdebug 程序调试工具

获取和安装 Xdebug

Xdebug 是一个开源的 PHP 程序调试工具,使用该工具可以追踪代码出错的具体位置,根据错误信息调试程序,提高开发效率。

Xdebug 文档:https://xdebug.org/

在 IntelliJ IDEA 中,可以快速安装 Xdebug。

Xdebug 安装完成后,需要重启 PHP 相关服务后生效。

使用 Xdebug

Xdebug 会将错误信息变成彩色表格形式,并且将错误定位到具体的函数。


示例:Xdebug

入口页面(index.php):

<?php
function getFile() {
    require 'outfile.php';
}
getFile();

示例效果:


]]>
0 https://www.duox.dev/post/175.html#comments https://www.duox.dev/feed/post/175.html
PHP 基础案例教程之 04-数组 https://www.duox.dev/post/167.html https://www.duox.dev/post/167.html Fri, 23 Jan 2026 03:11:00 +0000 多仔

AI 摘要

本文系统梳理 PHP 数组核心知识:先区分索引与关联数组,再演示 array()、[]、赋值三种声明方式;继而讲解用键访问、isset 检测,foreach 遍历及 unset 删除;随后介绍联合、相等、全等等数组运算符;最后分类盘点指针、元素、排序、检索及其他高频函数,并辅以可运行示例,帮助开发者快速掌握数组的创建、操作与高效应用。

数组的基本使用

初识数组

数组类型属于数据类型中的复合类型,用于存储大批量数据。

在 PHP 中,数组分为索引数组和关联数组。

索引数组即键的数据类型为整型的数组,默认情况下,索引数组的键从 0 开始,依次递增。

关联数组即键的数据类型为字符串型的数组,通常情况下,关联数组的键和值之间有一定的业务逻辑关系,经常使用关联数组来存储具有逻辑关系的变量。

定义数组

在 PHP 中,可以通过 array 结构法、赋值法、短数组定义法来定义数组。

array 结构法定义数组的基本用法:

// 定义索引数组
$数组 = array("值", "值", "...");

// 定义关联数组
$数组 = array("键" => "值", "键" => "值", ...);

// 定义混合数组
$数组 = array("值", "值", "键" => "值", "键" => "值", ...);

// 定义二维数组
$数组 = array(
    "键" => array(...),
    ...
);

赋值法定义数组的基本用法:

$数组[] = "值";

$数组[键] = "值";

短数组定义法定义数组的基本用法:

$数组 = ["值", "值", "..."];

$数组 = array("键" => "值", "键" => "值", ...);

访问数组

在 PHP 中,可以通过键访问数组。

访问数组的基本用法:

$数组[键];

使用 isset 函数可以判断变量或数组元素是否存在。

isset 函数的基本用法:

isset($array[$key]);

示例:访问数组

入口页面(index.php):

<?php
$user = [
    "name" => "John",
    "age" => 30,
    "city" => "XiaMen"
];

print_r("数组中是否存在name:");
var_dump(isset($user["name"]));
print_r("<br>");
print_r("数组中是否存在sex:");
var_dump(isset($user["sex"]));

示例效果:


遍历数组

在 PHP 中,通常使用 foreach 语句遍历数组。

foreach 语句遍历数组的基本用法:

foreach($数组 as $键 => $值) {
    // ...
}

示例:遍历数组

入口页面(index.php):

<?php
$user = [
    "name" => "John",
    "age" => 30,
    "city" => "XiaMen"
];

foreach ($user as $key => $value) {
    echo "$key: $value<br>";
}

示例效果:


删除数组元素

在 PHP 中,unset 函数可以删除数组中的元素。

索引数组元素被删除后,数组中的数字键名不会自动填补空缺的数字。

unset 函数的基本用法:

unset($array[$key]);

示例:删除数组元素

入口页面(index.php):

<?php
$user = [
    "name" => "John",
    "age" => 30,
    "city" => "XiaMen"
];

print_r("删除元素前的数组:");
var_dump($user);

unset($user["age"]);

print_r("<br>删除元素后的数组:");
var_dump($user);

示例效果:


数组运算符

PHP 提供了数组运算符对数组进行运算。

PHP 的基本数组运算符:

名称描述
+联合,$a+$b 即 $a 和 $b 的联合
==相等,$a == $b 即 $a 和 $b 有相同的键值对,则为 true
===全等,$a === $b 即 $a 和 $b 有相同的键值对,且顺序和类型都相同,则为 true
!=不等,$a != $b 即 $a 不等于 $b,则为 true
<>不等,$a != $b 即 $a 不等于 $b,则为 true
!==不全等,$a != $b 即 $a 不全等于 $b,则为 true

示例:数组运算符

入口页面(index.php):

<?php
$num = [1, 2];
$str = ["a", "b", "c"];

$temp = $num + $str;
print_r("数组联合的结果:");
var_dump($temp);

示例效果:


常用的数组函数

指针操作函数

数组指针用于指向数组中的某个元素,默认指向数组的第 1 个元素,通过移动或改变指针的位置,可以访问数组中的任意元素。

指针操作的基本函数:

名称描述
key($array)获取当前指针指向数组元素的键
current($array)获取当前指针指向数组元素的值
next($array)将数组中的指针向后移动一位
prev($array)将数组中的指针向前移动一位
end($array)将数组的指针指向最后一个数组元素
reset($array)将数组的指针指向第一个数组元素

示例:指针操作函数

入口页面(index.php):

<?php
$array = ["a", "b", "c", "d"];

print_r("当前指针所在的键是:".key($array).",所在的值是:".current($array));
print_r("<br>");

next($array);
print_r("指针向后移动,当前指针所在的键是:".key($array).",所在的值是:".current($array));
print_r("<br>");

end($array);
print_r("指针移动到最后,当前指针所在的键是:".key($array).",所在的值是:".current($array));
print_r("<br>");

prev($array);
print_r("指针向前移动,当前指针所在的键是:".key($array).",所在的值是:".current($array));
print_r("<br>");

reset($array);
print_r("指针移动到最前,当前指针所在的键是:".key($array).",所在的值是:".current($array));

示例效果:


元素操作函数

PHP 提供了一些针对数组元素的操作函数。

元素操作的基本函数:

名称描述
array_shift($array)删除数组开头的元素
array_pop($array)删除数组末尾的元素
array_unshift($array, $value1, ...)在数组开头添加元素
array_push($array, $value1, ...)在数组末尾添加元素
array_unique($array)去除数组中重复的值
array_slice($array, $start, $length)从数组中截取出部分数组
array_splice($array1, $start, $length, $array2)去掉数组中的一部分元素,并用其他值代替

示例:元素操作函数

入口页面(index.php):

<?php
$array = ["a", "b", "c", "d"];

print_r("当前数组:");
var_dump($array);
print_r("<br>");

array_shift($array);
print_r("删除数组开头的元素后的结果:");
var_dump($array);
print_r("<br>");

array_pop($array);
print_r("删除数组结尾的元素后的结果:");
var_dump($array);
print_r("<br>");

array_unshift($array, "e");
print_r("在数组开头添加元素后的结果:");
var_dump($array);
print_r("<br>");

array_push($array, "f");
print_r("在数组结尾添加元素后的结果:");
var_dump($array);

示例效果:


数组排序函数

PHP 内置了数组排序函数,可以很方便地实现对数组的排序。

数组排序的基本函数:

名称描述
sort($array)对数组进行升序排序
rsort($array)对数组进行降序排序
ksort($array)对数组按照键名升序排序
krsort($array)对数组按照键名降序排序
asort($array)对关联数组按照键值进行升序排序
arsort($array)对关联数组按照键值进行倒序排序
shuffle($array)将数组打乱
array_reverse($array)以相反的顺序返回数组

示例:数组排序函数

入口页面(index.php):

<?php
$array = ["c", "b", "d", "a"];

print_r("当前数组:");
var_dump($array);
print_r("<br>");

sort($array);
print_r("数组升序排序后的结果:");
var_dump($array);
print_r("<br>");

rsort($array);
print_r("数组降序排序后的结果:");
var_dump($array);
print_r("<br>");

shuffle($array);
print_r("数组打乱后的结果:");
var_dump($array);

示例效果:


数组检索函数

PHP 内置了数组检索函数,可以很方便地对数组中的元素进行查找。

数组检索的基本函数:

名称描述
in_array($value, $array)检查数组中是否存在指定的值
array_search($value, $array)搜索数组中给定的值并返回键名
array_key_exists($key, $array)检查指定的键名是否存在于数组中

示例:数组检索函数

入口页面(index.php):

<?php
$array = ["c", "b", "d", "a"];

print_r("数组中是否存在元素b:");
var_dump(in_array("b", $array));
print_r("<br>");

print_r("数组中元素c的键名是:");
var_dump(array_search("c", $array));
print_r("<br>");

print_r("数组中是否存在键名为9的元素:");
var_dump(array_key_exists("9", $array));

示例效果:


其他数组函数

PHP 提供了很多其他常用的数组函数。

数组的其他基本函数:

名称描述
count($array)计算数组中元素的个数
range($min, $max, $step)创建包含指定范围单元的数组
array_keys($array)返回数组中所有的键名
array_values($array)返回数组中所有的值
array_rand($array, $num)返回数组中一个或多个随机的键
array_merge($array1, $array2, ...)把一个或多个数组合并为一个数组
array_chunk($array, $size)把一个数组分割为新的数组块
array_sum($array)返回数组中值的和
array_replace($array1, $array2, ...)使用后面数组的值替换第一个数组的值

示例:其他数组函数

入口页面(index.php):

<?php
$array = ["c", "b", "d", "a"];

print_r("数组中的元素个数:".count($array));
print_r("<br>");

print_r("数组中所有的键名:");
var_dump(array_keys($array));
print_r("<br>");

print_r("数组中所有的值:");
var_dump(array_values($array));

示例效果:


]]>
0 https://www.duox.dev/post/167.html#comments https://www.duox.dev/feed/post/167.html
PHP 基础案例教程之 03-函数 https://www.duox.dev/post/164.html https://www.duox.dev/post/164.html Thu, 22 Jan 2026 09:01:00 +0000 多仔

AI 摘要

本文系统梳理 PHP 函数核心知识:从定义、无参/有参、引用传参、默认值、类型声明到可变参数与返回类型;解析作用域、嵌套与递归;展示静态、可变、回调、匿名函数高级技巧;并精选字符串、数学、时间日期等常用内置函数,辅以示例,助开发者快速掌握高效复用代码的完整技能。

函数的定义与调用

初识函数

在程序开发中,通常通过定义一个函数来实现特定的功能,从而使代码可以被复用,避免重复编写相同功能的代码。

函数的基本用法:

function 函数名([$参数1, $参数2]) {
    函数体
    [return 函数返回值;]
}

对于函数而言,设置参数的方式不同,其调用方式也不同。

无参函数

定义无参数的函数时,不需要传递参数,函数体用于完成指定的功能。


示例:无参函数

入口页面(index.php):

<?php
function sout() {
    return "Hello PHP";
}

echo sout();

示例效果:


有参函数

定义有参数的函数时,函数内部会根据用户传递的参数进行操作。


示例:有参函数

入口页面(index.php):

<?php
function add($a, $b) {
    return $a + $b;
}

echo "1 + 2 = ".add(1, 2);

示例效果:


引用传参

当需要函数修改它的参数值时,需通过函数参数的引用传递来实现,即引用传参。

在函数中使用引用传参的基本用法:

function 函数名(&$参数) {
    函数体
    [return 函数返回值;]
}

示例:引用传参

入口页面(index.php):

<?php
function extra(&$message) {
    $message = $message." PHP";
}

$message = "hello";

extra($message);

echo $message;

示例效果:


参数默认值

在设置函数参数时,还可以为其指定默认值,即可选参数,当调用者未传递该参数时,函数将使用默认值进行操作。

指定函数的参数默认值的基本用法:

function 函数名($参数 = 参数默认值) {
    函数体
    [return 函数返回值;]
}

示例:参数默认值

入口页面(index.php):

<?php
function say($name, $message = "Hello~") {
    return $name . " say " . $message;
}

echo say("Tom");

示例效果:


参数类型

在自定义函数时,可以指定参数具体是哪种数据类型。

  • 在 PHP 5 中不能直接指定诸如整数、浮点数、字符串等基本数据类型作为参数类型。
  • 在 PHP 7 中,类型声明得到了显著增强,可以更精确地指定各种基本数据类型。

一般情况下,指定参数类型的方式是弱类型参数设置,在调用函数时,如果传递的参数不是指定的类型,程序会将其强制转换成指定类型再进行操作。

设置函数的弱类型参数的基本用法:

function 函数名(参数类型 $参数) {
    函数体
    [return 函数返回值;]
}

示例:参数类型

入口页面(index.php):

<?php
function add(int $a, int $b) {
    return $a + $b;
}

echo "2.6 + 3.8 = ".add(2.6, 3.8);

示例效果:


在 PHP 中,还可以将函数参数设置为强类型参数,当用户传递的参数类型不符合函数的定义时,程序会报错提醒。

设置函数的强类型参数的基本用法:

declare(strict_types = 1);
function 函数名(参数类型 $参数) {
    函数体
    [return 函数返回值;]
}

示例:设置函数的强类型参数

入口页面(index.php):

<?php
declare(strict_types = 1);
function add(int $a, int $b) {
    return $a + $b;
}

echo "2.6 + 3.8 = ".add(2.6, 3.8);

示例效果:


可变参数列表

从 PHP 5.6 及以上版本开始,在定义函数时,可以指定可变参数列表,即函数可以接受不定数量的参数。

指定函数的可变参数列表的基本用法:

function 函数名(...$参数) {
    函数体
    [return 函数返回值;]
}

在指定函数的可变参数列表时,需要注意:

  • 可变参数列表只能用在参数列表的末尾。
  • 可变参数列表的数量可以为 0,但不能省略。
  • 在使用可变参数列表时,函数会自动将参数转化为数组,可以使用数组相关的函数来操作这些参数。

示例:可变参数列表

入口页面(index.php):

<?php
function num(...$num) {
    echo var_dump($num);
}

echo num(1, 2, 3, 4, 5, 6, 7);

示例效果:


函数返回值类型

从 PHP 7 开始,引入了对函数返回值类型声明的强大支持,允许明确指定函数返回的数据类型。

指定函数返回值类型的基本用法:

declare(strict_types = 1);
function 函数名(参数类型 $参数) : 返回值类型 {
    函数体
    [return 函数返回值;]
}

示例:函数返回值类型

入口页面(index.php):

<?php
declare(strict_types = 1);
function returnIntValue(int $value) : int {
    // int + float = float
    return $value + 1.0;
}

echo returnIntValue(5);

示例效果:


函数中变量的作用域

变量只有在其作用范围内才可以被使用,这个作用范围称为变量的作用域。

  • 在函数中定义的变量称为局部变量,在函数外定义的变量称为全局变量。
  • 默认情况下,在函数中不能使用全局变量。
  • 局部变量的改变,不会对全局变量有任何影响。

示例:函数中变量的作用域

入口页面(index.php):

<?php
$sum = 0;

function test() {
    $sum = 36;
    return $sum;
}

echo 'test() => '.test();
echo "<br>";
echo '$sum => '.$sum;

示例效果:


若要在函数中使用全局变量,可以使用 global 关键字或超全局变量 $GLOBALS。

global 关键字的基本用法:

function 函数名() {
    global $全局变量名;
}

超全局变量 $GLOBALS 的基本用法:

function 函数名() {
    $GLOBALS['全局变量名'];
}

示例:全局变量

入口页面(index.php):

<?php
$sum1 = 0;
$sum2 = 100;

function test() {
    global $sum1;
    echo '全局变量 $sum1 => '.$sum1;

    echo "<br>";

    echo '全局变量 $sum2 => '.$GLOBALS['sum2'];
}

test();

示例效果:


函数的嵌套调用

嵌套调用

嵌套调用是指在调用一个函数的过程中,调用另一个函数。


示例:嵌套调用

入口页面(index.php):

<?php
function sum($sub1, $sub2) {
    return $sub1 + $sub2;
}

function avg($sub1, $sub2) {
    $sum = sum($sub1, $sub2);
    return $sum / 2;
}

echo avg(92, 90);
echo "<br>";
echo avg(78, 56);

示例效果:


递归调用

递归调用时函数嵌套中的一种特殊的调用,是指函数在其函数题内调用自身的过程。


示例:递归调用

入口页面(index.php):

<?php
function factorial($n) {
    if ($n == 0) {
        return 1;
    } else {
        return $n * factorial($n - 1);
    }
}

echo factorial(5);

示例效果:


函数的高级应用

静态变量

在 PHP 函数中,执行完函数后,在函数中定义的变量会被释放或者被重新赋值,若想在函数执行完成后依然保留局部变量的值,可以使用静态变量。

静态变量的基本用法:

static $变量名 = 变量值;

示例:静态变量

入口页面(index.php):

<?php
function num1() {
    $num = 0;
    $num++;

    // num1函数中的变量$num在每一次调用函数时都会重新被赋值
    return $num;
}

function num2() {
    static $num = 0;    // 静态变量
    $num++;

    // num2函数中定义了静态变量,变量$num在每一次调用函数时不会重新被赋值
    // 重复调用num2函数,变量$num自增
    return $num;
}

for($i = 0; $i < 5; $i++) {
    echo num1().", ";
}

echo "<br>";

for($i = 0; $i < 5; $i++) {
    echo num2().", ";
}

示例效果:


可变函数

可变函数就是将一个变量变成一个函数的形式,PHP 会自动寻找与变量值同名的函数,并且尝试执行它。

可变函数的基本用法:

$变量名 = 变量值;
$变量名();

在使用可变函数时,需要注意:

  • 变量值可以是用户自定义的函数名称,也可以是 PHP 内置的函数名称,但是变量值必须是实际存在的函数的名称。
  • 使用可变函数可以增加程序的灵活性,但是滥用可变函数会降低 PHP 代码的可读性。

示例:可变函数

入口页面(index.php):

<?php
function test() {
    echo "Hello PHP";
}

$functionName = "test";

// $functionName() = test()
$functionName();

示例效果:


回调函数

回调函数是指将一个函数作为参数传递给另一个函数,然后在适当的时候被调用执行。


示例:回调函数

入口页面(index.php):

<?php
function sum($a, $b) {
    return $a + $b;
}

// call_user_funch函数可以接受用户自定义的回调函数作为参数
// 参数1:回调函数名
// 参数...:传递给回调函数的参数
// call_user_func函数执行后,将调用sum函数并返回执行结果
echo call_user_func('sum', 1, 2);

示例效果:


回调函数具有很大的灵活性和实用性,可以用于数据排序、数组过滤、文件处理等场景。

匿名函数

匿名函数就是没有函数名称的函数,也称为闭包函数,其强调的是函数本身没有名称,需要通过变量来引用和使用。

匿名函数的基本用法:

$变量名 = function() {
    函数体
    [return 函数返回值;]
};

$变量名();

示例:匿名函数

入口页面(index.php):

<?php
$sum = function ($a, $b) {
    return $a + $b;
};

echo $sum(1, 2);

示例效果:


若要在匿名函数中使用外部的变量,可以使用 use 关键字来实现。

匿名函数使用外部变量的基本用法:

$变量名 = function() use ($变量名) {
    函数体
    [return 函数返回值;]
};

$变量名();

示例:匿名函数使用外部变量

入口页面(index.php):

<?php
$c = 100;

$sum = function ($a, $b) use($c) {
    return $a + $b + $c;
};

echo $sum(1, 2);

示例效果:


匿名函数还可以作为函数的参数传递,实现回调函数。


示例:匿名函数作为函数的参数传递

入口页面(index.php):

<?php
function calculate($a, $b, $func) {
    // 调用回调函数func
    return $func($a, $b);
}

// 调用calculate函数时,传入一个回调函数
echo calculate(10, 20, function ($a, $b) {
    return $a + $b;
});

echo "<br>";

echo calculate(10, 20, function ($a, $b) {
    return $a * $b;
});

示例效果:


PHP 内置函数

字符串函数

字符串的基本函数:

名称描述
strlen($string)获取字符串的长度,一个英文字符、一个空格的长度均为 1
UTF-8 字符集的中文字符长度为 3
GBK 字符集的中文字符长度为 2
mb_strlen($string)获取字符串的长度,1 个中文字符长度为 1
在使用该函数时,需确保 PHP 配置文件开启 mbstring 扩展
strpos($string, $find)在字符串中查找另一个字符串首次出现的位置
strrpos($string, $find)在字符串中查找另一个字符串最后一次出现的位置
str_replace($find, $replace, $string)替换字符串中的一些字符
substr_replace($string, $replace, $start)替换字符串的一部分
substr($string, $start, $length)截取字符串的一部分
explode($separator, $string)将字符串按照指定的分隔符分割成数组
implode($separator, $array)将数组元素连接成一个字符串
trim($string, $charlist)去除字符串两端的空白字符或其他预定义字符
str_repeat($string, $repeat)重复指定的字符串指定的次数
strcmp($string1, $string2)比较两个字符串是否相等
该函数二进制安全,且区分大小写,函数返回 0 即字符串相等

示例:字符串函数

入口页面(index.php):

<div>strlen+mb_strlen获取字符串长度:</div>
<?php $str1 = "多仔的PHP笔记"; ?>
<div>$str1:<?php echo $str1; ?></div>
<div>$str1的长度是:<?php echo strlen($str1); ?></div>
<div>$str1的长度是:<?php echo mb_strlen($str1); ?></div>

<br>

<div>strpos+strrpos+substr截取字符串:</div>
<?php $str2 = "/Users/duozai/Desktop/demo.png" ?>
<div>$str2:<?php echo $str2; ?></div>
<div>"duozai" 第一次出现的位置:<?php echo strpos($str2, "duozai"); ?></div>
<div>"/" 最后一次出现的位置:<?php echo strrpos($str2, "/"); ?></div>
<div>截取文件名:<?php echo substr($str2, strrpos($str2, "/") + 1); ?></div>

<br>

<div>str_replace+substr_replace+str_repeat替换字符串:</div>
<?php $str3 = "+00 13200077700" ?>
<div>$str3:<?php echo $str3; ?></div>
<div>将 "+00" 替换成 "+86" :<?php echo str_replace("+00", "+86", $str3); ?></div>
<div>将手机号中间四位替换成*:<?php echo substr_replace($str3, str_repeat("*", 4), 7, 4); ?></div>

<br>

<div>explode+implode转换数组与字符串:</div>
<?php $str4 = "1,2,3,4,5,6,7" ?>
<div>$str4:<?php echo $str4; ?></div>
<div>将字符串转换成数组:<?php var_dump(explode(",", $str4)); ?></div>
<div>将数组转换成字符串:<?php echo implode("-", explode(",", $str4)); ?></div>

<br>

<div>trim去除字符串两端符号</div>
<?php $str5 = ",1,2,3,4,5,6,7," ?>
<div>$str5:<?php echo $str5; ?></div>
<div>去除两端逗号:<?php echo trim($str5, ","); ?></div>

<br>

<div>strcmp判断字符串是否相等</div>
<?php $str6 = "hello"; ?>
<?php $str7 = "Hello"; ?>
<div>$str6:<?php echo $str6; ?></div>
<div>$str7:<?php echo $str7; ?></div>
<div>$str6与$str7是否相等:<?php echo strcmp($str6, $str7); ?></div>

示例效果:


数学函数

数学的基本函数:

名称描述
abs($number)返回一个数的绝对值
ceil($number)返回一个数向上取最接近的整数
floor($number)返回一个数向下取最接近的整数
round($number)返回一个数的四舍五入的整数
min(...$value)返回一个数组中的最小值,或者几个指定值中的最小值
max(...$value)返回一个数组中的最大值,或者几个指定值中的最大值
pi()返回圆周率的值
pow($x, $y)返回一个数的指定次幂
sqrt($number)返回一个数的平方根
rand($min, $max)返回一个随机整数

示例:数学函数

入口页面(index.php):

<div>-123的绝对值是<?php echo abs(-123); ?></div>
<div>19.8向上取整是<?php echo ceil(19.8); ?></div>
<div>19.8向下取整是<?php echo floor(19.8); ?></div>
<div>19.8四舍五入是<?php echo round(19.8); ?></div>
<div>2, 4, 8的最小值是<?php echo min(2, 4, 8); ?></div>
<div>2, 4, 8的最大值是<?php echo max(2, 4, 8); ?></div>
<div>圆周率的值是<?php echo pi(); ?></div>
<div>2的3次方是<?php echo pow(2, 3); ?></div>
<div>9的平方根是<?php echo sqrt(9); ?></div>
<div>1-100的随机数是<?php echo rand(1, 100); ?></div>

示例效果:


时间和日期函数

PHP 通过 UNIX 时间戳处理时间,UNIX 时间戳定义了从格林尼治时间 1970 年 1 月 1 日 0 时 0 分 0 秒起至当前时间的总秒数。

时间和日期的基本函数:

名称描述
time()获取当前的 UNIX 时间戳
date($format[, $timestamp])格式化一个本地时间或日期
mktime($hour, $minute, $second, $month, $day, $year)获取指定日期的 UNIX 时间戳
strtotime($string)将字符串转换成 UNIX 时间戳
microtime()获取当前 UNIX 时间戳和微秒数

日期时间格式的基本字符:

名称 描述
Y4 位数字表示的完整年份
y2 位数字表示的年份
L是否为闰年,1 是/0 否
m数字表示的月份,有前导 0,返回值 01-12
n数字表示的月份,无前导 0,返回值 1-12
t给定月份所应有的天数,返回值 28-31
F完整英文单词表示的月份
M三个字母缩写表示的月份
d月份中的第几天,有前导 0,返回值 01-31
j月份中的第几天,无前导 0,返回值 1-31
时间g小时,12 小时制,无前导 0,返回值 1-12
h小时,12 小时制,有前导 0,返回值 01-12
G小时,24 小时制,无前导 0,返回值 0-23
H小时,24 小时制,有前导 0,返回值 00-23
i分钟,有前导 0,返回值 00-59
s秒数,有前导 0,返回值 00-59
星期N星期几,返回值 1(星期一)-7(星期日)
w星期几,返回 0(星期日)-6(星期六)
D三个字母缩写表示的星期
l完整英文单词表示的星期

示例:时间和日期函数

入口页面(index.php):

<div>当前时间戳:<?php echo time(); ?></div>
<div>当前时间戳和微秒:<?php echo microtime(); ?></div>
<div>当前日期:<?php echo date('Y-m-d H:i:s'); ?></div>
<div>2024年07月11日 08:00:00的时间戳:<?php echo mktime(8, 0, 0, 7, 11, 2024); ?></div>
<div>2024年07月11日 08:00:00的时间戳:<?php echo strtotime('2024-07-11 08:00:00'); ?></div>

示例效果:


]]>
0 https://www.duox.dev/post/164.html#comments https://www.duox.dev/feed/post/164.html
PHP 基础案例教程之 02-PHP 语法基础 https://www.duox.dev/post/162.html https://www.duox.dev/post/162.html Tue, 20 Jan 2026 08:16:00 +0000 多仔

AI 摘要

本文系统梳理 PHP 语法基础:从标准/短标记、注释与输出语句入手,详解变量传值与引用赋值、可变变量、常量、预定义常量及表达式;完整介绍标量、复合、特殊三大类型,字符串单双引号、heredoc/nowdoc 差异,is_xxx 检测、自动与强制类型转换;覆盖算术、比较、三元、逻辑、位运算等运算符及 if、switch、while、for、替代语法流程控制;最后说明 include/require 与 *_once 文件包含机制,为后续开发奠定扎实语法根基。

基本语法

PHP 标记

PHP 代码可以嵌入 HTML 中使用,为了区分 PHP 代码和 HTML 代码,需要使用 PHP 标记对 PHP 代码进行标识,PHP 的标记分为标准标记和短标记。

PHP 标记的基本用法:

<?php 代码块 ?>
<? 代码块 ?>    // 不推荐使用,需要在php.ini中启用short_open_tag
<?= 输出内容 ?>

示例:PHP 标记

入口页面(index.php):

<h1><?php echo "Hello PHP!" ?></h1>
<h1><?= "Hello PHP!" ?></h1>

示例效果:


在 PHP 标记后面,如果没有除 PHP 以外的其他代码,标记末尾的 ?> 符号可以省略。

注释

在 PHP 开发中,为了方便开发人员阅读和维护代码,可以添加注释对代码进行解释说明。

单行注释的基本用法:

// ...
# ...

多行注释的基本用法:

/*
    ....
*/

输出语句

PHP 提供了一系列的输出语句,常用的输出语句有 echo、print、print_r、var_dump 等。

echo 输出语句用于输出字符串,如果输出其他类型的数据,会自动转换成字符串。

echo 输出语句的基本用法:

echo "...";
echo "...", "...";

print 输出语句与 echo 输出语句类似,但 print 输出语句只能输出一个数据。

print 输出语句的基本用法:

print "...";

print_r 输出语句可以输出任意类型的数据,如字符串、数组等。

print_r 输出语句的基本用法:

print_r("...");

var_dump 输出语句不仅可以输出一个或多个任意类型的数据,还可以获取数据的类型和元素值。

var_dump 输出语句的基本用法:

var_dump("...");
var_dump("...", "...");

示例:输出语句

入口页面(index.php):

<?php
echo "Hello echo<br>";

print "Hello print<br>";

print_r("Hello print_r<br>");

var_dump("Hello var_dump")

示例效果:


标识符

定义标识符(如变量名、函数名、类名、方法名等)需要遵循一定的规则:

  • 标识符只能由字母、数字、下划线以及 0x80-0xff 范围内(十六进制数值范围)的字符组成。
  • 标识符不能以数字开头。
  • 标识符用作变量名时,区分大小写。

关键字

在使用关键字时,需要注意关键字不能作为常量、函数名或类名使用。

随着 PHP 版本的更新,关键字也在不断变化,可以通过查阅 PHP 官方手册来获取最新的关键字列表。

变量、常量和表达式

变量

PHP 是弱类型语言,变量不需要实现声明,就可以直接进行赋值使用。

PHP 变量赋值分为传值赋值和引用赋值。

传值赋值是将等号右边的数据赋值给左边的变量。

传值赋值的基本用法:

$变量名 = 变量值;

示例:传值赋值

入口页面(index.php):

<?php
$userName = "多仔";
$age = 18;

echo "姓名:".$userName;   // 使用.号拼接字符串
echo "<br>";
echo "年龄:".$age;

示例效果:


引用赋值时,如果其中的一个变量的值发生改变,则另一个变量的值也会发生改变。

引用赋值的基本用法:

$变量名 = &$要引用的变量名;

示例:引用赋值

入口页面(index.php):

<?php
$userName = "多仔";
$age = 18;

echo "姓名:".$userName;
echo "<br>";
echo "年龄:".$age;
echo "<br>";

// 引用赋值
$newAge = &$age;

// 修改变量$age的值
$age = 81;

// 变量$newAge的值随着变量$age的改变而改变
echo "年龄:".$newAge;

示例效果:


可变变量

PHP 提供了可变变量,可以在开发时动态地改变一个变量的名称,将另一个变量的值作为该变量的名称。

在使用可变变量时,变量的值要符合标识符规则,避免出现非法变量名的情况。

可变变量的基本用法:

$变量名 = $$变量名;

示例:可变变量

入口页面(index.php):

<?php
$userName = "多仔";
$age = 18;

$variableName = "userName";

// 相当于输出$userName
echo "姓名:".$$variableName;

示例效果:


常量

在 PHP 中,常量的值始终保持不变,常量一旦被定义就不能被修改或重新定义。

常量的命名遵循标识符的命名规则,习惯上总是使用大写字母定义常量名称。

在 PHP 中定义常量,可以使用 define 函数或 const 关键字。

define 函数的基本用法:

define(常量名, 常量值);

const 关键字的基本用法:

const 常量名 = 常量值;

示例:常量

入口页面(index.php):

<?php
define("HOST", "localhost");
define("PORT", "3306");

const USER = "root";
const PASSWORD = "root";

echo "HOST=", HOST, "<br>";
echo "PORT=", PORT, "<br>";
echo "USER=", USER, "<br>";
echo "PASSWORD=", PASSWORD, "<br>";

示例效果:


预定义常量

PHP 提供了预先定义好的常量来获取 PHP 中的信息。

PHP 中的基本预定义常量:

名称描述
FILE获取 PHP 文件的完整路径
LINE获取 PHP 文件中当前代码的行号
PHP_VERSION获取 PHP 的版本信息
PHP_OS获取当前 PHP 环境的操作系统类型
PHP_INT_MAX获取当前 PHP 环境中整型数的最大值
PHP_INT_SIZE获取 PHP 中整型数的字长
TRUE该常量是一个真值(true)
FALSE该常量是一个假值(false)
NULL该常量是一个空值(null)
E_ERROR表示运行时的致命性错误,值为 1
E_WARNING表示运行时的警告错误,值为 2
E_PARSE表示编译时的解析错误,值为 4
E_NOTICE表示编译时的题型信息,值为 8

示例:预定义常量

入口页面(index.php):

<?php
echo "PHP版本号:", PHP_VERSION, "<br>";
echo "PHP文件路径:", __FILE__, "<br>";

示例效果:


表达式

表达式是 PHP 中非常重要的基石,任何有值的内容都可以理解为表达式。

PHP 的基本表达式:

<?php
$a = 1;
echo $a + 1;
$a = $a + 4;
echo $a + $b;
echo PHP_VERSION;

数据类型

常用数据类型

PHP 支持 3 类数据类型,8 种数据类型。

名称
描述
标量类型bool布尔型值为 true/false,且不分大小写
int整型可用八进制、十进制、十六进制表示
在不同位数的操作系统中,取值范围不一样
当定义的整型数值大于系统的整型数所能表示的最大范围时,将会被自动转换为浮点数
float浮点型可用标准格式和科学计数法表示
string字符串型可用单引号、双引号、heredoc、nowdoc 表示
复合类型array数组支持单维和多维数组
object对象可以用来表示具体的实体或抽象的概念
特殊类型resource资源用于表示对外部资源的引用
外部资源可以是文件、图像、数据库连接等
NULL空值表示一个变量没有被赋予任何值

字符串数据类型

字符串是由连续的字母、数字或字符组成的字符序列。

在 PHP 中,可以使用单引号、双引号表示字符串。

  • 单引号字符串中的变量不会被解析。
  • 双引号字符串中的变量会被解析。

示例:字符串数据类型

入口页面(index.php):

<?php
$number = 100;

echo '$number=', $number;
echo '<br>';
echo "$number=", $number;

示例效果:


当双引号字符串中包含变量时,可能会出现变量与字符串混淆的问题。

为了让 PHP 识别变量,可以使用 {} 符号将变量包裹起来,{} 符号中的内容会被识别成具体的变量。


示例:使用 {} 识别变量

入口页面(index.php):

<?php
$ap = "test";

// 将$ap识别成一个变量
echo "{$ap}ple";

示例效果:


heredoc 和 nowdoc

在 PHP 中,heredoc 和 nowdoc 是两种特殊的字符串表示方式。

  • heredoc 允许在其中进行变量解析和使用特殊字符。
  • heredoc 中,位于开始标记和结束标记之间的变量可以被正常解析,变量不需要用连接符来拼接。
  • nowdoc 类似于 heredoc ,但它不会解析变量和特殊字符。
  • nowdoc 定义的变量不会被解析,会被原样输出。

使用 heredoc 定义字符串数据的基本用法:

>>>EOD
// ...
EOD;

使用 nowdoc 定义字符串数据的基本用法:

>>>'EOD'
// ...
EOD;

在使用 heredoc 和 nowdoc 时,需要注意:

  • 开始标记和结束标记使用相同的字符串,通常以大写字母来写。
  • 开始标记后不能出现空格或多余的字符。
  • 结束标记必须顶头写,不能有缩进和空格,且在结束标记末尾要有分号。

heredoc 和 nowdoc 在处理大段的文本内容时非常有用,能使代码更加清晰易读。


示例:heredoc 和 nowdoc

入口页面(index.php):

<?php
$name = "PHP";

$heredoc = <<<EOD
    <div>
        <h3>$name 是世界上最好的语言</h3>
    </div>
EOD;
echo $heredoc;

$nowdoc = <<<'EOD'
    <div>
        <h3>$name 是世界上最好的语言</h3>
    </div>
EOD;
echo $nowdoc;

示例效果:


数据类型检测

为了检测数据类型是否符合预期,PHP 提供了一组 is_xxx 形式的内置函数用于检测数据类型。

数据类型检测的基本函数:

名称描述
is_bool($var)是否是布尔型
is_string($var)是否是字符串型
is_float($var)是否是浮点型
is_int($var)是否是整型
is_null($var)是否是空值
is_array($var)是否是数组
is_resource($var)是否是资源型
is_object($var)
是否是对象型
is_numeric($var)是否为数字或由数字组成的字符串

示例:数据类型检测

入口页面(index.php):

<?php
var_dump(is_bool("1"));
echo "<br>";

var_dump(is_numeric("1"));
echo "<br>";

var_dump(is_string("1"));

示例效果:


自动数据类型转换

自动数据类型转换是指当参数与运算的两个数据类型不同时,PHP 会自动转换成相同的类型再进行运算。

自动转换成布尔型时:

  • 整型 0、浮点型 0、空字符串、字符串 0 转换成布尔型时,都会被转换成 false。
  • 其他数据转换成布尔型时,都会被转换成 true。

示例:自动转换成布尔型

入口页面(index.php):

<?php
var_dump(0 == false);
echo "<br>";

var_dump(0.0 == false);
echo "<br>";

var_dump('' == false);
echo "<br>";

var_dump("0" == false);

示例效果:


自动转换成整型时:

  • 当浮点型数据转换成整型时,将直接对浮点数向下取整。
  • 当布尔型数据转换成整型时,true 会被转换成整型 1,false 会被转换成整型 0。
  • 在 PHP 8 以前,当字符串型数据转换成整型时,若字符串以数字开始,则使用该数字,否则转换为 0。
  • 自 PHP 8 起,如果无法解释运算符前后的其中一个运算对象,则会抛出 TypeError。

示例:自动转换成整型

入口页面(index.php):

<?php
var_dump(true + 1);
echo "<br>";

var_dump(false + 1);
echo "<br>";

var_dump("101PHP" + 1);
echo "<br>";

var_dump("PHP101" + 1);

示例效果:


自动转换成字符串型时:

  • 当布尔值数据转换成字符串型时,true 会被转换成字符串型 1,false 会被转换成空字符串。
  • 当整型或浮点型数据转换成字符串型时,直接将数字转换成字符串形式。

示例:自动转换成字符串型

入口页面(index.php):

<?php
var_dump("true => " . true);
echo "<br>";

var_dump("false => " . false);
echo "<br>";

var_dump(101 . "PHP");
echo "<br>";

var_dump(3.14 . "PHP");

示例效果:


强制数据类型转换

强制数据类型转换是将某个数据或变量转换成想要的数据类型。

强制数据类型转换的基本用法:

(目标数据类型) 变量或数据

示例:强制数据类型转换

入口页面(index.php):

<?php
var_dump((boolean) -1);
echo "<br>";

var_dump((integer) "hello");
echo "<br>";

var_dump((float)false);
echo "<br>";

var_dump((string)101);

示例效果:


数据类型转换函数

PHP 提供了一系列数据类型转换函数,用于获取变量或数据的指定类型的值。

数据类型转换的基本函数:

名称描述
strval($var)获取字符串型的值
intval($var)获取整型的值
floatval($var)获取浮点型的值
boolval($var)获取布尔型的值

示例:数据类型转换

入口页面(index.php):

<?php
var_dump(strval(false));
echo "<br>";

var_dump(intval("101"));
echo "<br>";

var_dump(floatval("0"));
echo "<br>";

var_dump(boolval("1"));

示例效果:


运算符

算数运算符

PHP 的基本算数运算符:

运算符描述运算符作用
+-
*/
%取模**幂运算

赋值运算符

PHP 的基本赋值运算符:

运算符描述运算符描述
=赋值+=加并赋值
-=减并赋值*=乘并赋值
/=除并赋值%取模并赋值
.=连接并赋值**=幂运算并赋值

比较运算符

PHP 的基本比较运算符:

运算符描述运算符描述
==等于!=不等于
<>不等于===全等
!==不全等>大于
>=大于等于<小于
<=小于等于

使用 PHP 的比较运算符时需要注意:

  • 对数据类型不相同对两个数据进行比较时,PHP 会自动将其转换成类型相同的数据再进行比较。
  • === 和 !== 运算符在进行比较时,不仅要比较数值是否相等,还要比较数据类型是否相同。
  • == 和 != 运算符在进行比较时,只比较数值是否相等。

三元运算符

三元运算符即三目运算符,用于实现简单的条件判断,根据条件表达式的结果执行不同的表达式。

三元运算符的基本用法:

条件表达式 ? 条件表达式成立时执行 : 条件表达式不成立时执行

逻辑运算符

PHP 的基本逻辑运算符:

运算符描述运算符描述
&&
!xor异或
andor

递增/递减运算符

PHP 基本的递增/递减运算符:

运算符描述运算符描述
++递增--递减

使用 PHP 的递增/递减运算符时需要注意:

  • 递增/递减运算符只针对纯数字或字母(a-z、A-Z)进行运算。
  • 对于值为字母的变量,只支持递增操作。
  • 当操作数为布尔型类型的数据时,递增/递减操作对其值不产生影响。
  • 当操作数为 NULL 时,递增的结果为 1,递减不受影响。

字符串拼接运算符

PHP 提供了用于拼接两个字符串的运算符 . 符号。

当使用字符串拼接运算符拼接布尔型、整型、浮点型或 NULL 时,会被自动转换成字符串型。


示例:字符串拼接

入口页面(index.php):

<?php
echo "Hello"."PHP";

位运算符

PHP 中的位运算符用于对二进制位(0 和 1)进行操作。

PHP 的基本位运算符:

运算符
名称描述
&按位与如果两个二进制位都为 1,则该位的运算结果为 1,否则为 0
按位或如果二进制位上有一个值位 1,则该位的运算结果为 1,否则为 0
~按位非如果二进制位时 0,则取反值 1。 如果二进制位时 1,则取反值 0
^按位异或如果两个二进制位相同,则该位的运算结果为 0,否则为 1
<<左移将所有二进制位向左移动 1 位,右边的空位补 0,左边移走的部分舍去
>>右移将所有二进制位向右移动 1 位,左边的空位根据原数的符号补位 0 或 1,原数是负数就补 1,原数是正数就补 0

示例:位运算符

入口页面(index.php):

<?php
$m = 1; // 二进制为01
$n = 2; // 二进制为10

// 按位与
$mn_and = $m & $n;
echo "按位与结果:" . $mn_and . "<br>";

// 按位或
$mn_or = $m | $n;
echo "按位或结果:" . $mn_or . "<br>";

// 按位异或
$mn_xor = $m ^ $n;
echo "按位异或结果:" . $mn_xor . "<br>";

// 按位取反
$m_not = ~$m;
echo "按位取反结果:" . $m_not . "<br>";

$m = 3;
// 左移
$m_left_shift = $m << 1;
echo "左移结果:" . $m_left_shift . "<br>";

$m = 8;
// 右移
$m_right_shift = $m >> 2;
echo "右移结果:" . $m_right_shift . "<br>";

示例效果:


位运算可以用于优化一些特定的操作,例如在处理标志位、进行高效的位掩码操作或利用位移实现快速的乘除运算等场景中。

错误控制运算符

错误控制运算符用于在可能出现错误的表达式前使用,不会直接将错误显示给用户。

错误控制运算符的基本用法:

@表达式;

在 PHP8 中,错误控制运算符已经被弃用。

流程控制

分支结构

PHP 中的分支结构常用的有 if、if-else、if-elseif-else、switch-case。

if 语句的基本用法:

if(条件表达式) {
    // ...
}

if-else 语句的基本用法:

if(条件表达式) {
    // ...
} else {
    // ...
}

if-elseif-else 语句的基本用法:

if(条件表达式) {
    // ...
} elseif(条件表达式) {
    // ...
} else {
    // ...
}

switch-case 语句的基本用法:

switch(表达式) {
    case 值1:
        // ...
        break;
    case 值2:
        // ...
        break;
    // ...
    default:
        // ...
}

循环结构

PHP 中的循环结构常用的有 while、do-while、for。

while 语句的基本用法:

while(循环条件) {
    // ...
}

do-while 语句的基本用法:

do{
    // ...
} while(循环条件);

for 语句的基本用法:

for(初始化表达式; 循环条件; 操作表达式) {
    // ...
}

跳转语句

PHP 中的跳转语句常用的有 berak、continue。

  • break 语句在循环语句中用于终止、跳出循环。
  • continue 语句在循环语句中用于结束本次循环,开始下一轮循环。

流程控制代替语句

在 HTML 模板中嵌入 PHP 代码时,流程控制替代语句是一种可读性更好的语法。

流程控制语句和流程控制替代语句的比较:

流程控制语句流程控制替代语句
if(条件表达式) {
// ...
}
if(条件表达式):
// ...
endif;
switch(表达式) {
// ...
}
switch(表达式):
// ...
endswitch;
while(循环条件) {
// ...
}
while(循环条件):
// ...
endwhile;
for(初始化表达式; 循环条件; 操作表达式) {
// ...
}
for(初始化表达式; 循环条件; 操作表达式):
// ...
endfor;

示例:流程控制替代语句

入口页面(index.php):

<h3>10以内的偶数列表</h3>
<ul>
    <?php
    for ($i = 0; $i < 10; $i++) {
        if ($i % 2 == 0) {
            echo "<li>$i</li>";
        }
    }
    ?>
</ul>

<h3>10以内的偶数列表</h3>
<ul>
    <?php for ($i = 0; $i < 10; $i++): ?>
        <?php if($i % 2 == 0): ?>
            <li><?php echo $i ?></li>
        <?php endif; ?>
    <?php endfor; ?>
</ul>

示例效果:


文件包含语句

include 和 require

include 语句和 require 语句都可以引入一个外部文件。

  • include 语句和 require 的用法类似。
  • 当引入外部文件出现错误时,icnlude 语句会发出警告信息,程序继续执行。
  • 当引入外部文件出现错误时,require 语句会抛出致命错误,程序停止运行。

使用 include 语句引入公共代码的基本用法:

include '完整路径文件名';
include('完整路径文件名');

使用 require 语句引入公共代码的基本用法:

require '完整路径文件名';
require('完整路径文件名');

示例:include 和 require

工具类(util.php):

<?php
echo "这是工具类 util.php";

入口页面(index.php):

<?php
include './util.php';

echo "<br>Hello PHP";

示例效果:


include_once 和 require_once

include_once 语句和 require_once 语句也可以引入一个外部文件。

  • 使用 include_once 语句和 require_once 语句引入外部文件时,PHP 会检查该文件是否在程序中已经被引入。
  • 如果该已经被引入,则外部文件不会被再次引入,避免重复引入同一个文件。

示例:include_once 和 require_once

入口页面(index.php):

<?php
echo "<p>使用include引入util.php三次:</p>";
include './util.php';
echo "<br>";
include './util.php';
echo "<br>";
include './util.php';
echo "<br>";

echo "<p>使用include_once引入util.php三次:</p>";
// 上文已经引入util.php,此处不再重复引入
include_once './util.php';
echo "<br>";
include_once './util.php';
echo "<br>";
include_once './util.php';

示例效果:


]]>
0 https://www.duox.dev/post/162.html#comments https://www.duox.dev/feed/post/162.html
PHP 基础案例教程之 01-PHP 开篇 https://www.duox.dev/post/143.html https://www.duox.dev/post/143.html Sun, 18 Jan 2026 02:03:00 +0000 多仔

AI 摘要

文章系统梳理 PHP 语言:回顾 PHP 的演进,总结开源免费、跨平台、面向对象、数据库丰富、开发高效等核心优势;详解 Windows、Linux、macOS 下 PHP 8.4 的手动安装要点与线程安全选择;对比 FlyEnv、UPUPW、LNMP、PhpStudy、宝塔等一键集成环境;演示用 IntelliJ IDEA 搭建项目、配置 CLI 解释器、启动内置 Web 服务器并输出 phpinfo 验证环境;最后提示官方手册查阅方法,为初学者提供零门槛入门路径。

初识 PHP

PHP 概述

PHP 是一种运行在服务器端的脚本语言,其语法风格融合了 C、Java 和 Perl 的特点。

PHP 主要用来开发动态网页,它可以将网页中需要动态变化的内容通过程序来生成,PHP 代码还可以嵌入 HTML 中使用,从而在服务端动态生成网页。

PHP 动态网页的处理流程:

PHP 发展史

PHP 最初为 Personal Home Page(个人主页)的缩写,于 1994 年由拉斯姆斯·勒多夫(Rasmus Lerdorf)创建,用来显示个人履历和统计网页流量。

1995 年 6 月,拉斯姆斯·勒多夫发布了 PHP 1.0,同年又发布了 PHP 2.0,命名为 PHP/FI(PHP/Form Interpreter),该版本可以处理复杂的嵌入式标签语言,同时支持 MySQL 数据库,此时使用 PHP/FI 开发的网站数量迅速增长,提高了其在开发领域的影响力。

1997 年,泽夫·苏拉塞(Zeev Suraski)和安迪·古特曼(Andi Gutmans)加入了 PHP 开发小组,重新编写了底层的解析引擎,很多开发人员也自愿加入到 PHP 的工作中,从此 PHP 成为了真正意义上的开源项目。

1998 年 6 月,PHP 3.0 版本发布,这一版本具有更好的执行效率、更加清晰的结构和更高的可扩展性,开发人员也可以参与到 PHP 扩展模块的开发。

2000 年 5 月,PHP 4.0 版本发布,该版本使用 Zend 引擎为 PHP 提供强大的动力,提高了运行复杂程序的性能。相比 PHP 的前几个版本,PHP 4.0 的性能高出近十倍,此外还更新了一些其他内容,例如支持多种 Web 服务器、丰富的函数库、类和对象的语法等,这一版本中逐渐开始采用面向对象的思想。

2004 年 7 月,PHP 5.0 正式发布,这标志着 PHP 一个新时代的到来,该版本使用第二代 Zend 引擎,引入了完善的面向对象机制。

2007 年,PHP 开发小组开始重构 PHP 6.0 版本,在该版本中进一步完善了面向对象机制,精简数组语法,但是 PHP 6.0 版本没有正式发布。

2015 年 6 月,PHP 7.0 发布,该版本是 10 年来的大改版,在性能上有更大的突破,PHP 7.0 在 PHP 5.0 基础上做了进一步的改进,功能更强大,执行效率更高。

2020 年 11 月,PHP 8.0 发布,该版本包含了很多新功能与优化项,包括命名参数、联合类型、注解、构造器属性提升、match 表达式、nullsafe 运算符、JIT,并改进了类型系统、错误处理、语法一致性。

PHP 特点

随着时间的推移,PHP 凭借其特点,在 Web 开发领域占据了重要地位。

  • 开源免费:PHP 的源代码是开源的,并且可以免费使用。
  • 跨平台:PHP 的跨平台性很好,移植方便,在 Linux 平台和 Windows 平台上都可以运行。
  • 面向对象:PHP 提供了类和对象的语法,使用 PHP 进行 Web 开发时可以选择面向对象编程。
  • 支持多种数据库:PHP 支持 ODBC(开放数据库互联),可以连接任何支持该标准的数据库,如 MySQL、Oracle、SQL Server 和 DB2 等。PHP 与 MySQL 是最佳搭档,使用得最多。
  • 开发效率高:PHP 语法简单、实用性强、开发速度快,目前有很多 PHP 框架可以提高项目的开发速度。

根据 TIOBE 公布的 2024 年 4 月编程语言排行榜,PHP 在该榜单中的排名已跌至第 17 位。

在实际应用中,编程语言的选择应根据具体的项目需求、团队技术栈、性能要求等多方面因素来决定。虽然 PHP 的排名有所下降,但它在一些领域仍然被广泛使用,特别是在中小型网站和 Web 内容管理系统中。

搭建 PHP 开发环境

集成环境

使用集成安装的方式,可以快速搭建 PHP 系列开发环境,集成安装可以快速搭建开发环境,免去繁琐的环境安装、配置过程,但集成安装有可能会造成局部环境冲突,需要根据实际情况妥善选择。

常见的集成安装环境有:FlyEnv、UPUPW、PHPStudy、LNMP/LAMP、宝塔等。

FlyEnv 是一款一体化全栈环境管理工具,提供了一个完整的运行环境,通过极速多版本切换、全栈技术支持和无缝跨平台体验,简化开发流程。

FlyEnv:https://www.flyenv.com/

UPUPW 绿色服务器平台是 Windows 下很有特色的一款免费服务器 PHP 套件,包括 Apache、Nginx、MySQL、Redis 等核心应用,支持 PHP、ASP、ASP.NET 解析语言,更适应 Windows 服务器的高效生产工作。

UPUPW:https://www.upupw.net/

LNMP 一键安装包是一个用 Linux Shell 编写的可以为 Linux VPS 或独立主机安装 LNMP(Nginx/MySQL/PHP)、LNMPA(Nginx/MySQL/PHP/Apache)、LAMP(Apache/MySQL/PHP)生产环境的 Shell 程序。

LNMP:https://lnmp.org/

PhpStudy(小皮面板)是国内 12 年老牌公益软件,集安全,高效,功能与一体,已获得全球用户认可安装,运维也高效,支持一键 LAMP、LNMP、集群、监控、网站、FTP、数据库、JAVA 等 100 多项服务器管理功能。

PhpStudy:https://www.xp.cn/

宝塔面板支持一键 LNMP/LAMP/WNMP/WAMP/IIS/SQLServer/MySQL/集群/监控/网站/FTP/数据库/JAVA/PM2 等 100 多项服务器管理功能。

宝塔面板:https://www.bt.cn/

PHP

本地开发也可以手动安装 PHP,课程选用 PHP 版本为 8.4。

Windows 系统下载 PHP:https://windows.php.net/download/

  • PHP 版本分为线程安全(Thread Safe,TS)和非线程安全(Non Thread Safe,NTS)。
  • 一般情况下,Apache+PHP 选择 TS,Nginx+PHP、IIS+PHP 选择 NTS。
  • 在 IIS 或 Nginx 中以 FastCGI 方式运行 PHP 时,PHP 拥有独立的进程,并且 FastCGI 是单一线程的,不存在多个线程之间可能引发的问题,因此使用非线程安全版本能够获得更好的性能。
  • PHP 的线程安全与非线程安全版本只存在于 Windows 版本中,在 macOS/Linux 系统中,PHP 通常只提供非线程安全版本,因为 macOS/Linux 系统采用的是多进程的工作方式,不存在线程安全问题。
  • PHP 压缩包下载解压完成后,自行根据压缩包内提供的 .ini 配置文件来编写 PHP 配置文件(php.ini),并将整个文件夹复制到磁盘指定的位置中即可。

Linux 系统下载 PHP:使用 yum/apt 包管理工具安装。

macOS 系统下载 PHP:使用 HomeBrew 包管理工具安装。

IDE

Visual Studio Code、IntelliJ IDEA、PHPStorm 均可开发 PHP 项目,建议直接使用 IntelliJ IDEA 作为 PHP 项目开发所使用的 IDE。

在 IntelliJ IDEA 中,有支持 PHP 项目的插件。

在 IntelliJ IDEA 中,还需要配置 PHP 语言级别和 CLI 解释器,以支持 PHP 项目开发。

phpinfo

PHP 开发环境搭建完成后,可以创建一个 PHP 项目,查看 PHP 环境信息。

  • 新建 PHP 文件,并编写 PHP 文件基本结构。
  • 使用 PHP 内置的 phpinfo 函数输出 PHP 环境信息。
  • 配置 PHP 内置 Web 服务器,运行 PHP 项目。

PHP 内置了一个简单的 Web 服务器,自 PHP 5.4.0 起可用。

使用 PHP 内置 Web 服务器,无需额外安装和配置复杂的 Web 服务器软件(如 Apache、 Nginx),即可快速启动一个简单的服务器来运行 PHP 脚本。

PHP 内置 Web 服务器在功能和效率上不如 Apache、Nginx 等成熟的 Web 服务器,但对于小型项目的开发和调试非常方便。


示例:phpinfo

新建 PHP 项目:

入口页面(index.php):

<?php    // 所有的PHP脚本以 <?php 开头
phpinfo();    // 输出PHP环境信息

配置 PHP 内置 Web 服务器:

示例效果:


PHP 手册

访问手册

部分语法、新特性,需要通过查阅 PHP 手册来学习。

PHP 手册:https://www.php.net/manual/zh/

]]>
0 https://www.duox.dev/post/143.html#comments https://www.duox.dev/feed/post/143.html
Solon + EasyQuery + ElementPlus 实现后台管理系统之 08-权限认证优化 https://www.duox.dev/post/139.html https://www.duox.dev/post/139.html Tue, 23 Dec 2025 11:42:52 +0000 多仔

AI 摘要

文章聚焦 Solon + EasyQuery + ElementPlus 后台管理系统的按钮级权限优化:前端用 Pinia 仓库存储用户权限标识,封装 hasPerms 方法,在模板中 v-if 控制按钮显隐;后端基于 Sa-Token 实现 StpInterface 返回权限集合,并用 @SaCheckPermission 注解做 API 级校验,实现前后端一致的细粒度权限闭环,防止越权并提升体验。

精确到按钮级别的权限认证

基础原理

按钮级权限控制不是锦上添花,而是保障系统安全和用户体验的刚需,原因在于:

  • 数据安全与操作合规:不同角色的用户能执行的操作不同(比如普通员工只能查看数据,管理员能删除 / 编辑),如果仅做页面级权限,用户可能通过伪造请求(比如绕过前端手动调接口)执行越权操作,按钮级控制能从前端直接屏蔽非法操作入口,减少恶意请求。
  • 提升用户体验:避免给用户展示看得见但点不了的按钮,或点击后提示无权限的尴尬场景,让界面只显示用户真正能操作的功能,降低使用困惑。
  • 统一权限逻辑:前端和后端权限规则对齐,避免前端显示按钮但后端拒绝请求的不一致问题,减少前后端联调成本。

前端实现按钮级别的权限认证的核心逻辑:先获取用户权限标记集合 ->在渲染按钮时校验权限 -> 最终决定按钮是否显示/禁用。

前端优化

编写登录用户数据仓库(store/currentUser.js),存储当前登录用户权限标记列表:

import {ref, computed, reactive} from 'vue'
import { defineStore } from 'pinia'

export const useCurrentUserStore = defineStore('currentUser', () => {
    // 登录用户信息实体
    let currentUser = reactive({})

    // 当前用户菜单列表
    let currentMenu = reactive([])

    // 当前用户权限标记
    let currentPerms = reactive([])

    // 设置登录用户信息实体
    function setCurrentUser(currentUser) {
        this.currentUser = currentUser
    }

    // 设置当前用户菜单列表
    function setCurrentMenu(currentMenu) {
        this.currentMenu = currentMenu
    }

    // 设置当前用户权限标记
    function setCurrentPerms(currentPerms) {
        this.currentPerms = currentPerms
    }

    function hasPerms(identifier) {
        // 判断当前用户是否拥有指定权限标记
        return this.currentPerms.includes(identifier)
    }

    return { currentUser, setCurrentUser, currentMenu, setCurrentMenu, currentPerms, setCurrentPerms, hasPerms }
})

编写权限工具类(plugins/PermsUtil.js),优化将用户权限标记存储到仓库中方法:

// 将用户权限菜单存储到仓库中
useCurrentUserStore().setCurrentMenu(toTreeList(response.data, false))

// 将用户权限标记存储到仓库中(包含所有类型的权限)
useCurrentUserStore().setCurrentPerms(response.data.map(perm => perm.identifier))

编写页面组件,完善按钮级别的权限认证:

<el-button type="warning" @click="showAddDialog" v-if="useCurrentUserStore().hasPerms('system:users:add')">
    添加用户
</el-button>

在浏览器中测试:

后端 API 的权限认证

基础原理

参考文档:https://sa-token.cc/doc.html#/use/jur-authhttps://sa-token.cc/doc.html#/use/at-check

后端 API 是系统数据和业务操作的唯一入口,前端权限认证仅为体验层防护,后端权限认证才是真正的安全兜底,原因在于:

  • 防越权操作:前端权限可被轻易绕过(比如通过 Apifox、抓包工具直接调用 API,或修改前端代码),如果后端不校验权限,恶意用户能执行删除数据、修改配置等高危操作,直接威胁系统安全。
  • 符合业务规则:不同角色的用户本就该有不同操作范围(如普通员工只能查数据,管理员能删数据),API 权限认证是业务规则在后端的落地,确保什么人能做什么事。
  • 降低系统风险:即使前端漏洞导致权限控制失效,后端的权限校验仍能拦截非法请求,避免单点漏洞引发全系统风险。

后端 API 实现权限认证的核心逻辑:登录生成身份凭证 Token -> 接口调用时校验凭证有效性并关联用户 -> 查询用户权限集合与 API 权限要求匹配 -> 匹配成功放行/失败拦截。

后端优化

编写权限认证是嫌累(cn.duozai.sadmin.config.StpInterfaceImpl),返回一个账号所拥有的权限码集合:

/**
 * SaToken权限认证实现类
 */
@Component
public class StpInterfaceImpl implements StpInterface {

    /**
     * 返回一个账号所拥有的权限码集合
     * @visduo
     *
     * @param loginId 登录id
     * @param loginType 登录类型
     * @return 权限码集合
     */
    @Override
    public List<String> getPermissionList(Object loginId, String loginType) {
        // 从会话中获取权限列表(获取当前登录用户权限列表时存入)
        List<PermsEntity> permsList = (List<PermsEntity>) StpUtil.getSession().get("perms");
        
        // 遍历权限列表,获取权限标识列表
        List<String> identifierList = new ArrayList<>();
        for (PermsEntity permsEntity : permsList) {
            identifierList.add(permsEntity.getIdentifier());
        }

        // 返回权限标识列表
        return identifierList;
    }

    /**
     * 返回一个账号所拥有的角色标识集合 (权限与角色可分开校验)
     * @visduo
     *
     * @param loginId 登录id
     * @param loginType 登录类型
     * @return 角色标识集合
     */
    @Override
    public List<String> getRoleList(Object loginId, String loginType) {
        return new ArrayList<>();
    }

}

编写控制器,完善方法级别的权限认证:

@SaCheckPermission("system:users:add")    // 注解校验
@Post
@Mapping("/add")
public ResponseResult add() {
    // ...
}
]]>
0 https://www.duox.dev/post/139.html#comments https://www.duox.dev/feed/post/139.html
Stable Diffusion AIGC 视觉设计实战教程之 09-ControlNet 插件 https://www.duox.dev/post/138.html https://www.duox.dev/post/138.html Tue, 23 Dec 2025 11:31:35 +0000 多仔

AI 摘要

ControlNet 插件为 Stable Diffusion 提供工业级精准控图能力,通过姿态、深度、边缘、语义分割等 20 余种预处理器,将参考图结构转化为生成条件,实现线稿上色、建筑可视化、换脸、局部重绘、风格迁移等场景。文章系统梳理安装流程、参数释义、多预处理器叠加技巧,并以 OpenPose、Canny、Depth、Tile、Inpaint 等为例给出实战参数,帮助创作者在插画、摄影、3D 辅助等领域高效产出高保真、高一致性的 AI 图像。

ControlNet 插件

ControlNet 概述

ControlNet(控制网)是由 lllyasviel 团队于 2023 年提出的神经网络架构,核心是为了解决在 Stable Diffusion 中如何让图像生成变得更加可控的问题,是 Stable Diffusion 迈向工业化的非常重要的一步。

ControlNet 通过预处理器提取参考图中的姿态、深度、边缘等结构信息,再由 ControlNet 模型转换为检查点模型能够理解的生成条件,让生成图像精准遵循参考图的布局与结构,彻底解决生图结构失控的痛点,是 Stable Diffusion 中实现精准控图的核心插件。

ControlNet 插件的应用场景:

  • 插画创作:基于线稿生成高精度彩色插画,保留线条构图。
  • 角色设计:基于姿势参考图生成指定动作的角色形象,如游戏角色战斗姿势等。
  • 建筑可视化:根据图纸生成写实风格的建筑效果图。
  • 3D 模型辅助生成:根据深度图、法线图控制生成图像的空间立体感,辅助 3D 建模纹理绘制。
  • 摄影修图:基于照片生成二次元风格图像,保留人物构图。

图生图与 ControlNet 插件的区别:

  • 图生图是基于已有图像,通过调整参数、添加提示词等让模型生成新图像,对原图依赖度高,主要是在原图基础上修改或拓展。
  • ControlNet 是 Stable Diffusion 插件,虽本质也是图生图,但可借助多种控制类型(如边缘线稿、姿态、深度等)和预处理器,在遵循原构图下更灵活、精确地控制图像生成,对原图破坏小,自由度与可控性更高。

ControlNet 插件的发展史:

  • V1.0(2023-03):初代发布,仅 8 支持种基础预处理器(Canny、HED、Midas Depth、OpenPose 等),实现边缘、姿态、深度等核心控制。
  • V1.1(2023-11):扩展至 14 种,新增 Lineart、Shuffle、Reference 等预处理器,优化训练数据与稳定性,适配更多场景。
  • SDXL 适配(2023-2024):插件更新支持 SDXL,推出适配大模型的专用预处理器(如 SDXL - ControlNet Tile、Depth 等),强化细节控制,同步兼容 SD1.5 生态。
  • 多模态与精细化(2024-2025):新增 InstructP2P、Reference 、PuLID、DWPose 等预处理器,引入 ONNX 加速、AIO 集成预处理,提升效率与兼容性,覆盖文控、换脸、风格迁移等多元需求。
  • 社区与生态拓展:第三方衍生预处理器(如针对 FLUX 的适配版)涌现,预处理器与模型解耦更灵活,支持多预处理器叠加,兼顾显存优化与控制精度平衡。

ControlNet 安装

ControlNet 插件的安装与使用:https://github.com/lllyasviel/ControlNet

LiblibAI 已内置 ControlNet 插件,在本地部署的 Stable Diffusion 中使用 ControlNet,需要确保 ControlNet 插件已经安装到 WebUI 中。

ControlNet 仅凭插件本体是无法正常运行的,必须结合特定的 ControlNet 预处理器、模型,以实现不同的功能效果。

ControlNet 基本参数

ControlNet 面板主要分为图像上传板块、控制类型板块、控制参数板块。

在图像上传板块可以上传参考图,通过输入参考图像来引导 AI 生成在细节、风格、结构等方面更符合创作者期望的图像,实现对图像生成过程的精细控制。

在控制类型(Control Type)板块中,可以选择控制的模式,每一种模式对应不同的预处理器,也对应不同的 ControlNet 模型,在选择时,检查点模型、控制模式、预处理器、ControlNet 模型四者一一对应。

ControlNet 可使用的预处理器非常多,允许创作者通过引入额外的控制信号来引导图像生成的过程,从而生成更精确、更丰富的效果,预处理器就像是给 AI 翻译图像语言的工具。

  • 画轮廓:用边缘检测预处理器,把照片里的物体轮廓线条提取出来(像自动生成线稿),告诉 AI 按这个形状来画。
  • 看深度:用深度检测预处理器,分析照片里物体的远近关系(比如谁在前、谁在后),让 AI 生成的新图有类似的空间感。
  • 学姿势:用姿态检测预处理器,识别照片里人物的动作(比如抬手、走路),让 AI 生成的人物摆出一样的姿势。

在控制参数板块中,可以调整相关参数:

  • 完美像素:自动让参考图的分辨率、比例和最终生成图保持一致,避免因尺寸不匹配导致的结构变形。
  • 允许预览:在生成最终图像前,先预览预处理器输出的控制图,能提前确认结构是否符合预期,避免生成后才发现控制图有问题。
  • 控制权重(Control Weight):取值范围为 0~2,表示 ControlNet 对生成图像的控制程度,数值越大,参考图的引导作用越强,生成图像越贴近参考图的特征。
  • 上传蒙版:用于指定参考图里需要修改的白色区域和保留不动的黑色区域,实现精准局部重绘。
  • 起始步数(Starting Control Step):取值范围为 0~1,表示 ControlNet 在图像生成过程中,从哪个阶段开始发挥作用。0 表示从生成过程一开始就起作用,数值越接近 1,ControlNet 介入越晚,前期主要由基础模型按常规方式生成。
  • 完结步数(Ending Control Step):取值范围为 0~1,表示 ControlNet 在图像生成过程中作用结束的阶段。1 表示一直作用到生成结束,数值越接近 0,ControlNet 提前结束控制,后期主要由基础模型自由生成。
  • 预处理器分辨率(Preprocessor Resolution):在使用预处理器对图像进行处理时,图像所被设定的分辨率大小,其决定了预处理器处理图像的精细程度,数值越高,处理后的图像细节越丰富,但计算量也会增大,处理耗时增加。
  • 控制模式(Control Mode):用于调节在图像生成中提示词和 ControlNet 上传图像对最终生成结果的影响侧重,可选均衡、更注重提示词、更倾向于让 ControlNet 自由发挥。
  • 图片缩放模式(Resize Model):决定参考图适配生成需求的方式,可选拉伸、裁剪、填充。

ControlNet 支持同时使用多个预处理器(即叠加多个 ControlNet 控制单元),只需在界面中开启多个 ControlNet 选项卡,分别选择不同预处理器、上传对应控制图即可。

ControlNet 基本用法

以生成一张人物写实图为例,参考生成参数如下。

  • ckpt 检查点模型:麦橘超然 majicFlus
  • 正向提示词(中文):一个女孩,在海边,穿着白色长裙,长袖,戴着太阳帽,面带微笑
  • 正向提示词(英文):A girl,over the sea,white long dress,long sleeves,sun hat,smile
  • 负向提示词:ng_deepnegative_v1_75t,(badhandv4:1.2),EasyNegative,(worst quality:2)
  • 采样方法:Euler a
  • 迭代步数:30
  • 图片尺寸:768x1024
  • 提示词引导系数:3.5

生成效果:

以上图为例,使用 ControlNet 控制人物姿态,参考插件参数如下。

  • 完美像素:启用
  • 控制类型:OpenPose 姿态
  • 预处理器:openpose(OpenPose 姿态)
  • ControlNet 模型:F.1-ControlNet-Pose-V1
  • 控制权重:1.5
  • 起始步数:0
  • 完结步数:0.7
  • 控制模式:均衡
  • 图片缩放模式:填充

爆炸运行 & 预览效果:

调整生成参数如下。

  • 正向提示词(中文):一个男孩,在海边,穿着白色裤子,长袖,戴着太阳帽,面带微笑
  • 正向提示词(英文):A boy,by the sea,wearing white pants,long sleeves,wearing a sun hat,with a smile on his face
  • 图片数量:4

生成效果:

ControlNet 预处理器

OpenPose 姿态

OpenPose 是一种基于计算机视觉的人体姿态估计算法,通过检测人体关键点(如关节、面部特征点)并连接成骨骼结构,精确捕捉人物的动作和姿态。

OpenPose 算法通常检测以下关键点:

  • 身体:18 个关键点(头部、颈部、肩膀、肘部、手腕、髋部、膝盖、脚踝等)。
  • 手部:每只手 21 个关键点(手指关节和手掌)。
  • 面部:70 个关键点(眼睛、眉毛、鼻子、嘴巴等)。

OpenPose 姿态预处理器允许创作者通过上传姿态参考图或直接绘制骨架来控制生成图像中的人物姿势。

OpenPose 姿态预处理器的应用场景:

  • 人物动作控制:让模型生成的人物摆出指定姿势如跳舞、运动,比如输入瑜伽动作姿势图,模型就能画出对应姿势的插画。
  • 多人物场景协调:控制画面中多个人物的互动姿势,避免人物动作僵硬或冲突。
  • 动画/游戏角色设计:快速生成角色的关键帧动作,减少手绘工作量,后续可导入 3D 软件细化。

OpenPose 姿态预处理器的关键参数:

  • 通过调整不同的预处理器,可以单独对姿态、手部等组合进行识别,也可以使用精度更高的预处理器得到更准确的姿势。
  • 如:openpose full 高精度检测全身姿态、openpose hand 检测姿态及手部、openpose faceonly 仅检测脸部等。

在 OpenPose 姿态预处理器中,可以打开姿态编辑器调整姿态以重塑动作。

Canny 硬边缘

Canny 硬边缘预处理器用于提取图像的边缘轮廓,生成清晰的线条引导,且线条只有黑白两色,便于模型理解和遵循。

Canny 硬边缘预处理器的应用场景:

  • 漫画插画风格生成:用清晰线条勾勒人物轮廓,搭配提示词生成日系动漫效果,低阈值保留发丝细节,高阈值强化主体轮廓。
  • 照片转线条画:将写实照片转为线条引导的艺术图,通过调整阈值控制线条疏密,适合制作极简风格海报或创意头像。
  • 建筑或机械设计可视化:突出硬边缘结构,帮助模型理解几何形状,生成工业设计草图或建筑外观渲染图。
  • 线稿上色:导入手绘线稿图,提取清晰轮廓,搭配风格提示词让 AI 精准填充色彩,既保留线稿的结构感,又能快速生成多样配色的插画。

Canny 硬边缘预处理器的关键参数:

  • 高低阈值(High/Low Threshold):阈值越高,识别出来的线条越少。
  • 如果上传的参考图是白色背景和黑色线条的图,预处理器直接设置为 invert 反转。

SoftEdge 软边缘

SoftEdge 软边缘预处理器用于处理图像边缘轮廓信息,目标是识别并区分图像中各种形状(如直线、圆弧等)的边缘。

SoftEdge 软边缘预处理器的应用场景:

  • 艺术插画创作:绘制梦幻、柔和风格插画时,让元素边缘自然融合过渡,比如画一朵朦胧的花朵、缥缈的云朵,营造诗意氛围。
  • 产品渲染图:处理产品渲染图中产品与背景的衔接,让产品边缘不生硬,比如电子产品融入场景时,使产品与周围环境过渡自然,增强真实感。
  • 人像摄影后期:修饰人像照片,柔化人物发丝、皮肤边缘,弱化瑕疵,呈现更自然柔和的肤质与轮廓,提升人像美感。
  • 立体艺术字:生成带有柔和渐变边缘的艺术字效果,让字体轮廓不生硬,与背景的光影、色彩自然衔接。

SoftEdge 软边缘预处理器的关键参数:

  • 通过调整不同的预处理器变体,可适配不同精度与安全需求。
  • 如:hed 边缘柔和度高,pidinet 边缘更精准,teed 偏细腻线条,anyline 兼容多种线稿类型。
  • 带有 safe 的预处理器在生成过程中加入了安全机制,可有效避免生成包含不良或敏感内容的边缘信息,适用于儿童绘本绘制、正规出版物配图制作等对内容安全性要求较高的场景。

Lineart 线稿

Lineart 线稿预处理器是一种用于控制图像生成过程中线稿风格的约束方式,允许创作者输入简单线条或线稿(通常只包含黑白线条,没有色彩和阴影),生成符合轮廓的完整图像。

Lineart 线稿预处理器的应用场景:

  • 插画漫画创作:把照片转成干净的线稿,直接用于上色或让模型生成日系、欧美漫画等风格。
  • 服装设计草图:快速生成服装轮廓线稿(如裙子褶皱、领口形状等),模型可以基于线稿填充不同材质或花纹(如蕾丝、皮革等)。
  • UI 图标设计:制作简洁的界面元素或图标,线条粗细均匀,模型能保持设计风格统一。

Lineart 线稿预处理器的关键参数:

  • 通过调整不同的预处理器,可以适配不同的风格类型。
  • 如:anime 动漫线稿提取、realistic 写实线稿提取、standard 标准线稿提取等。

MLSD 直线

MLSD 是一种基于深度学习的直线检测算法,能够识别图像中的直线段而非简单的边缘,并将其转化为清晰的矢量线条。

Lineart 线稿、Canny 硬边缘、SoftEdge 软边缘、MLSD 直线的异同:

  • Lineart 线稿是专门提取干净的绘画线稿,适配不同风格的线条感,提供更加细致的线条识别和控制。
  • Canny 硬边缘是提取黑白硬轮廓边缘,侧重物体形状边界。
  • SoftEdge 软边缘是提取柔和语义边缘,边缘过渡自然不生硬。
  • MLSD 直线是精准提取图像中的直线与几何轮廓,过滤曲线、纹理等干扰信息,仅聚焦规则几何线条的约束。
  • 四者核心差异是线条的提取范围、风格属性和硬朗程度,前三者覆盖全类型边缘 / 线条,MLSD 仅针对直线类几何结构。

MLSD 直线检测预处理器的应用场景:

  • 建筑设计效果图生成:根据建筑草图生成精准比例的别墅、写字楼效果图,保证墙体、门窗、梁柱的直线笔直。
  • 室内空间布局设计:锁定房间的墙面、地板、天花板的直线结构,生成不同风格的家装效果,避免空间比例失衡。
  • 工业产品设计:生成电子产品、家具、工具等带规则几何结构的产品图,保证产品的线条规整、造型精准。
  • 线稿优化与风格化:将粗糙的建筑线稿转化为写实或插画风格的成品图,保留原始线稿的几何结构。
  • 几何风格艺术创作:生成极简主义、构成主义风格的艺术作品,强化画面的直线分割与几何美感。

MLSD 直线检测预处理器的关键参数:

  • MLSD Value Threshold(MLSD 值阈值)用于筛选直线检测结果,其值越高对直线像素值要求越严,检测出的直线越少。
  • MLSD Distance Threshold(MLSD 距离阈值)用于判断两条线段能否合并为一条的依据,其值越大允许线段间距离越大,直线检测结果更简洁。

Depth 深度图

Depth 即深度,源于三维概念,描述物体间远近关系,图像只有黑白两色,白色表示距离镜头近,黑色表示距离镜头远,深度图能将图像采集器到场景各点的距离作为像素值,体现画面物体三维深度关系。

Depth 深度图预处理器通过传递图片空间信息,指导 AI 图像生成,辅助指定构图、姿势和 3D 结构等,在保持原始构图时生成新颖图像,比如创建有空间感的多层次场景,让 AI 理解动作层次和空间信息。

Depth 深度图预处理器的应用场景:

  • 3D 场景生成与立体效果:给模型输入带深度信息的图(近实远虚),生成有纵深感的场景,比如模拟森林深处、走廊尽头的空间层次。
  • 物体遮挡关系控制:让模型知道谁在前、谁在后,比如画人物拿杯子时,用深度图确保手在杯子前面,避免元素错位。
  • 景深特效模拟:通过调整深度范围,让模型生成类似相机大光圈效果,比如拍人像时虚化背景突出主体,或拍微距时虚化前景聚焦昆虫。

Depth 深度图预处理器的关键参数:

  • 通过调整不同的预处理器,可以灵活匹配不同场景的空间精度需求,快速获取从大场景纵深到精细局部层次的深度控制图。
  • 如:Midas 速度快适配大场景,Zoe 全局均衡通用性强,Leres/Leres++ 细节拉满适合精细构图,DepthAnything 泛化性佳适配任意风格。

Tile/Blur 分块/模糊

Tile/Blur 分块/模糊预处理器是 ControlNet 里负责高清修复与大图生成的预处理器,核心作用是拆分图像为多个小块并保留局部细节特征,避免大尺寸生图时出现模糊、重复纹理或细节丢失的问题,同时柔化块与块之间的拼接痕迹,让画面更自然连贯。

Tile/Blur 分块/模糊预处理器与 Tiled Diffusion 插件的异同:

  • 相同:都可以用于放大场景的分块处理。
  • 原理不同:Tile/Blur 分块/模糊预处理器先提取原图分块特征作控制图,通过 ControlNet 模型约束生成,而 Tiled Diffusion 插件在潜空间分块,通过算法逐块生成并拼接。
  • 显存控制不同:Tile/Blur 分块/模糊预处理器显存占用低,依赖 ControlNet 轻量处理,而 Tiled Diffusion 可通过分块大小、重叠区域灵活控制,小分块更省显存。
  • 细节可控性不同:Tile/Blur 分块/模糊预处理器处理的细节贴合原图,创意空间受控制权重影响,而 Tiled Diffusion 插件可调分块、重叠、采样步数,还支持区域提示,自由度更高。
  • Tile/Blur 分块/模糊预处理器与 Tiled Diffusion 插件经常结合使用,尤其在大图生成、低显存设备高清放大、复杂细节修复等场景,二者互补,前者控结构与细节,后者控显存与拼接,协同解决大尺寸生图爆显存、细节丢失、拼接断层三大痛点。

Tile/Blur 分块/模糊预处理器的应用场景:

  • 中小尺寸图像高清放大,保留边缘与纹理细节,避免放大后模糊。
  • 重复纹理(如布料、墙面、瓷砖)的拼接痕迹修复,让纹理过渡自然。
  • 风格转绘时锁定原图色彩与结构(如真人漫改、插画转写实),减少风格偏移。
  • 老照片、监控截图、压缩图等低质图像的细节修复,去除噪点与划痕。
  • 设计稿、文献扫描件的高清化处理,适配打印与数字出版的精度要求。

Tile/Blur 分块/模糊预处理器的关键参数:

  • 通过调整不同的预处理器,可以适配不同的细节与色彩需求,实现布局锁定、色彩固定或锐化增强等效果。
  • 如:resample 侧重保留布局与细节、colorfix 在保留布局的同时固定色彩、colorfix+sharp 在固定色彩基础上增加锐化、blur_gaussian 通过高斯模糊调整画面景深与融合度。

Inpaint 局部重绘

Inpaint 局部重绘预处理器用于通过蒙版精准锁定需要修改的区域,对图像的局部区域进行重绘或修复。

Inpaint 局部重绘预处理器与图生图局部重绘的异同:

  • 相同:都能对图像局部区域进行修改,通过蒙版框选目标区域,实现精准的局部重绘需求。
  • 原理不同:Inpaint 局部重绘预处理器先提取原图非蒙版区域的结构特征作为控制图,约束生成过程中全局结构不偏移,而图生图局部重绘仅依赖蒙版限定重绘范围,无额外结构约束,生成结果易受提示词影响出现整体比例失衡。
  • 结构稳定性不同:Inpaint 局部重绘预处理器通过 ControlNet 模型锁定非蒙版区域的轮廓、透视、比例,即使蒙版区域较大,也能保证主体与背景的衔接自然,而图生图局部重绘在大区域修改时,易出现主体变形、背景错位等问题。
  • 操作灵活度不同:Inpaint 局部重绘预处理器需在 ControlNet 面板与图生图面板配合设置,参数调节维度更多(如控制权重、引导时机),而图生图局部重绘操作更简洁,仅需在图生图面板设置蒙版与重绘幅度,适合快速简单的局部修改。
  • 适配场景不同:Inpaint 局部重绘预处理器适合复杂场景的局部重绘(如人物换衣、场景替换等),而图生图局部重绘适合简单的局部修复(如去杂物、小范围补全)。
  • Inpaint 局部重绘预处理器通常与多类工具(如图生图局部重绘、OpenPose 姿态预处理器等)配合实现精准且协调的图像局部优化。

Inpaint 局部重绘预处理器的应用场景:

  • 人物局部修改:更换衣服款式/颜色、调整发型、修改妆容,保留人物肢体姿态与背景不变。
  • 场景局部替换:将室内背景改为户外风景、把普通街道替换为赛博朋克风格街道,保证主体与新背景透视匹配。
  • 图像杂物去除:删除照片中的路人、水印、电线等干扰元素,让画面更简洁,同时还原背景细节。
  • 局部细节精修:优化产品图的瑕疵、增强插画的局部纹理、修复老照片的局部破损。
  • 创意局部改造:给普通物体添加特效(给杯子加蒸汽、给人物加翅膀)、将平面元素改为立体效果,兼顾创意与画面协调性。

Inpaint 局部重绘预处理器的关键参数:

  • 通过调整不同的预处理器,可以适配不同的局部重绘需求,实现结构精准锁定或细节保留优先的效果。
  • 如:global_harmonious 兼顾蒙版区域与全局画面的色彩,光影协调,避免出现局部与背景割裂的问题、only_mask 仅聚焦蒙版区域修改,对非蒙版区域无额外约束,适合简单的局部补全、sketch 可结合草图控制蒙版区域的结构,适合需要精准控制局部形态的场景。

Segmentation 语义分割

Segmentation 语义分割预处理器可以将图像按语义类别(如人物、天空、建筑、植物、衣物等)进行像素级分割,生成带类别标签的控制图,通过精准锁定特定类别区域实现针对性生成或修改,确保不同语义区域的边界清晰、内容匹配,避免区域混淆或内容错位。

Segmentation 语义分割预处理器的应用场景:

  • 场景元素批量替换:将全图的天空替换为晚霞/星空、把所有植物替换为秋季植被,保持其他区域结构不变。
  • 全局风格统一调整:仅让人物区域保持写实风格,将背景建筑区域转为动漫风格,实现多风格融合。
  • 多区域精准控色:统一调整全图衣物的颜色、优化所有建筑的光影色调,确保同类别区域风格协调。
  • 复杂场景分层创作:先分割出人物、背景、道具等区域,分别对各区域进行细节强化,再整合生成高质量图像。
  • 图像内容规整优化:修正场景中语义错位的元素(如将误判为植物的道具修正为金属材质)、统一调整同类别元素的比例与位置。

Segmentation 语义分割预处理器的关键参数:

  • 通过调整不同的预处理器变体,可适配不同场景的语义分割需求。
  • 如:ade20k 擅长室内外场景精细分割、coco 聚焦常见物体的粗粒度分割,能识别 80 + 类高频物体。

Recolor 重上色

Recolor 重上色预处理器是 ControlNet 中专注于图像色彩重塑的预处理器,核心作用是在严格保留原图构图、轮廓与细节结构的基础上,对图像进行重新上色或色彩优化,无需改动画面主体形态即可实现黑白转彩色、风格调色等效果,同时尽量贴合提示词定义的色彩逻辑,让色彩过渡自然且与内容匹配。

Recolor 重上色预处理器与图生图局部重绘的异同:

  • 相同:都能对图像进行色彩调整,实现特定区域或整体的颜色改变。
  • 原理不同:Recolor 重上色预处理器先提取原图的亮度或强度特征作为控制图,通过 ControlNet 模型约束色彩生成,确保结构不偏移,而图生图局部重绘依赖蒙版框选目标区域,通过重绘幅度控制色彩覆盖范围。
  • 操作复杂度不同:Recolor 重上色预处理器无需手动框选,仅需设置参数和提示词即可实现全图或全局色彩重塑,操作更简洁,而图生图局部重绘需精准绘制蒙版,对细节操作要求更高。
  • 色彩可控性不同:Recolor 重上色预处理器的色彩效果受提示词描述精度影响较大,易出现颜色串色,而图生图局部重绘通过蒙版精准锁定区域,配合提示词可实现点对点的精准色彩替换,可控性更强。
  • 适用效率不同:Recolor 重上色预处理器适合全图色彩风格统一调整(如黑白照片整体上色),效率更高,而图生图局部重绘适合多区域差异化色彩修改(如同时修改衣服、头发、背景颜色),灵活性更强。

Recolor 重上色预处理器的应用场景:

  • 黑白老照片、老影像的色彩还原,唤醒复古影像的岁月细节。
  • 线稿/草图快速上色,保留线条结构的同时生成多样色彩方案。
  • 现有图像的风格调色,如将冷色调转为暖色调、实现赛博朋克/莫兰迪等色彩风格迁移。
  • 产品设计多色方案预览,在固定产品形态下快速切换不同配色。
  • 低饱和/褪色图像的色彩增强,还原画面原本的色彩层次。

Recolor 重上色预处理器的关键参数:

  • 通过调整不同的预处理器,可以适配不同的色彩重塑需求,实现亮度优先或饱和度优先的上色效果。
  • 如:luminance 细节清晰,色彩过渡自然、intensity 色彩饱和、视觉冲击强。

IP-Adapter 风格迁移

IP-Adapter(Image Prompt Adapter)风格迁移预处理器通过参考图提取人物形象特征或画面风格特征,无需复杂提示词即可将参考特征融入生成过程,实现一键迁移 IP 形象、统一风格,同时保留模型原生的创意生成能力,兼顾精准度与灵活性。

IP-Adapter 风格迁移预处理器的应用场景:

  • IP 形象精准复刻:将原创角色、动漫 IP 的五官、造型迁移到不同场景,如把卡通 IP 形象融入古风场景、科幻场景。
  • 多图风格统一:批量迁移参考图的艺术风格,让生成的系列图保持一致风格。
  • 真人形象二次元化:基于真人照片迁移五官特征,生成同形象的动漫/插画风格作品。
  • 细节化风格迁移:仅迁移参考图的局部特征(如参考图的光影色调、服饰纹理),保留主体创意生成。

IP-Adapter 风格迁移预处理器的关键参数:

  • 通过选择不同的特征提取模式,适配形象 / 风格迁移需求。
  • 如:clip_sd15 是 SD 1.5 中适配任意图像的基础特征复用、face_id 专注真人脸 ID 迁移,实现五官复刻、face_id_plus 额外保留面部细节与神态,精度更高。

InstantID 换脸

InstantID 换脸预处理器通过提取参考人脸的 ID 特征与姿态特征,生成带人脸约束的控制信号,在保留目标人脸核心特征的前提下,自由定制生成画面的场景、风格与动作,实现跨角度、跨风格的精准换脸。

InstantID 换脸与 IP-Adapter face_id 风格迁移预处理器的异同:

  • 相同:都能基于参考图实现人脸特征的精准迁移,保证生成人脸与参考图五官匹配。
  • 原理不同:InstantID 换脸预处理器同时提取人脸 ID 特征 + 姿态特征,无需额外依赖 OpenPose 即可匹配参考人脸的角度/神态,而 IP-Adapter face_id 风格迁移预处理器仅提取人脸 ID 特征,姿态控制需搭配其他 ControlNet 单元。
  • 适配性不同:InstantID 换脸预处理器对低分辨率参考图、侧脸/多角度人脸的适配性更强,换脸不易出现五官变形,而 IP-Adapter face_id 风格迁移预处理器更适配正脸、高清参考图的特征迁移。
  • 显存占用不同:InstantID 换脸预处理器采用轻量化特征编码,低显存即可稳定运行,而 IP-Adapter face_id 风格迁移预处理器显存占用略低,但多特征叠加时需额外显存。
  • InstantID 换脸预处理器通常与 OpenPose 姿态、Depth 深度图等预处理器配合使用,尤其在复杂动作换脸场景,实现二者互补,协同解决换脸时姿态偏移、比例失衡的痛点。
  • InstantID 换脸预处理器适配 SDXL 模型。

InstantID 换脸预处理器的应用场景:

  • 多角度人脸换脸:将参考人脸复刻到侧脸、仰角/俯角等非正脸场景,保证五官比例与角度匹配。
  • 低质参考图换脸:基于模糊老照片、监控截图、低分辨率头像生成高清换脸图,还原核心五官特征。
  • 风格化换脸创作:保留参考人脸特征,生成动漫、油画、赛博朋克等不同艺术风格的人脸图像。
  • 批量人脸替换:对系列插画、场景图进行统一人脸替换,保证多图人脸特征一致,提升创作效率。

InstantID 换脸预处理器的关键参数:

  • 通过选择不同的预处理器,适配不同换脸精准度需求。
  • 如:face_embedding 为换脸基础,face_keypoints 可提取人脸关键点,辅助强化五官位置精准度。

其他预处理器

部分 ControlNet 预处理器虽使用频率略低,但能解决特定场景的控图需求,可根据创作目标灵活选用。

  • NormalMap 正态法线贴图预处理器用于提取图像的法线方向信息生成贴图,强化物体的光影立体感与材质质感,适配 3D 渲染、游戏模型等场景。
  • Scribble/Sketch 涂鸦/草图预处理器用于将任意手绘涂鸦、简易线稿转化为结构控制图,基于粗糙线条生成对应风格的完整图像,降低创作门槛。
  • Shuffle 随机洗牌预处理器用于打乱原图的内容元素,保留风格,生成与原图风格一致但内容不同的新图像,适合快速拓展同风格素材。
  • InstructP2P 指导生图预处理器用于通过文字指令精准控制图像局部修改,实现文字驱动的定向生图,无需手动蒙版。
  • Reference 参考预处理器用于提取参考图的风格、内容特征,让生成图与参考图保持风格或元素一致性,兼顾创意与参考特征的复用。
  • Revision 预处理器用于基于原图与文字指令,对图像进行局部或全局的优化修订,实现精准的图像迭代优化。
  • T2I-Adapter 预处理器用于将文字描述转化为多维度控制信号,辅助 Stable Diffusion 生成更贴合文字指令的图像,强化文生图的精准度。
  • PuLID 换脸基于像素级人脸特征匹配,用于提取参考脸的皮肤纹理、细微神态等细节,实现高精度换脸,适配写真、商业人像等场景。
]]>
0 https://www.duox.dev/post/138.html#comments https://www.duox.dev/feed/post/138.html
Stable Diffusion AIGC 视觉设计实战教程之 08-高级图像处理 https://www.duox.dev/post/137.html https://www.duox.dev/post/137.html Sun, 21 Dec 2025 12:19:00 +0000 多仔

AI 摘要

本文系统梳理 Stable Diffusion 的高清放大与高级图像处理方案:详解 Hires.fix 两阶段重绘、后期处理、图生图、SD Upscale、Ultimate SD Upscale、Tiled Diffusion 等六种放大策略及参数设置;介绍 Layer diffusion 原生透明图生成、ADetailer 人脸手部智能修复、Inpaint Anything 点击分割重绘三大插件用法;并说明 PNG 元数据读取与保护技巧,为 AIGC 视觉设计提供一站式技术参考。

高清放大

高分辨率修复

Stable Diffusion 文生图的高分辨率修复(Hires.fix)核心采用低分辨率打底 + 高分辨率重绘的两阶段流程,既能提升分辨率,又能保证构图与细节,是解决大尺寸生成模糊、细节不足等问题的方案。

高分辨率修复分两步完成高清化:

  • 第一阶段:按设定的低分辨率生成基础图,确保构图准确。
  • 第二阶段:将基础图通过放大算法提升至目标分辨率,再添加适量噪声后,用扩散模型去噪重绘,补充细节并修正失真,最终输出高清图。

高分辨率修复的核心参数:

  • 放大算法:决定低分辨率图放大到高分辨率时的像素重建逻辑,直接影响细节精度与风格匹配度。
  • 放大倍率:从基础低分辨率图到最终高分辨率图的缩放比例(等比缩放),低显存优先选择 1.5~2.0 倍,生成超大幅图不建议单次使用高倍率。
  • 将宽度/高度调整到:手动指定缩放的宽度和高度。
  • 重绘幅度:控制高分辨率修复第二阶段去噪重绘的幅度,取值范围为 0~1,0 即完全不重绘仅简单放大,1 即完全抛弃原图重新生成高分辨率图,0.3~0.5 能保留 90%+ 原构图,新增中等细节(如皮肤纹理、毛发等),适合绝大多数场景。重绘幅度尽可能不要超过 0.6,避免出现变形风险。
  • 重绘采样步数:控制高分辨率修复第二阶段去噪重绘的步数,推荐取值范围为基础迭代步数的 2/3。

高分辨率修复常用的放大算法:

  • R-ESRGAN 4x+:通用型算法,细节锐化强,修复模糊边缘效果好,适合照片、写实插画、风景图等高清放大,但过度锐化易产生塑料感。
  • R-ESRGAN 4x+ Anime6B:针对二次元优化,线条更流畅,色彩更鲜艳,适合动漫、漫画、二次元角色图等高清放大,用于写实图高清放大时容易失真。
  • SwinIR 4x:细节还原细腻,保留纹理自然度(如皮肤、布料等),适合人像、写实摄影、高精度插画等高清放大,但生成速度较慢,对模糊图修复力弱。
  • Latent:潜空间放大,在画面放大的同时不会增加画面细节,但整体比较柔和,适合所有场景。
  • 4x_NMKD-Superscale:平衡细节与自然度,对低清图修复效果突出,适合老照片修复、低分辨率素材重绘,但生成时间较长。
  • Lanczos:轻量、快速且风格中性的图像放大算法,低失真、无过度锐化,适合作为主算法快速预览,或作为辅算法修正其他强锐化算法的缺陷。

以生成一张人物写实图为例,参考生成参数如下。

  • ckpt 检查点模型:麦橘超然 majicFlus
  • 正向提示词(中文):一个女孩,独自一人,从下方视角,樱花,户外,棕色头发,白天,衬衫,写实风格,天空,棕色眼睛,蓝天,模糊,粉色衬衫,嘴唇,微张的嘴唇,条纹衬衫,上半身,向下看,条纹,树
  • 正向提示词(英文):1girl, solo, from below, cherry blossoms, outdoors, brown hair, day, shirt, realistic, sky, brown eyes, blue sky, blurry, pink shirt, lips, parted lips, striped shirt, upper body, looking down, striped, tree
  • 负向提示词(英文):ng_deepnegative_v1_75t,(badhandv4:1.2),EasyNegative,(worst quality:2)
  • 采样方法:Euler a
  • 迭代步数:20
  • 提示词引导系数:7
  • 图片尺寸:512x512

生成效果:

调整生成参数如下。

  • 随机数种子:955073264
  • 高分辨率修复:开启
  • 放大算法:R-ESRGAN 4x+
  • 放大倍率:3(512x512~1536x1536)
  • 放大重绘幅度:0.3

生成效果:

后期处理附加功能放大

Stable Diffusion 中的附加功能后期处理,也为创作者提供了丰富的图片处理选项,创作者也可以使用附加功能后期处理实现高清放大。

后期处理附加功能放大允许用户自己上传自己的图片,并直接提高图片的分辨率,不会对原图进行任何形式的重绘和修改,而是直接对图片的分辨率进行提升。

后期处理附加功能高清放大的核心参数:

  • 放大倍率、将宽度/高度调整到:调整放大的尺寸/倍率。
  • 放大算法:支持 Upscaler1(主算法)、Upscaler2(可选辅助算法),主算法 + 辅助算法结合可以在一定程度上避免单算法的锐化过度、油光或细节不足等问题。
  • Upscaler 2 可见度:用来调节辅算法与主算法的混合比例。取值范围为 0~1,数值越小,主算法的效果占比越高,数值越接近 1,辅助算法的效果占比越高。
  • GFPGAN 可见度:针对模糊、变形、低清人脸的修复算法,能快速改善严重失真的人脸,但修复过度时容易出现塑料感或面部细节丢失。取值范围为 0~1,数值越大,对应的人脸修复算法效果越明显,数值越小,则越贴近原图的人脸质感,修复效果越弱。
  • CodeFormer 可见度:更精细的人脸修复算法,修复效果更自然,对皮肤纹理、五官细节的保留更好,塑料感远低于 GFPGAN,适合对人脸真实度要求高的场景。

下图原始尺寸为 512x512。

以上图为例进行后期处理附加功能放大,参考生成参数如下。

  • 放大倍率:4(512x512~2048x2048)
  • Upscaler1:R-ESRGAN_4x+
  • Upscaler2:Lanczos
  • Upscaler 2 可见度:0.3
  • CodeFormer 可见度:0.8

生成效果:

图生图直接放大

在 Stable Diffusion 中,高清放大图像还可以借助图生图功能设置图像的分辨率和重绘幅度等参数来实现,但此方法也有尺寸上限的局限性,当分辨率过大时可能会导致无法生图等问题。

SD Upscale

SD Upscale 插件是 Stable Diffusion 的专用放大脚本,是早期实现超分放大的标准化工具,在一些本地部署的 Stable Diffusion 中可以使用该内置插件实现高清放大。

SD Upscale 的核心原理是将原图切割成一个个图块,针对每一个图块分别进行高清修复,完成修复后再将这些图块重新拼接,最终得到放大且高清的图像。

在这个过程中,分块重叠像素宽度扮演着关键角色,其本质是为了避免拼接痕迹,提升图像的整体连贯性。由于每个图块在修复时是独立进行的,如果图块之间没有重叠部分,直接拼接可能会在接缝处出现明显的色差、纹理不连续等问题。

设置分块重叠像素宽度后,在修复过程中,这部分重叠区域会被重复处理,模型会综合考虑相邻图块的信息,对重叠部分进行融合优化。当完成所有图块的修复和拼接后,重叠区域经过处理,使得图像过渡自然,大幅减少了拼接产生的违和感,最终呈现出视觉效果更好的放大图像。

Ultimate SD Upscale

Ultimate SD Upscale(USD)是 SD Upscale 的进阶扩展插件,核心优势在于更强的细节控制、无缝拼接与显存适配,适合高倍数、超高清放大、精细细节修复。

Ultimate SD Upscale 插件的安装与使用:https://github.com/Coyote-A/ultimate-upscale-for-automatic1111

Tiled Diffusion

Tiled Diffusion 是 Stable Diffusion 的高分辨率生成专用扩展插件,核心逻辑是将目标尺寸的大图,按规则分割成多个独立小图块,分别执行扩散生成、放大计算,最后通过算法无缝拼接,能以更小的计算成本更稳定地输出超高清图像,速度快、细节完整。

Tiled Diffusion 是由 Tiled Diffusion 插件、Tiled VAE 插件组成,Tiled Diffusion 负责高分辨率图像的分块生成与无缝拼接,Tiled VAE 负责分块编码解码以避免画质崩坏,二者是高分辨率生成的配套组合,在使用时必须同时启用才能兼顾低显存占用与高清画质。

Tiled Diffusion 和 SD Upscale 的核心区别:

  • Tiled Diffusion 在潜空间分块计算,显存占用极低,而 SD Upscale 在像素空间分步放大 + 重绘,显存压力大。
  • Tiled Diffusion 主打一步到位生成、放大 8K 级大图,而 SD Upscale 适合中小尺寸分步放大。
  • Tiled Diffusion 全局一致性强,但参数不当易出拼接缝,而 SD Upscale 无拼接问题,但分步重绘可能有风格断层。

本地部署的 Stable Diffusion 需要自行安装 Tiled Diffusion 插件、Tiled VAE 插件,LiblibAI 已内置该插件,使用时需要注意部分检查点模型不支持使用 Tiled Diffusion 插件。

Tiled Diffusion 的安装与使用:https://github.com/pkuliyi2015/multidiffusion-upscaler-for-automatic1111

Tiled Diffusion 的核心参数:

模块名称描述推荐
Tiled Diffusion
通用
方案Mixture of Diffusers 适合局部重绘
MultiDiffusion 能确保分块内容一致性,生成大图无明显拼接痕
MultiDiffusion
潜空间分块宽 / 高用于把超大尺寸图片的运算空间拆成小块分别处理
取值范围 = 16 ~ (检查点模型能生成的最大图片尺寸 / 8)
96
潜空间分块重叠设置相邻分块的重叠区域,消除拼接缝
MultiDiffusion 方案设置为 32 或 48
Mixture of Diffusers 方案设置为 16 或 32
48
分块单批数量指定一次同时处理多少个拆分好的小块,数量越少越省显存、越稳定1
分区提示词控制把图像按潜空间分块划分为多个区域,给每个区域单独写提示词-
Tiled Diffusion
文生图
覆盖图像尺寸勾选后按目标分辨率计算分块,可突破原生图片尺寸限制-
Tiled Diffusion
图生图
保持输入图像大小控制图生图的输出尺寸是否与原图一致
用于修复细节勾选,用于超清放大取消勾选
-
放大倍数放大后图片尺寸 = 原图尺寸 x 放大倍数-
放大算法无约束,优先 LanczosLanczos
噪声反转高清放大必开,细节修复可选-
反转步数越小越贴近原图,越大创作空间越大10
修复程度数值越大越贴近原图-
重铺噪声强度数值越大,越能增加噪声随机性,生成的细节更丰富
数值过高会偏离原图
≤0.6
重铺噪声大小数值越大,噪声覆盖的区域越广,越适合优化大场景细节
64
Tiled VAE编码器分块大小控制 VAE 编码阶段的分块尺寸,单位为潜空间单位
用于降低显存峰值占用,实现大尺寸图像编码
建议在 CUDA error: out of memory 报错前尽可能大的设置其值
1024
解码器分块大小控制 VAE 解码阶段的分块尺寸,单位为潜空间单位
用于匹配编码器分块逻辑,延续显存优化策略
192
快速编码解码器启用轻量化编解码算法,开启后速度提升 30%-50%开启
快速编码器颜色修复校准分块色偏,优先开启开启

以生成一张人物写实图为例,参考生成参数如下。

  • ckpt 检查点模型:majicMIX realistic 麦橘写实_v7
  • 正向提示词(中文):两个穿着圣诞毛衣的可爱女孩,身处雪景之中,水彩画风格,在艺术网站上热门,焦点清晰,工作室照片,细节精致,高度写实
  • 正向提示词(英文):two adorable gril,wearing christmas sweaters,in a snowy christmas scene,Watercolor,trending on artstation,sharp focus,studio photo,intricate details,highly detailed
  • 负向提示词:ng_deepnegative_v1_75t,(badhandv4:1.2),EasyNegative,(worst quality:2)
  • 采样方法:Euler a
  • 迭代步数:25
  • 图片尺寸:768x1024
  • 提示词引导系数:7

生成效果:

将上图发送至图生图,参考生成参数如下。

  • 重绘幅度:0
  • 随机数种子:757092860

Tiled Diffusion/Tiled VAE 参考插件参数如下。

  • Tiled Diffusion/Tiled VAE:开启
  • 方案:MultiDiffusion
  • 放大算法:R-ESRGAN_4x+
  • 放大倍数:4(768x1024~3072x4096)

生成后对比效果:

LiblibAI 超清放大

超清放大是由 LiblibAI 自带的的类似于 Tiled Diffusion 插件的高清放大功能。

超清放大的核心参数:

  • 重绘幅度:建议不超过 0.4,过高的重绘幅度会导致画面变化过大,以及画出不需要的元素。
  • 全面增强:重绘幅度高于 0.5 时建议开启,有助于在保持一致性的同时丰富图像细节。此设置在基础算法 1.5 下表现更稳定,基础算法 XL 下可能会出现色彩失真的情况。
  • 细节强化:丰富画面细节,但可能导致画面内容变化。
  • 画质增强:提升画质,建议在 0.5~1.5 之间调节。

高级图像处理插件

Layer diffusion

Layer diffusion 是由 lllyasviel 团队推出的 Stable Diffusion 扩展技术,能让 Stable Diffusion 支持原生生成带 Alpha 通道的透明图像与多图层内容,无需额外抠图,适配 SD 1.5/XL,大幅提升设计类图像的生产效率。

本地部署的 Stable Diffusion 需要自行安装 Layer diffusion 插件,LiblibAI 已内置该插件。

Layer diffusion 的安装与使用:https://github.com/layerdiffusion/sd-forge-layerdiffuse

Layer diffusion 的核心参数:

  • 启用开关:开启 Layer diffusion 后最终图片尺寸会自适应到 64 的倍数。
  • Method:指定 Layer diffusion 的工作机制,适配不同的模型版本与生成目标。
  • Weight:控制 Layer diffusion 的透明效果强度,决定背景被替换为透明的程度。取值范围为 0~2,1.0 即标准透明强度,背景完全透明且主体边缘干净,数值越高透明效果增强,但可能误将主体边缘判定为背景。
  • Stop at:控制 Layer diffusion 在扩散过程中停止干预的时机,平衡透明效果与内容完整性。取值范围为 0~1,1.0 即 Layer diffusion 全程参与扩散,透明效果最彻底,但复杂场景可能出现主体细节缺失。

以生成一张电商产品图为例,参考生成参数如下。

  • ckpt 检查点模型:电商产品场景_XL
  • 正向提示词(中文):超高清细节,图像展现了一个时尚的矩形香水瓶,配有金色瓶盖和标签,瓶子放置在反光表面上,营造出戏剧性的阴影,光线从上方照射在瓶子上,在深色背景的映衬下,凸显出其优雅的设计
  • 正向提示词(英文):ultra high definition details,the image features a sleek,rectangular perfume bottle with a gold cap and label,the bottle is placed on a reflective surface,creating a dramatic shadow,light rays illuminate the bottle from above,highlighting its elegant design against a dark background
  • 负向提示词:ng_deepnegative_v1_75t,(badhandv4:1.2),EasyNegative,(worst quality:2)
  • 采样方法:DPM++ 2M Karras
  • 迭代步数:30
  • 图片尺寸:768x1024
  • 提示词引导系数:7

Layer diffusion 参考插件参数如下。

  • Layer diffusion:开启
  • Method:(基础算法 XL) 生成透明底的图片 (Conv Injection)
  • Weight:1.0
  • Stop at:1.0

生成效果:

ADetailer

ADetailer(After Detailer)是 Stable Diffusion 的核心细节修复插件,在生成后自动检测人脸、手部等易崩坏区域,通过蒙版 + 局部重绘提升细节,适配 SD1.5/XL,是解决脸崩手残的高效工具。

本地部署的 Stable Diffusion 需要自行安装 ADetailer 插件,LiblibAI 已内置该插件。

ADetailer 的安装与使用:https://github.com/Bing-su/adetailer

ADetailer 的核心参数:

  • 模型选择:选择检测目标时所使用的模型,如人脸 face_xxx.pt、手部 hand_xxx.pt、身体 person_xxx.pt 等。
  • ADetailer 正向提示词:修复区域专用正向提示词,针对性强化细节,避免风格漂移。
  • ADetailer 负向提示词:修复区域专用负向提示词,补充模糊、失真、结构异常等负向提示词,抑制缺陷。
  • 目标检测阈值:控制哪些区域会被判定为目标。取值范围为 0~1,数值越高越严格、误检越少,但也越容易漏检小/模糊目标。
  • 最小面积比例:按蒙版面积占图像总面积的比例设定下限,仅保留 >= 该值的蒙版。取值范围为 0~1,数值越高越易筛除小噪点、杂物,但也可能漏检小目标。
  • 最大面积比例:按蒙版面积占图像总面积的比例设定上限,仅保留 <= 该值的蒙版。取值范围为 0~1,数值越高越允许大目标蒙版,越低越能防止蒙版覆盖大区域导致画面崩坏。
  • 蒙版的预处理:用于对 ADetailer 自动检测生成的蒙版进行位移、缩放、模糊、合并等调整,校准目标区域范围、柔化边缘,避免重绘出现生硬边界。
  • 局部重绘:仅用于对预处理后的蒙版区域执行图像重绘,通过去噪强度、采样步数等参数控制修复幅度,在保留原图风格的前提下优化目标区域细节。

以生成一张人物写实图为例,参考生成参数如下。

  • ckpt 检查点模型:majicMIX realistic 麦橘写实_v7
  • 正向提示词(中文):一个女孩
  • 正向提示词(英文):1girl
  • 负向提示词:ng_deepnegative_v1_75t,(badhandv4:1.2),EasyNegative,(worst quality:2)
  • 采样方法:Euler a
  • 迭代步数:20
  • 图片尺寸:512x512
  • 提示词引导系数:7

生成效果:

调整生成参数如下。

  • 随机数种子:4063326573

ADetailer 参考插件参数如下。

  • ADetailer:开启
  • 模型选择:face_yolov8n
  • 目标检测阈值:0.3

生成效果:

Inpaint Anything

Inpaint Anything 是一款基于 Segment Anything Model(SAM)的智能局部重绘插件,核心是点击即分割、文本控生成,无需手动精细绘制蒙版,即可精准移除、替换或填充图像中任意物体、区域,适配物体移除、背景替换、局部内容生成等场景。

本地部署的 Stable Diffusion 需要自行安装 Inpaint Anything 插件,LiblibAI 已内置该插件。

Inpaint Anything 的安装与使用:https://github.com/Uminosachi/sd-webui-inpaint-anything

下图原始尺寸为 1024x1024,以下图为例进行局部重绘。

打开 Inpaint Anything 插件,将需要重绘的图片上传至 Inpaint Anything 插件,确认已选好 SAM 模型,点击 Run Segment Anything,生成彩色分割图。

在彩色分割图中,使用画笔工具涂抹或点击分割图中需重绘的目标区域,点击创建蒙版,下方会显示选中的蒙版区域。

在蒙版区域中,根据实际情况修剪、添加蒙版。

切换到仅蒙版标签,点击获取蒙版,再点击发送到图生图重绘,在图生图页面进一步调整参数。

以上图为例进行图生图,参考生成参数如下。

  • ckpt 检查点模型:F.1-dev-fp8
  • 正向提示词(中文):宽松的粉色短款 T 恤
  • 正向提示词(英文):Loose pink short-sleeved T-shirt,
  • 负向提示词(英文):ng_deepnegative_v1_75t,(badhandv4:1.2),EasyNegative,(worst quality:2)
  • 采样方法:Euler
  • 迭代步数:30
  • 提示词引导系数:3.5
  • 图片尺寸:1024x1024
  • 缩放模式:填充
  • 蒙版边缘模糊度:6
  • 重绘幅度:0.95
  • 蒙版模式:重绘蒙版内容

生成效果:

PNG 图片信息

获取图片信息

PNG 图片信息是核心实用功能,可以读取由 Stable Diffusion 平台生成的 PNG 图片中内嵌的生成元数据,快速复用这些参数到其他功能模块,不管是复刻自己的作品,还是学习他人的创作参数都很便捷。

只有 Stable Diffusion 生成且未清除元数据的 PNG 图才能读取到这些元信息,非 Stable Diffusion 生成或二次编辑、重新保存导致元数据丢失的图片,无法读取到对应内容。

PNG 图片信息功能仅针对 PNG 图的元数据做读取,并非通过 AI 反推图像参数,和 CLIP 反推、DeepBooru 反推、WD 1.4 标签器等提示词反推功能有着本质区别。

如果想保护自己的创作参数不被他人读取,可通过 Photoshop 等工具重新导出图片,这样会清除图片中的生成元数据。

]]>
0 https://www.duox.dev/post/137.html#comments https://www.duox.dev/feed/post/137.html