PHP 身份证号码校验进阶技巧分享(附代码示例) PHP

PHP的生态非常丰富,但身份证号码校验依然是最常用的功能点之一。本文整理了最实用的几种实现方式。


emer 发布于  2026-10-10 08:20 

PHP 字符串反转快速上手指南(建议收藏) PHP

很多线上 Bug 的根源,都在于对字符串反转的理解不够深入。本文从常见错误出发,反推正确的使用姿势。


emer 发布于  2026-10-10 08:16 

PHP常用数组函数,10个必须掌握 PHP

前言

PHP数组函数太多了,记不住?本文整理了10个最常用的数组函数,写代码天天用,必须掌握。

一、array_column — 取数组某一列

用法

$users = [
    ['id' => 1, 'name' => '张三'],
    ['id' => 2, 'name' => '李四'],
    ['id' => 3, 'name' => '王五']
];

$names = array_column($users, 'name');
// 结果:['张三', '李四', '王五']

取列并指定键

$userMap = array_column($users, 'name', 'id');
// 结果:[1 => '张三', 2 => '李四', 3 => '王五']

二、array_map — 遍历处理数组

用法

$numbers = [1, 2, 3, 4, 5];

$squares = array_map(function($n) {
    return $n * $n;
}, $numbers);
// 结果:[1, 4, 9, 16, 25]

实际应用

// 把所有名字转成大写
$names = ['zhang', 'li', 'wang'];
$upperNames = array_map('strtoupper', $names);
// 结果:['ZHANG', 'LI', 'WANG']

三、array_filter — 过滤数组

用法

$numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

$even = array_filter($numbers, function($n) {
    return $n % 2 == 0;
});
// 结果:[2, 4, 6, 8, 10]

过滤空值

$arr = ['a', '', 0, null, 'b', '0'];
$result = array_filter($arr);
// 结果:['a', 'b']

四、array_merge — 数组合并

用法

$arr1 = ['a', 'b'];
$arr2 = ['c', 'd'];

$merged = array_merge($arr1, $arr2);
// 结果:['a', 'b', 'c', 'd']

关联数组合并

$arr1 = ['name' => '张三', 'age' => 20];
$arr2 = ['age' => 25, 'city' => '北京'];

$merged = array_merge($arr1, $arr2);
// 结果:['name' => '张三', 'age' => 25, 'city' => '北京']
// 注意:age被后面的覆盖了

五、in_array — 判断值是否在数组里

用法

$fruits = ['apple', 'banana', 'orange'];

if (in_array('apple', $fruits)) {
    echo '有苹果';
}

注意严格模式

$arr = [1, '2', '3'];

in_array(2, $arr); // true(因为类型转换了)
in_array(2, $arr, true); // false(严格模式)

六、array_keys — 取数组的键

用法

$user = ['name' => '张三', 'age' => 20, 'city' => '北京'];

$keys = array_keys($user);
// 结果:['name', 'age', 'city']

找某个值的键

$ages = [
    '张三' => 20,
    '李四' => 25,
    '王五' => 30
];

$keys = array_keys($ages, 25);
// 结果:['李四']

七、array_values — 取数组的值

用法

$user = ['name' => '张三', 'age' => 20, 'city' => '北京'];

$values = array_values($user);
// 结果:['张三', 20, '北京']

八、array_sum — 数组求和

用法

$numbers = [1, 2, 3, 4, 5];

$sum = array_sum($numbers);
// 结果:15

九、count — 统计数组长度

用法

$fruits = ['apple', 'banana', 'orange'];

$count = count($fruits);
// 结果:3

多维数组

$users = [
    ['name' => '张三'],
    ['name' => '李四']
];

count($users); // 2
count($users, COUNT_RECURSIVE); // 4(递归统计)

十、explode / implode — 字符串和数组互转

explode — 字符串转数组

$str = 'apple,banana,orange';

$fruits = explode(',', $str);
// 结果:['apple', 'banana', 'orange']

implode — 数组转字符串

$fruits = ['apple', 'banana', 'orange'];

$str = implode(',', $fruits);
// 结果:'apple,banana,orange'

十一、常用场景

场景1:从数据库取数据,提取某列

$users = Db::name('user')->select();
$names = array_column($users, 'name');

场景2:过滤空值

$list = array_filter($list);

场景3:判断是否存在

if (in_array($userId, $adminIds)) {
    // 是管理员
}

场景4:数组去重后转字符串

$tags = array_unique($tags);
$tagStr = implode(',', $tags);

十二、常见坑

坑1:array_merge关联数组键名覆盖

问题: 相同键名会被覆盖。

解决: 用+号或array_replace。

坑2:in_array类型不严格

问题: in_array(0, ['a', 'b'])返回true。

解决: 加第三个参数true,严格模式。

坑3:count返回0

问题: 传了null进去。

解决: 先判断是不是数组。

总结

10个必须掌握的数组函数:

  1. array_column — 取某一列
  2. array_map — 遍历处理
  3. array_filter — 过滤
  4. array_merge — 合并
  5. in_array — 判断存在
  6. array_keys — 取键
  7. array_values — 取值
  8. array_sum — 求和
  9. count — 统计长度
  10. explode/implode — 字符串数组互转

记住:

  • 天天用的就是这10个
  • 写代码前先想想有没有现成函数
  • 别自己写循环,用内置函数更快

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-9 07:57 

PHP实现简单分页,SQL limit用法 PHP

前言

做网站列表页,数据太多一页显示不完,需要分页。PHP+MySQL做分页很简单,就是用SQL的limit。本文写个完整的分页示例,直接拿去用。

一、分页原理

分页就两件事:

  1. 查总条数:看看一共有多少条数据
  2. 查当前页数据:用limit取当前页要显示的那几条

公式:

偏移量 = (当前页 - 1) × 每页条数

比如每页10条,第3页:

偏移量 = (3 - 1) × 10 = 20
SQL: SELECT * FROM users LIMIT 20, 10

二、SQL limit用法

语法

SELECT * FROM 表名 LIMIT 偏移量, 每页条数

例子

-- 取前10条
SELECT * FROM users LIMIT 0, 10;

-- 取第11-20条
SELECT * FROM users LIMIT 10, 10;

-- 取第21-30条
SELECT * FROM users LIMIT 20, 10;

三、完整分页代码

第一步:接收当前页码

<?php
// 当前页,默认第1页
$page = isset($_GET['page']) ? intval($_GET['page']) : 1;

// 每页显示多少条
$pageSize = 10;

// 计算偏移量
$offset = ($page - 1) * $pageSize;

第二步:查总条数

// 连接数据库
$conn = mysqli_connect('127.0.0.1', 'root', '123456', 'test', 3306);
mysqli_set_charset($conn, 'utf8mb4');

// 查总条数
$sql = "SELECT COUNT(*) as total FROM users";
$result = mysqli_query($conn, $sql);
$row = mysqli_fetch_assoc($result);
$total = $row['total'];

// 算总页数
$totalPage = ceil($total / $pageSize);

第三步:查当前页数据

// 查当前页的数据
$sql = "SELECT id, name, age FROM users ORDER BY id DESC LIMIT $offset, $pageSize";
$result = mysqli_query($conn, $sql);

// 取数据
$list = [];
while ($row = mysqli_fetch_assoc($result)) {
    $list[] = $row;
}

第四步:显示数据和分页导航

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>用户列表</title>
</head>
<body>

<h1>用户列表</h1>

<table border="1">
    <tr>
        <th>ID</th>
        <th>姓名</th>
        <th>年龄</th>
    </tr>
    <?php foreach ($list as $item): ?>
    <tr>
        <td><?php echo $item['id']; ?></td>
        <td><?php echo $item['name']; ?></td>
        <td><?php echo $item['age']; ?></td>
    </tr>
    <?php endforeach; ?>
</table>

<p>共 <?php echo $total; ?> 条,第 <?php echo $page; ?> / <?php echo $totalPage; ?> 页</p>

<p>
    <?php if ($page > 1): ?>
    <a href="?page=<?php echo $page - 1; ?>">上一页</a>
    <?php endif; ?>

    <?php for ($i = 1; $i <= $totalPage; $i++): ?>
        <?php if ($i == $page): ?>
            <strong><?php echo $i; ?></strong>
        <?php else: ?>
            <a href="?page=<?php echo $i; ?>"><?php echo $i; ?></a>
        <?php endif; ?>
    <?php endfor; ?>

    <?php if ($page < $totalPage): ?>
    <a href="?page=<?php echo $page + 1; ?>">下一页</a>
    <?php endif; ?>
</p>

</body>
</html>

四、封装成分页函数

function pagination($page, $totalPage, $url = '')
{
    $html = '';

    if ($page > 1) {
        $html .= '<a href="' . $url . '?page=' . ($page - 1) . '">上一页</a> ';
    }

    for ($i = 1; $i <= $totalPage; $i++) {
        if ($i == $page) {
            $html .= '<strong style="margin:0 5px;">' . $i . '</strong> ';
        } else {
            $html .= '<a href="' . $url . '?page=' . $i . '" style="margin:0 5px;">' . $i . '</a> ';
        }
    }

    if ($page < $totalPage) {
        $html .= '<a href="' . $url . '?page=' . ($page + 1) . '">下一页</a>';
    }

    return $html;
}

// 使用
echo pagination($page, $totalPage);

五、常见坑

坑1:页码没做限制

用户输入 ?page=999,结果查出来是空的。

解决: 限制页码范围:

$page = max(1, min($page, $totalPage));

坑2:offset算错了

$offset = $page * $pageSize; // 错!

正确:

$offset = ($page - 1) * $pageSize; // 对!

坑3:总条数查错了

带条件查询的时候,总条数也要带条件。

比如:

// 带条件查数据
$sql = "SELECT * FROM users WHERE status = 1 LIMIT $offset, $pageSize";

// 总条数也要带条件
$sql = "SELECT COUNT(*) FROM users WHERE status = 1";

坑4:大表分页越查越慢

数据多了以后,LIMIT 100000, 10 会很慢。

原因: MySQL要先扫描前面10万条再跳过。

优化:

-- 先查id,再关联
SELECT u.* FROM users u
INNER JOIN (SELECT id FROM users ORDER BY id LIMIT 100000, 10) t
ON u.id = t.id;

六、带搜索条件的分页

// 搜索关键词
$keyword = isset($_GET['keyword']) ? trim($_GET['keyword']) : '';

// 拼WHERE
$where = "WHERE 1=1";
if ($keyword) {
    $where .= " AND name LIKE '%$keyword%'";
}

// 总条数
$sql = "SELECT COUNT(*) as total FROM users $where";

// 当前页数据
$sql = "SELECT * FROM users $where ORDER BY id DESC LIMIT $offset, $pageSize";

总结

记住:

  1. 分页就是 LIMIT 偏移量, 每页条数
  2. 偏移量 = (当前页 - 1) × 每页条数
  3. 先查总条数,再算总页数
  4. 页码要做限制,不能超出范围
  5. 带条件查询时,总条数也要带条件

核心公式:

$page = isset($_GET['page']) ? intval($_GET['page']) : 1;
$pageSize = 10;
$offset = ($page - 1) * $pageSize;

$sql = "SELECT * FROM users LIMIT $offset, $pageSize";

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-9 07:37 

PHP报错Permission denied权限问题解决 PHP

前言

PHP写文件、读文件、上传文件,突然报"Permission denied"?这是Linux文件权限问题,最常见就是文件或目录的所有者不对、权限不够。本文讲怎么排查和解决。

一、报错长啥样

Warning: fopen(/data/test.txt): failed to open stream: Permission denied in /www/test.php on line 5

意思:PHP没权限操作这个文件/目录。

二、常见原因

原因1:文件/目录权限不够

PHP没有读或写的权限。

原因2:文件/目录所有者不对

PHP用www用户跑,但文件是root创建的,www没权限。

原因3:SELinux开着

CentOS默认开SELinux,即使权限对了也不让访问。

原因4:目录权限不够

要写文件的话,目录本身也要有写权限。

三、排查步骤

第一步:看报错的文件路径

报错信息里会告诉你是哪个文件:

Permission denied: /data/upload/test.jpg

就是 /data/upload/ 这个目录的问题。

第二步:看文件权限

ls -l /data/upload/

输出类似:

-rw-r--r-- 1 root root 1024 Oct  9 10:00 test.txt

看第一个字段:

  • -rw-r--r-- 表示所有者能读写,其他人只能读

看所有者:

  • root root 表示所有者和组都是root

第三步:看PHP用什么用户跑

ps aux | grep php-fpm

输出里会看到:

www   1234  0.0  0.5 123456 7890  ?  S  10:00  0:00 php-fpm: pool www

PHP是用 www 用户跑的。

如果文件所有者是root,那www用户就没权限写。

四、解决方法

方法1:改文件所有者

把文件/目录的所有者改成PHP的用户:

# 改单个文件
chown www:www /data/upload/test.txt

# 改整个目录(包括里面的文件)
chown -R www:www /data/upload/

推荐这个方法,最安全。

方法2:改权限

给所有人加权限:

# 文件加写权限
chmod 666 /data/upload/test.txt

# 目录加写权限
chmod 777 /data/upload/

注意: 777太不安全了,尽量用方法1改所有者。

方法3:看SELinux

CentOS开了SELinux的话,即使权限对了也不行。

检查SELinux:

getenforce

输出 Enforcing 就是开着。

临时关掉:

setenforce 0

永久关掉:

vi /etc/selinux/config

把:

SELINUX=enforcing

改成:

SELINUX=disabled

重启服务器生效。

或者只给目录加SELinux权限:

chcon -R -t httpd_sys_rw_content_t /data/upload/

五、常见场景

场景1:上传图片报错

用户上传图片,报Permission denied。

原因: uploads目录所有者不对。

解决:

chown -R www:www /www/wwwroot/你的站/uploads/

场景2:写日志报错

PHP写日志文件,报Permission denied。

原因: 日志目录没权限。

解决:

chown -R www:www /var/log/你的应用/

场景3:session不存

PHP session存不进去。

原因: session目录没权限。

解决:

chown -R www:www /var/lib/php/session/

场景4:缓存目录没权限

ThinkPHP/Laravel缓存写不进去。

原因: runtime目录没权限。

解决:

chown -R www:www runtime/

六、常用命令

看文件权限

ls -l 文件名

看目录权限

ls -ld 目录名

改所有者

chown 用户:组 文件
chown -R 用户:组 目录

改权限

chmod 755 目录
chmod 644 文件

七、权限数字含义

数字 含义
7 读+写+执行 (4+2+1)
6 读+写 (4+2)
5 读+执行 (4+1)
4 只读

常用:

  • 目录:755
  • 文件:644
  • 上传目录:775(或改所有者)

八、常见坑

坑1:只改了文件,没改目录

要写文件的话,目录本身也要有写权限。

解决: 目录也要改所有者。

坑2:递归改权限

chmod -R 777 目录

太危险了,所有人都能写。

解决: 优先改所有者,不要随便777。

坑3:SELinux偷偷开着

CentOS7以后默认开SELinux,权限对了也不行。

检查:

getenforce

坑4:父目录没权限

比如 /data/upload/ 有权限了,但 /data/ 没权限,还是进不去。

解决: 从根开始一层一层检查。

总结

记住:

  1. 报错先看是哪个文件/目录
  2. 看文件所有者是不是PHP的用户(一般是www)
  3. 不是就 chown -R www:www 目录
  4. 还不行就检查SELinux
  5. 尽量改所有者,不要随便777

最常用:

chown -R www:www /你的目录/

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-9 07:36 

PHP file_get_contents获取https内容失败 PHP

前言

PHP用file_get_contents获取http内容没问题,换成https就报错了?这是最常见的问题,一般就是openssl扩展没开,或者SSL证书验证没过。本文讲怎么解决。

一、问题现象

<?php
$url = 'https://api.example.com/data';
$result = file_get_contents($url);

echo $result;

结果报错:

Warning: file_get_contents(): failed to open stream: Unable to find the wrapper "https"

或者:

Warning: file_get_contents(): SSL operation failed with code 1

二、常见原因

原因1:openssl扩展没装

PHP默认不开openssl扩展,file_get_contents不支持https。

原因2:allow_url_open没开

php.ini里禁了远程打开。

原因3:SSL证书验证失败

对方网站证书有问题,PHP验证不通过。

原因4:网络问题

服务器出不去,或者DNS解析不了。

三、排查步骤

第一步:看openssl扩展装了没

php -m | grep openssl

有输出就是装了,没输出就是没装。

或者写个phpinfo:

<?php
phpinfo();

搜"openssl",看有没有。

第二步:看allow_url_open开了没

<?php
echo ini_get('allow_url_fopen');

输出1就是开了,空就是没开。

第三步:用curl测试

curl https://api.example.com/data

curl能通就是PHP的问题,curl也不通就是网络问题。

四、解决方法

方法1:装openssl扩展(推荐)

CentOS

yum install php-openssl

或者:

yum install php7x-openssl

(x是你的PHP版本)

Ubuntu

apt install php-openssl

装完重启

systemctl restart php-fpm

方法2:改php.ini配置

打开php.ini,找到:

;extension=openssl

去掉前面的分号:

extension=openssl

然后重启php-fpm。

方法3:关掉SSL验证(临时)

不想改配置,可以在代码里关验证:

<?php
$context = stream_context_create([
    'ssl' => [
        'verify_peer' => false,
        'verify_peer_name' => false
    ]
]);

$result = file_get_contents('https://api.example.com/data', false, $context);

echo $result;

注意: 这是临时方案,生产环境建议把证书配好。

方法4:改用curl(推荐)

file_get_contents不好用,直接用curl:

<?php
$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, 'https://api.example.com/data');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);

$result = curl_exec($ch);

if (curl_errno($ch)) {
    echo '错误: ' . curl_error($ch);
}

curl_close($ch);

echo $result;

curl比file_get_contents好用多了,推荐用curl。

五、常见坑

坑1:CLI和FPM配置不一样

命令行里openssl装了,网页上还是不行。

原因: CLI和FPM用不同的php.ini。

解决: 看phpinfo里的配置路径,改对应的那个。

坑2:装了扩展没重启

装完忘了重启php-fpm。

解决:

systemctl restart php-fpm

坑3:对方网站证书过期

对方网站SSL证书过期了,PHP验证不通过。

解决: 关验证,或者让对方更新证书。

坑4:allow_url_fopen没开

php.ini里禁了远程打开。

解决:

allow_url_fopen = On

坑5:防火墙挡了出站

服务器防火墙挡了443端口出站。

解决:

# 看能不能出去
curl -I https://www.baidu.com

# 不行的话开防火墙
firewall-cmd --add-port=443/tcp --permanent
firewall-cmd --reload

六、POST请求示例

file_get_contents发POST:

<?php
$url = 'https://api.example.com/submit';
$data = http_build_query([
    'name' => '张三',
    'age' => 20
]);

$context = stream_context_create([
    'http' => [
        'method' => 'POST',
        'header' => "Content-type: application/x-www-form-urlencoded\r\n",
        'content' => $data,
        'timeout' => 30
    ],
    'ssl' => [
        'verify_peer' => false,
        'verify_peer_name' => false
    ]
]);

$result = file_get_contents($url, false, $context);

echo $result;

还是建议用curl,更灵活。

七、封装函数

function http_get($url, $timeout = 30)
{
    $ch = curl_init();

    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
    curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);

    $result = curl_exec($ch);

    if (curl_errno($ch)) {
        $error = curl_error($ch);
        curl_close($ch);
        return ['code' => -1, 'msg' => $error];
    }

    curl_close($ch);
    return ['code' => 0, 'data' => $result];
}

// 使用
$res = http_get('https://api.example.com/data');
if ($res['code'] == 0) {
    echo $res['data'];
} else {
    echo '请求失败: ' . $res['msg'];
}

总结

记住:

  1. file_get_contents不支持https,是openssl扩展没装
  2. 装openssl扩展,重启php-fpm
  3. 或者关SSL验证临时解决
  4. 最推荐:改用curl,比file_get_contents好用多了

推荐方案:

直接用curl,别用file_get_contents搞https。

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-9 07:34 

PHP字符串处理常用函数,substr、explode PHP

前言

PHP字符串处理天天用,截取、拼接、查找、替换,每个项目都离不开。本文整理最常用的字符串函数,收藏随用随查。

一、字符串长度

strlen()

字节长度(中文算3个字节):

echo strlen('hello'); // 5
echo strlen('你好');   // 6(UTF-8每个中文3字节)

mb_strlen()

字符长度(中文算1个字符):

echo mb_strlen('你好', 'utf-8'); // 2

区别: strlen看字节,mb_strlen看字符。

二、截取字符串

substr()

$str = 'hello world';

// 从第0位取5个
echo substr($str, 0, 5); // hello

// 从第6位取到最后
echo substr($str, 6); // world

// 从倒数第5位取
echo substr($str, -5); // world

mb_substr()(中文截取)

$str = '我是中国人';

// 从第0个字符取2个
echo mb_substr($str, 0, 2, 'utf-8'); // 我是

注意: 中文一定要用mb_substr,不然会乱码。

三、查找字符串

strpos()

找位置(从左找,找到返回位置,没找到返回false):

$str = 'hello world';

echo strpos($str, 'world'); // 6

// 没找到
var_dump(strpos($str, 'abc')); // bool(false)

strrpos()

从右找:

echo strrpos('a/b/c', '/'); // 3

strstr()

找并截取:

$str = 'user@example.com';

echo strstr($str, '@'); // @example.com

str_contains()(PHP8)

var_dump(str_contains('hello world', 'world')); // bool(true)

注意: PHP8以上才有。

四、替换字符串

str_replace()

$str = 'hello world';

echo str_replace('world', 'php', $str); // hello php

str_ireplace()

不区分大小写:

echo str_ireplace('WORLD', 'php', $str); // hello php

preg_replace()

正则替换:

$str = '2026-10-09';

// 把横线换成点
echo preg_replace('/-/g', '.', $str); // 2026.10.09

五、拼接和拆分

implode()(数组转字符串)

$arr = ['a', 'b', 'c'];

echo implode(',', $arr); // a,b,c
echo implode('-', $arr); // a-b-c

explode()(字符串转数组)

$str = 'a,b,c';

$arr = explode(',', $str);
// ['a', 'b', 'c']

限制拆分次数

$str = 'a,b,c,d';

// 只拆成2段
$arr = explode(',', $str, 2);
// ['a', 'b,c,d']

六、去除空白

trim()

去首尾空格:

$str = '  hello  ';

echo trim($str); // hello

ltrim() / rtrim()

ltrim($str); // 去左边
rtrim($str); // 去右边

七、大小写转换

strtoupper('hello'); // HELLO
strtolower('HELLO'); // hello
ucwords('hello world'); // Hello World
ucfirst('hello'); // Hello

八、重复和填充

str_repeat()

echo str_repeat('ab', 3); // ababab

str_pad()

// 补到10位,右边补*
echo str_pad('123', 10, '*', STR_PAD_RIGHT); // 123*******

// 左边补
echo str_pad('123', 10, '0', STR_PAD_LEFT); // 0000000123

九、常见场景

场景1:手机号中间打星号

$phone = '13812345678';

echo substr($phone, 0, 3) . '****' . substr($phone, -4);
// 138****5678

场景2:截取文件名后缀

$file = 'photo.jpg';

echo strrchr($file, '.'); // .jpg

场景3:邮箱拆分

$email = 'user@example.com';

$name = strstr($email, '@', true); // user
$domain = strstr($email, '@');    // @example.com

场景4:URL参数解析

$url = 'https://example.com/index.php?id=1&name=zhangsan';

// 拿问号后面的
$query = parse_url($url, PHP_URL_QUERY);
// id=1&name=zhangsan

parse_str($query, $params);
// ['id' => '1', 'name' => 'zhangsan']

场景5:HTML标签转义

$str = '<script>alert(1)</script>';

echo htmlspecialchars($str);
// &lt;script&gt;alert(1)&lt;/script&gt;

十、常见坑

坑1:中文截取乱码

用substr截中文,结果乱码了。

原因: substr按字节截,中文一个字3个字节,容易截到半个字。

解决: 用mb_substr:

mb_substr($str, 0, 10, 'utf-8');

坑2:strpos===0的问题

$str = 'abc';
if (strpos($str, 'a') == false) {
    echo '没找到';
}

问题: strpos找到a在位置0,0==false是true。

解决:

if (strpos($str, 'a') === false) {
    echo '没找到';
}

注意: 一定要用===,不是==。

坑3:trim只去空格

trim默认只去空格和换行。

要去指定字符:

trim($str, "/"); // 去首尾的/

坑4:explode空字符串

$str = '';
$arr = explode(',', $str);
// [''] 不是空数组!

解决:

if ($str === '') {
    $arr = [];
} else {
    $arr = explode(',', $str);
}

总结

最常用的10个:

  1. strlen() 字符串长度(字节)
  2. mb_strlen() 字符长度(中文友好)
  3. substr() 截取字符串
  4. strpos() 查找位置
  5. str_replace() 替换
  6. explode() 字符串转数组
  7. implode() 数组转字符串
  8. trim() 去空格
  9. strtoupper() / strtolower() 大小写
  10. str_pad() 填充

记住:

  • 中文用mb_*系列函数
  • 查找用=== false判断
  • 数组字符串互转用explode/implode

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-9 07:33 

PHP数组常用函数大全,array操作 PHP

前言

PHP数组用得最多,几乎每个脚本都要操作数组。本文整理最常用的数组函数,收藏起来随用随查。

一、创建和遍历

数组定义

<?php
// 索引数组
$arr = [1, 2, 3, 4, 5];

// 关联数组
$user = [
    'name' => '张三',
    'age' => 20,
    'email' => 'zhangsan@qq.com'
];

遍历

// foreach遍历
foreach ($arr as $value) {
    echo $value;
}

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

二、增删改查

添加元素

// 末尾加
$arr[] = 6;
array_push($arr, 7, 8);

// 开头加
array_unshift($arr, 0);

// 关联数组加
$user['phone'] = '13800138000';

删除元素

// 删最后一个
array_pop($arr);

// 删第一个
array_shift($arr);

// 删指定key
unset($user['age']);

// 删多个
unset($arr[0], $arr[1]);

修改元素

$arr[0] = 100;
$user['name'] = '李四';

查找元素

// 值是否在数组里
in_array(3, $arr); // true

// 找key
array_key_exists('name', $user); // true

// 找值的key
array_search(2, $arr); // 1

三、数组统计

长度

count($arr);
sizeof($arr); // 和count一样

求和、最大、最小

array_sum($arr);      // 求和
max($arr);            // 最大
min($arr);            // 最小

去重

$unique = array_unique($arr);

打乱

shuffle($arr);

四、排序

索引数组排序

sort($arr);    // 升序
rsort($arr);   // 降序

关联数组排序

asort($user);  // 按值升序
arsort($user); // 按值降序
ksort($user);  // 按key升序
krsort($user); // 按key降序

五、拆分和合并

取一段

// 从第2个开始取3个
$slice = array_slice($arr, 1, 3);

合并数组

$arr1 = [1, 2];
$arr2 = [3, 4];

$merge = array_merge($arr1, $arr2); // [1,2,3,4]

交差

$arr1 = [1, 2, 3];
$arr2 = [2, 3, 4];

array_intersect($arr1, $arr2); // [2,3] 交集
array_diff($arr1, $arr2);      // [1] 差集

六、key和value操作

取所有key

$keys = array_keys($user);
// ['name', 'age', 'email']

取所有value

$values = array_values($user);
// ['张三', 20, 'zhangsan@qq.com']

翻转key和value

$flipped = array_flip($user);

填充数组

// 5个元素,值都是0
$arr = array_fill(0, 5, 0);

七、数组和字符串互转

数组转字符串

$arr = ['a', 'b', 'c'];
$str = implode(',', $arr); // 'a,b,c'

字符串转数组

$str = 'a,b,c';
$arr = explode(',', $str); // ['a', 'b', 'c']

八、常用场景

场景1:数组去重

$arr = [1, 2, 2, 3, 3, 3];
$unique = array_unique($arr);
// [1, 2, 3]

场景2:查值在不在

$fruits = ['apple', 'banana', 'orange'];

if (in_array('apple', $fruits)) {
    echo '有苹果';
}

场景3:二维数组按key排序

$users = [
    ['name' => '张三', 'age' => 20],
    ['name' => '李四', 'age' => 25],
    ['name' => '王五', 'age' => 18]
];

// 按age排序
array_multisort(array_column($users, 'age'), SORT_ASC, $users);

场景4:数组分页

$page = 1;
$pageSize = 10;
$offset = ($page - 1) * $pageSize;

$pageData = array_slice($allData, $offset, $pageSize);

场景5:过滤空值

$arr = ['a', '', null, 'b', 0, 'c'];
$filtered = array_filter($arr);
// ['a', 'b', 'c'] 空字符串、null、0都被过滤了

九、常见坑

坑1:count(null)报错

PHP7.2以后,count(null)会警告。

解决:

$count = is_array($arr) ? count($arr) : 0;

坑2:==和===的区别

in_array('123', [123]); // true(==)
in_array('123', [123], true); // false(===)

注意: 第三个参数true才是严格比较。

坑3:array_merge和+的区别

$arr1 = ['a' => 1, 'b' => 2];
$arr2 = ['b' => 3, 'c' => 4];

array_merge($arr1, $arr2); // ['a'=>1, 'b'=>3, 'c'=>4]
$arr1 + $arr2;             // ['a'=>1, 'b'=>2, 'c'=>4]

区别: array_merge后者覆盖前者,+前者保留。

坑4:引用传递

foreach ($arr as &$value) {
    $value = $value * 2;
}
unset($value); // 一定要unset,不然后面会出问题

总结

最常用的10个:

  1. count() 数组长度
  2. in_array() 值是否在数组里
  3. array_key_exists() key是否存在
  4. array_unique() 去重
  5. array_merge() 合并
  6. array_slice() 取一段
  7. array_sum() 求和
  8. explode() 字符串转数组
  9. implode() 数组转字符串
  10. array_column() 取二维数组某一列

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-9 07:31 

PHP cURL请求超时,超时时间设置 PHP

前言

PHP用cURL请求接口,结果一直卡住或者超时?cURL默认没有超时时间,对方服务器慢的话能卡你几分钟。必须设超时,不然整个脚本都堵死了。本文讲怎么设。

一、为什么要设超时

不设超时的后果:

  1. 对方服务器挂了,你的脚本一直等着
  2. 对方服务器慢,你的脚本卡很久
  3. 高并发下,进程都堵在cURL上,服务器卡死

一定要设!

二、两个超时参数

1. CURLOPT_CONNECTTIMEOUT

连接超时,单位秒。

就是TCP连接花多久。

推荐: 5-10秒

2. CURLOPT_TIMEOUT

总超时,单位秒。

整个请求(连接+发送+接收)花多久。

推荐: 30-60秒

区别

参数 含义 推荐值
CURLOPT_CONNECTTIMEOUT 连接超时 5秒
CURLOPT_TIMEOUT 总超时 30秒

三、完整示例

<?php
$url = 'https://api.example.com/data';

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

// 连接超时(秒)
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);

// 总超时(秒)
curl_setopt($ch, CURLOPT_TIMEOUT, 30);

// 毫秒级超时(可选)
// curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, 5000);
// curl_setopt($ch, CURLOPT_TIMEOUT_MS, 30000);

$result = curl_exec($ch);

if (curl_errno($ch)) {
    echo 'cURL错误: ' . curl_error($ch);
}

curl_close($ch);

echo $result;

四、超时错误码

常见错误码

错误码 说明
28 超时(CURLE_OPERATION_TIMEDOUT)
7 连接失败(CURLE_COULDNT_CONNECT)
6 域名解析失败(CURLE_COULDNT_RESOLVE_HOST)

检查错误码

if (curl_errno($ch) == 28) {
    echo "请求超时了";
}

五、常见坑

坑1:timeout设成了毫秒

CURLOPT_TIMEOUT的单位是秒,不是毫秒!

错误:

curl_setopt($ch, CURLOPT_TIMEOUT, 5000); // 5000秒,不是5秒!

正确:

curl_setopt($ch, CURLOPT_TIMEOUT, 5); // 5秒

或者用毫秒版:

curl_setopt($ch, CURLOPT_TIMEOUT_MS, 5000); // 5000毫秒 = 5秒

坑2:set_time_limit不够

PHP脚本本身有最大执行时间。

如果cURL超时30秒,但PHP脚本只允许10秒,PHP先超时了。

解决:

set_time_limit(0); // 不限制
// 或者
set_time_limit(60); // 60秒

坑3:DNS解析慢

域名解析也要时间,算在连接超时里。

解决: 连接超时设长一点,比如10秒。

坑4:https证书问题

https请求如果证书有问题,也会卡住或报错。

临时关闭验证:

curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);

注意: 生产环境不建议关,最好把证书配好。

坑5:重定向太多

对方返回301/302重定向,cURL默认不自动跳。

开启自动跳转:

curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_MAXREDIRS, 3); // 最多跳3次

六、POST请求示例

<?php
$url = 'https://api.example.com/submit';
$data = [
    'name' => '张三',
    'age' => 20
];

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);

$result = curl_exec($ch);

if (curl_errno($ch)) {
    echo '错误: ' . curl_error($ch);
}

curl_close($ch);

echo $result;

七、封装成函数

function http_curl($url, $post = false, $data = [], $timeout = 30)
{
    $ch = curl_init();

    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
    curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);

    if ($post) {
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, is_array($data) ? http_build_query($data) : $data);
    }

    $result = curl_exec($ch);

    if (curl_errno($ch)) {
        $error = curl_error($ch);
        curl_close($ch);
        return ['code' => -1, 'msg' => $error];
    }

    curl_close($ch);
    return ['code' => 0, 'data' => $result];
}

// 使用
$res = http_curl('https://api.example.com/data');
if ($res['code'] == 0) {
    echo $res['data'];
} else {
    echo '请求失败: ' . $res['msg'];
}

八、推荐配置

普通接口请求

curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);  // 5秒连接
curl_setopt($ch, CURLOPT_TIMEOUT, 30);        // 30秒总超时

快速接口(查个数据)

curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3);  // 3秒连接
curl_setopt($ch, CURLOPT_TIMEOUT, 10);        // 10秒总超时

慢接口(上传大文件)

curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10); // 10秒连接
curl_setopt($ch, CURLOPT_TIMEOUT, 120);       // 2分钟总超时

总结

记住:

  1. cURL一定要设超时,不然卡死
  2. CURLOPT_CONNECTTIMEOUT 连接超时(秒)
  3. CURLOPT_TIMEOUT 总超时(秒)
  4. 单位是秒,不是毫秒
  5. 超时了用 curl_errno 判断是不是28

最常用:

curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-9 07:30 

PHP获取当前时间不对,时区设置date.timezone PHP

前言

PHP用date()获取当前时间,结果比实际时间差了8个小时?这是最常见的时区问题。PHP默认用UTC时区,北京时间是东八区,所以差了8小时。本文讲怎么改。

一、问题现象

<?php
echo date('Y-m-d H:i:s');

输出:

2026-10-09 00:30:00

但实际北京时间是:

2026-10-09 08:30:00

差了8个小时。

二、原因

PHP默认时区是UTC(世界标准时间),不是北京时间。

北京时间是 UTC+8,所以差了8小时。

三、解决方法

方法1:改php.ini(推荐)

第一步:找到php.ini

php --ini

找到Loaded Configuration File那一行:

Loaded Configuration File: /etc/php.ini

第二步:修改date.timezone

打开php.ini,找到这行:

;date.timezone =

改成:

date.timezone = Asia/Shanghai

第三步:重启php-fpm

systemctl restart php-fpm

方法2:代码里设置(临时)

不想改php.ini,可以在代码里设:

<?php
date_default_timezone_set('Asia/Shanghai');

echo date('Y-m-d H:i:s');

注意: 要在所有日期函数之前设。

方法3:.htaccess里设

Apache的话,可以在.htaccess里设:

php_value date.timezone Asia/Shanghai

四、常用时区对照

时区 说明
Asia/Shanghai 北京时间(东八区)
Asia/Chongqing 重庆时间
Asia/Urumqi 乌鲁木齐时间
Asia/Hong_Kong 香港时间
Asia/Taipei 台北时间
Asia/Tokyo 东京时间(东九区)
America/New_York 纽约时间
Europe/London 伦敦时间
UTC 世界标准时间

国内用: Asia/Shanghai

五、验证时区

看当前时区

<?php
echo date_default_timezone_get();
// 输出:Asia/Shanghai

看服务器时间

date

看PHP时间

<?php
echo date('Y-m-d H:i:s');

对比一下,应该一样了。

六、常见坑

坑1:CLI和FPM时区不一样

命令行里改了php.ini,但网页上还是不对。

原因: CLI和FPM用不同的php.ini。

解决: 看phpinfo()里的配置路径,改对应的那个。

<?php
phpinfo();

搜"Loaded Configuration File",看用的哪个文件。

坑2:改了没重启

改了php.ini忘了重启php-fpm。

解决:

systemctl restart php-fpm

坑3:代码里又改回去了

某个框架或库里又调了 date_default_timezone_set('UTC')。

解决: 全局搜一下,看哪里改的。

坑4:用了gmdate()

gmdate()总是用UTC时区,不管你设什么。

比如:

echo gmdate('Y-m-d H:i:s');

这个输出的是UTC时间,不是北京时间。

解决: 用date()不要用gmdate(),或者自己加8小时。

坑5:数据库时间不对

PHP时区对了,但MySQL里的时间不对。

原因: MySQL自己也有时区设置。

解决: MySQL连接后设时区:

SET time_zone = '+8:00';

或者改my.cnf:

default-time-zone = '+8:00'

七、常用日期函数

获取当前时间

date_default_timezone_set('Asia/Shanghai');

// 当前日期时间
echo date('Y-m-d H:i:s');

// 今天
echo date('Y-m-d');

// 现在几点
echo date('H:i:s');

// 时间戳
echo time();

时间戳转日期

$time = time();
echo date('Y-m-d H:i:s', $time);

日期转时间戳

$str = '2026-10-09 08:30:00';
echo strtotime($str);

几天以后

// 3天后
echo date('Y-m-d', strtotime('+3 days'));

// 下周
echo date('Y-m-d', strtotime('next week'));

八、框架里的设置

ThinkPHP

在config/app.php里:

'default_timezone' => 'Asia/Shanghai',

Laravel

在config/app.php里:

'timezone' => 'Asia/Shanghai',

总结

记住:

  1. PHP默认UTC时区,差8小时
  2. 改php.ini里的 date.timezone = Asia/Shanghai
  3. 改完重启php-fpm
  4. 或者代码里 date_default_timezone_set('Asia/Shanghai')
  5. CLI和FPM可能用不同的php.ini

最常用:

date_default_timezone_set('Asia/Shanghai');
echo date('Y-m-d H:i:s');

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-9 07:28 

PHP session不生效,cookie配置检查 PHP

前言

PHP用session存用户登录状态,结果刷新页面就掉了?session不生效太常见了,一般就是cookie配置不对、路径不对、或者目录没权限。本文讲怎么排查和解决。

一、session工作原理

简单说:

  1. 浏览器访问网站
  2. PHP创建session,生成session_id
  3. session_id通过cookie发给浏览器
  4. 浏览器每次请求带上这个cookie
  5. PHP根据cookie里的session_id找到对应数据

核心: session靠cookie传session_id,cookie不行session就没了。

二、常见原因

原因1:cookie没设置对

session.cookie_path、session.cookie_domain配置不对。

原因2:session保存目录没权限

session文件存不进去。

原因3:session.auto_start没开

或者开了但和代码冲突。

原因4:跨域问题

主域和子域之间cookie不共享。

原因5:HTTPS下cookie的secure问题

cookie设了secure,但用http访问。

三、排查步骤

第一步:检查session有没有启动

<?php
session_start();

// 存个值
$_SESSION['test'] = 'hello';

// 看有没有
echo '<pre>';
print_r($_SESSION);
echo '</pre>';

刷新页面,看test还在不在。

第二步:看cookie里有没有PHPSESSID

按F12打开浏览器开发者工具 → Application → Cookies。

看有没有 PHPSESSID 这个cookie。

没有的话: 就是cookie没设对。

有的话: 那就是session保存目录的问题。

四、php.ini配置检查

找到php.ini位置

php --ini

关键配置

;session保存目录
session.save_path = "/var/lib/php/session"

;是否自动启动
session.auto_start = 0

;cookie路径
session.cookie_path = /

;cookie域名
session.cookie_domain =

;cookie有效期(秒)
session.cookie_lifetime = 0

;是否仅https
session.cookie_secure = 0

;是否仅http(防XSS)
session.cookie_httponly = 1

五、常见坑和解决

坑1:session目录没权限

session文件写不进去。

检查:

ls -ld /var/lib/php/session

解决:

chmod 777 /var/lib/php/session
chown apache:apache /var/lib/php/session

或者看php-fpm用的哪个用户。

坑2:cookie_path不对

比如网站装在子目录,但cookie_path设成了别的。

解决:

ini_set('session.cookie_path', '/');
session_start();

坑3:cookie_domain不对

多域名访问时,cookie只在一个域名下有效。

解决:

ini_set('session.cookie_domain', '.example.com');

注意前面有个点,表示所有子域名都生效。

坑4:HTTPS下设了secure

cookie_secure=1表示只在https下传cookie,用http访问就没了。

解决:

session.cookie_secure = 0

或者全站用https。

坑5:session.auto_start冲突

代码里已经session_start()了,但php.ini里也开了auto_start,冲突。

解决:

session.auto_start = 0

六、代码里动态设置

不想改php.ini,可以在代码里设:

<?php
// 必须在session_start()之前

ini_set('session.cookie_path', '/');
ini_set('session.cookie_domain', '.example.com');
ini_set('session.cookie_lifetime', 0);

session_start();

$_SESSION['user_id'] = 1;

七、检查session是否生效

写个测试页:

<?php
session_start();

// 第一次访问,设置
if (!isset($_SESSION['count'])) {
    $_SESSION['count'] = 1;
} else {
    $_SESSION['count']++;
}

echo "访问次数: " . $_SESSION['count'];
echo "<br>";
echo "Session ID: " . session_id();
echo "<br>";
echo "Session 文件: " . session_save_path() . "/sess_" . session_id();

刷新页面,数字应该一直涨。

如果不涨: 就是session没存住。

八、常见场景

场景1:登录后刷新就掉

原因: cookie_path或domain不对。

解决: 检查cookie配置。

场景2:换了个子域名就掉

比如 www.example.com 登录了,跳到 bbs.example.com 就没登录。

原因: cookie_domain没设成 .example.com。

解决:

ini_set('session.cookie_domain', '.example.com');

场景3:从http跳到https就掉

原因: cookie_secure=1,但http不带cookie。

解决: 全站用https,或者关掉secure。

场景4:session目录满了

原因: session文件太多。

解决: 清理旧session,或者设gc_maxlifetime。

session.gc_maxlifetime = 1440

九、快速排查清单

  1. F12看cookie里有没有PHPSESSID
  2. 没有 → 查cookie_path、cookie_domain、cookie_secure
  3. 有 → 查session目录权限
  4. 都没问题 → 看session.auto_start有没有冲突
  5. 跨域问题 → cookie_domain设成 .主域名

总结

记住:

  1. session靠cookie传session_id
  2. 先看cookie里有没有PHPSESSID
  3. 没有就查cookie配置
  4. 有就查session目录权限
  5. 跨域名记得设cookie_domain=.主域名

最常用:

ini_set('session.cookie_path', '/');
session_start();

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-9 07:27 

PHP 过滤和验证数据 PHP

PHP 过滤和验证数据

用户输入不可信,必须过滤验证,这是Web开发的基本功。

1. 为什么要过滤验证

  • 防止 SQL 注入
  • 防止 XSS 攻击
  • 保证数据格式正确
  • 防止脏数据入库

2. filter_var 函数

PHP 内置过滤器,很好用。

验证邮箱

$email = 'test@example.com';
if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
    echo '邮箱格式正确';
} else {
    echo '邮箱格式错误';
}

验证数字

$age = '20abc';
if (filter_var($age, FILTER_VALIDATE_INT)) {
    echo '是整数';
}

验证URL

$url = 'https://example.com';
if (filter_var($url, FILTER_VALIDATE_URL)) {
    echo 'URL格式正确';
}

验证IP

$ip = '192.168.1.1';
if (filter_var($ip, FILTER_VALIDATE_IP)) {
    echo 'IP格式正确';
}

3. filter_input 获取并过滤

从 GET/POST 获取并过滤:

// 获取并过滤GET参数
$id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT);

// 获取并过滤POST参数
$email = filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);

4. 过滤输入

过滤HTML标签

$str = '<script>alert(1)</script>你好';
// 去除HTML标签
echo strip_tags($str);

// HTML转义(安全输出)
echo htmlspecialchars($str);

过滤特殊字符

$str = "hello ' world";
// 转义单引号
echo addslashes($str);

5. 常用验证场景

验证手机号

function checkPhone($phone) {
    return preg_match('/^1[3-9]\d{9}$/', $phone);
}

if (checkPhone('13800138000')) {
    echo '手机号正确';
}

验证身份证

function checkIdCard($idcard) {
    return preg_match('/^\d{17}[\dXx]$/', $idcard);
}

验证用户名

// 4-16位,字母数字下划线
function checkUsername($name) {
    return preg_match('/^\w{4,16}$/', $name);
}

6. 安全建议

1)所有外部输入都要验证

  • GET、POST、COOKIE
  • 不要相信任何用户输入

2)用预处理防SQL注入

  • 不要自己拼接SQL
  • 用 PDO 预处理

3)输出时转义

  • 输出到HTML要 htmlspecialchars
  • 防止 XSS 攻击

4)白名单验证

  • 只接受允许的值
  • 不要用黑名单

7. 完整示例

// 接收用户注册信息
$username = trim($_POST['username']);
$email = trim($_POST['email']);
$age = (int)$_POST['age'];

$errors = [];

// 验证用户名
if (!preg_match('/^\w{4,16}$/', $username)) {
    $errors[] = '用户名4-16位字母数字下划线';
}

// 验证邮箱
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
    $errors[] = '邮箱格式错误';
}

// 验证年龄
if ($age < 18 || $age > 100) {
    $errors[] = '年龄必须18-100岁';
}

if (empty($errors)) {
    // 验证通过,入库
    echo '注册成功';
} else {
    print_r($errors);
}

总结

PHP 过滤和验证数据要点:

  • 所有用户输入都不可信
  • 用 filter_var 验证格式
  • 用 filter_input 获取并过滤
  • 输出用 htmlspecialchars 防XSS
  • 用预处理防SQL注入
  • 用正则验证手机号、用户名
  • 白名单验证比黑名单好
  • 不要自己拼接SQL字符串

做Web开发,安全永远第一位。


emer 发布于  2026-10-9 07:26 

PHP 时间日期处理 PHP

PHP 时间日期处理

时间日期是开发常用功能,这些函数要记住。

1. 获取当前时间

// 当前时间戳
echo time();

// 当前日期时间
echo date('Y-m-d H:i:s');

// 今天日期
echo date('Y-m-d');

2. 时间戳和日期互转

时间戳转日期

$time = time();
echo date('Y-m-d H:i:s', $time);

日期转时间戳

$date = '2024-01-01 12:00:00';
$time = strtotime($date);
echo $time;

3. 常用日期格式

// 2024-01-01
echo date('Y-m-d');

// 2024-01-01 12:00:00
echo date('Y-m-d H:i:s');

// 2024年01月01日
echo date('Y年m月d日');

// 2024/01/01
echo date('Y/m/d');

// 星期几
echo date('l');  // Sunday

4. 常用格式字符

  • Y: 4位年
  • m: 2位月
  • d: 2位日
  • H: 24小时制
  • i: 分钟
  • s: 秒

5. 日期加减

// 明天
echo date('Y-m-d', strtotime('+1 day'));

// 昨天
echo date('Y-m-d', strtotime('-1 day'));

// 一周后
echo date('Y-m-d', strtotime('+1 week'));

// 一个月后
echo date('Y-m-d', strtotime('+1 month'));

// 一年后
echo date('Y-m-d', strtotime('+1 year'));

6. 计算时间差

$start = strtotime('2024-01-01');
$end = strtotime('2024-01-10');

// 相差天数
$diff = ($end - $start) / 86400;
echo $diff . '天';

7. DateTime 类(推荐)

// 创建日期对象
$date = new DateTime('2024-01-01');

// 格式化输出
echo $date->format('Y-m-d H:i:s');

// 加一天
$date->add(new DateInterval('P1D'));
echo $date->format('Y-m-d');

// 计算两个日期差
$start = new DateTime('2024-01-01');
$end = new DateTime('2024-01-10');
$diff = $start->diff($end);
echo $diff->days . '天';

8. 常用场景

1)几天前

function timeAgo($time) {
    $diff = time() - $time;
    if ($diff < 60) return '刚刚';
    if ($diff < 3600) return floor($diff/60) . '分钟前';
    if ($diff < 86400) return floor($diff/3600) . '小时前';
    return floor($diff/86400) . '天前';
}

2)生日计算

$birthday = '1990-01-01';
$age = floor((time() - strtotime($birthday)) / 31536000);
echo $age . '岁';

总结

PHP 时间日期处理要点:

  • time() 获取时间戳
  • date() 格式化日期
  • strtotime() 日期转时间戳
  • 用 +1 day 等做日期加减
  • 推荐用 DateTime 类
  • 时间差除以86400得天数
  • 注意时区设置

做开发时间日期天天用,这些函数必须熟。


emer 发布于  2026-10-9 07:23 

PHP 生成随机密码 PHP

PHP 生成随机密码

注册、重置密码功能经常要生成随机密码,这几种方法要会。

1. 简单随机字符串

function generatePassword($length = 8) {
    $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
    $password = '';
    for ($i = 0; $i < $length; $i++) {
        $password .= $chars[mt_rand(0, strlen($chars) - 1)];
    }
    return $password;
}

// 生成8位密码
echo generatePassword(8);

2. 带特殊字符的密码

function generateStrongPassword($length = 12) {
    $lower = 'abcdefghijklmnopqrstuvwxyz';
    $upper = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
    $numbers = '0123456789';
    $special = '!@#$%^&*()';

    $all = $lower . $upper . $numbers . $special;

    $password = '';
    // 确保至少包含每种字符
    $password .= $lower[mt_rand(0, strlen($lower) - 1)];
    $password .= $upper[mt_rand(0, strlen($upper) - 1)];
    $password .= $numbers[mt_rand(0, strlen($numbers) - 1)];
    $password .= $special[mt_rand(0, strlen($special) - 1)];

    // 剩余随机
    for ($i = 4; $i < $length; $i++) {
        $password .= $all[mt_rand(0, strlen($all) - 1)];
    }

    // 打乱顺序
    return str_shuffle($password);
}

echo generateStrongPassword(12);

3. 更安全的 random_bytes

PHP 7+ 推荐用 random_bytes,更安全:

function generateSecurePassword($length = 12) {
    $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*';
    $max = strlen($chars) - 1;
    $password = '';

    for ($i = 0; $i < $length; $i++) {
        $password .= $chars[random_int(0, $max)];
    }

    return $password;
}

echo generateSecurePassword(16);

4. 生成验证码

function generateCode($length = 6) {
    $chars = '0123456789';
    $code = '';
    for ($i = 0; $i < $length; $i++) {
        $code .= $chars[random_int(0, 9)];
    }
    return $code;
}

// 6位数字验证码
echo generateCode(6);

5. 生成随机 Token

function generateToken($length = 32) {
    return bin2hex(random_bytes($length / 2));
}

// 32位随机token
echo generateToken();

6. 安全建议

1)用 random_int 不用 mt_rand

  • random_int 是密码安全随机数
  • mt_rand 不够安全

2)密码长度

  • 普通密码:8-12位
  • 强密码:12位以上
  • Token:32位以上

3)密码强度

  • 大小写字母+数字+特殊字符
  • 避免纯数字或纯字母

4)不要自己写随机算法

  • 用 PHP 内置函数
  • 不要用时间戳做随机种子

总结

PHP 生成随机密码要点:

  • 简单密码用 mt_rand 拼接
  • 强密码包含大小写+数字+特殊字符
  • 安全密码用 random_int
  • Token 用 bin2hex(random_bytes())
  • 验证码用纯数字
  • 推荐用 PHP 7+ 的 random_int
  • 不要自己写随机算法

做用户系统,生成密码和验证码是必备功能。


emer 发布于  2026-10-9 07:20 

PHP PDO 连接数据库 PHP

PHP PDO 连接数据库

PDO 是 PHP 推荐的数据库连接方式,支持多种数据库,防注入。

1. 什么是 PDO

PDO(PHP Data Objects)是 PHP 数据库抽象层,统一接口操作多种数据库。

2. 为什么用 PDO

  • 防SQL注入: 预处理语句
  • 支持多数据库: MySQL、PostgreSQL、SQLite 等
  • 面向对象: 写法更规范
  • 错误处理: 统一的错误模式

3. 连接数据库

// 数据库配置
$host = '127.0.0.1';
$dbname = 'test';
$user = 'root';
$pass = 'root';

try {
    // 连接数据库
    $pdo = new PDO(
        "mysql:host=$host;dbname=$dbname;charset=utf8mb4",
        $user,
        $pass,
        [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
        ]
    );
    echo '连接成功';
} catch(PDOException $e) {
    die('连接失败:' . $e->getMessage());
}

4. 查询数据

查询多条

$stmt = $pdo->query("SELECT * FROM users");
$users = $stmt->fetchAll();

查询单条

$stmt = $pdo->query("SELECT * FROM users WHERE id = 1");
$user = $stmt->fetch();

5. 预处理语句(防注入)

查询

// 问号占位符
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([1]);
$user = $stmt->fetch();

// 命名占位符
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = :id");
$stmt->execute([':id' => 1]);
$user = $stmt->fetch();

插入

$stmt = $pdo->prepare("INSERT INTO users (name, age) VALUES (:name, :age)");
$stmt->execute([
    ':name' => '张三',
    ':age' => 20
]);

更新

$stmt = $pdo->prepare("UPDATE users SET name = :name WHERE id = :id");
$stmt->execute([
    ':name' => '李四',
    ':id' => 1
]);

删除

$stmt = $pdo->prepare("DELETE FROM users WHERE id = :id");
$stmt->execute([':id' => 1]);

6. 获取自增ID

$pdo->exec("INSERT INTO users (name) VALUES ('王五')");
$id = $pdo->lastInsertId();

7. 事务处理

try {
    $pdo->beginTransaction();

    $pdo->exec("INSERT INTO orders ...");
    $pdo->exec("UPDATE stock ...");

    $pdo->commit();
    echo '事务成功';
} catch(Exception $e) {
    $pdo->rollBack();
    echo '事务失败:' . $e->getMessage();
}

8. 常用配置

// 设置返回关联数组
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC

// 错误模式
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION

// 关闭预处理模拟(真正服务端预处理)
PDO::ATTR_EMULATE_PREPARES => false

总结

PHP PDO 连接数据库要点:

  • PDO 是统一数据库接口
  • 预处理语句防 SQL 注入
  • 支持事务操作
  • 配置错误模式方便调试
  • 推荐用命名占位符
  • 生产环境关闭预处理模拟
  • 记得设置 utf8mb4 字符集

做数据库开发,PDO 比 mysqli 更好用。


emer 发布于  2026-10-9 07:17 

PHP 上传文件处理 PHP

PHP 上传文件处理

文件上传是 Web 开发常见功能,安全处理很重要。

1. HTML 表单

<form method="post" action="upload.php" enctype="multipart/form-data">
    <input type="file" name="file">
    <button type="submit">上传</button>
</form>

注意:必须加 enctype="multipart/form-data"。

2. PHP 接收文件

// $_FILES 接收上传文件
$file = $_FILES['file'];

// 文件信息
$name = $file['name'];        // 文件名
$tmp = $file['tmp_name'];     // 临时路径
$size = $file['size'];        // 文件大小
$error = $file['error'];      // 错误码
$type = $file['type'];        // MIME类型

3. 错误码说明

  • UPLOAD_ERR_OK (0): 上传成功
  • UPLOAD_ERR_INI_SIZE (1): 超过 php.ini 限制
  • UPLOAD_ERR_FORM_SIZE (2): 超过表单限制
  • UPLOAD_ERR_PARTIAL (3): 部分上传
  • UPLOAD_ERR_NO_FILE (4): 没有文件

4. 完整上传代码

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $file = $_FILES['file'];

    // 检查错误
    if ($file['error'] !== UPLOAD_ERR_OK) {
        exit('上传失败');
    }

    // 检查大小(限制2M)
    if ($file['size'] > 2 * 1024 * 1024) {
        exit('文件太大');
    }

    // 允许的扩展名
    $allowExt = ['jpg', 'png', 'gif'];
    $ext = pathinfo($file['name'], PATHINFO_EXTENSION);
    if (!in_array($ext, $allowExt)) {
        exit('不允许的文件类型');
    }

    // 生成新文件名
    $newName = uniqid() . '.' . $ext;
    $uploadDir = 'uploads/';

    // 移动文件
    if (move_uploaded_file($file['tmp_name'], $uploadDir . $newName)) {
        echo '上传成功';
    } else {
        echo '保存失败';
    }
}

5. php.ini 配置

; 上传最大文件大小
upload_max_filesize = 2M

; 表单最大提交大小
post_max_size = 8M

; 允许上传
file_uploads = On

; 临时目录
upload_tmp_dir = /tmp

6. 安全注意事项

1)不要用原文件名

  • 防止覆盖文件和路径穿越
  • 用 uniqid 生成新文件名

2)验证文件类型

  • 不要只看扩展名
  • 用 finfo 检查 MIME 类型
$finfo = new Finfo(FILEINFO_MIME_TYPE);
$mime = $finfo->file($file['tmp_name']);

3)上传目录不可执行

  • 上传目录关闭 PHP 执行
  • 防止上传木马

4)重命名文件

  • 不要保留用户上传的文件名
  • 防止覆盖和目录穿越攻击

7. 常见问题

1)上传失败,$_FILES 为空

  • 检查表单是否有 enctype
  • 检查 post_max_size 够不够大

2)move_uploaded_file 失败

  • 检查目录权限
  • 检查目录是否存在

3)大文件上传超时

  • 修改 max_execution_time
  • 修改 memory_limit

总结

PHP 文件上传要点:

  • 表单必须加 enctype
  • 用 $_FILES 接收文件
  • 检查错误码和文件大小
  • 验证文件类型
  • 重命名文件防止安全问题
  • 上传目录关闭执行权限
  • 注意 php.ini 配置

做上传功能,安全永远第一位。


emer 发布于  2026-10-9 07:13 

PHP 超全局变量详解 PHP

PHP 超全局变量详解

PHP 超全局变量在所有作用域都能用,写接口和表单开发天天用到。

1. 什么是超全局变量

超全局变量是 PHP 预定义的数组变量,不需要 global 声明,在函数、类、文件里都能直接访问。

2. 常用超全局变量

1)$_GET
获取 URL 查询参数。

// 访问 index.php?id=1&name=张三
$id = $_GET['id'];       // 1
$name = $_GET['name'];   // 张三

2)$_POST
获取表单 POST 提交的数据。

// 表单 method="post"
$username = $_POST['username'];
$password = $_POST['password'];

3)$_REQUEST
同时获取 GET、POST、COOKIE 数据。

$id = $_REQUEST['id'];
// 不推荐,安全隐患大

4)$_SESSION
会话数据,跨页面共享。

session_start();
$_SESSION['user_id'] = 1;
$_SESSION['username'] = '张三';

5)$_COOKIE
获取客户端 Cookie。

$token = $_COOKIE['token'];

6)$_SERVER
服务器和执行环境信息。

// 获取请求方法
$method = $_SERVER['REQUEST_METHOD'];

// 获取当前URL
$uri = $_SERVER['REQUEST_URI'];

// 获取客户端IP
$ip = $_SERVER['REMOTE_ADDR'];

// 获取HTTP头
$host = $_SERVER['HTTP_HOST'];

3. 文件上传变量

$_FILES
处理文件上传。

// 表单 enctype="multipart/form-data"
$file = $_FILES['upload'];
$name = $file['name'];        // 文件名
$tmp = $file['tmp_name'];     // 临时路径
$size = $file['size'];        // 文件大小
$error = $file['error'];      // 错误码

4. 注意事项

  • 安全问题: 所有超全局变量都不可信,必须做过滤和验证
  • isset 判断: 取值前用 isset 判断是否存在,避免报错
  • 类型转换: 数字参数记得转 int
  • 不要用 $_REQUEST: 安全隐患大,明确用 GET 还是 POST

5. 安全取值示例

// 安全获取GET参数
$id = isset($_GET['id']) ? intval($_GET['id']) : 0;

// 安全获取POST参数
$username = isset($_POST['username']) ? trim($_POST['username']) : '';

// 判断请求方法
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // 处理POST请求
}

总结

PHP 超全局变量要点:

  • $_GET:获取 URL 参数
  • $_POST:获取表单数据
  • $_SESSION:会话数据
  • $_COOKIE:客户端 Cookie
  • $_SERVER:服务器信息
  • $_FILES:文件上传
  • 所有外部输入都要过滤验证,不能直接用
  • 取值前先 isset 判断

做 PHP 开发,超全局变量是基础中的基础。


emer 发布于  2026-10-9 07:09 

PHP报错Call to undefined function解决 PHP

前言

运行PHP代码,突然报错:"Call to undefined function xxx()"?这个错太常见了,一般就是扩展没装或者文件没引入。本文讲怎么排查和解决。

一、报错长啥样

Fatal error: Uncaught Error: Call to undefined function mysql_connect() in xxx.php on line 5

意思:你调用了一个不存在的函数。

二、常见原因

原因1:PHP扩展没装

比如用了 mysqli_connect(),但没装mysqli扩展。

或者用了 gd库 的函数,但没装gd。

原因2:文件没引入

你自己写的函数,忘了include/require文件。

原因3:函数名写错了

拼写错了,比如 str_lower 写成 strlower。

原因4:PHP版本不对

低版本PHP没有高版本才有的函数。

三、排查步骤

第一步:看是哪个函数报错

报错信息里会告诉你函数名:

Call to undefined function curl_init()

这里就是 curl_init() 函数没找到。

第二步:判断是内置函数还是自己写的

  • 内置函数:PHP自带的,比如 curl_init、mysqli_connect
  • 自己写的:你在别的文件里定义的

第三步:如果是内置函数,查扩展装了没

php -m | grep curl

看看curl扩展装了没。

或者写个phpinfo:

<?php
phpinfo();
?>

搜这个函数名对应的扩展,看有没有。

四、安装扩展

例子1:装curl扩展

# CentOS
yum install php-curl

# Ubuntu
apt install php-curl

例子2:装mysqli扩展

yum install php-mysqli

例子3:装gd库

yum install php-gd

装完重启

systemctl restart php-fpm

五、如果是自己写的函数

检查文件引入

<?php
// 引入函数文件
require 'functions.php';

// 调用
my_function();

检查函数名对不对

// functions.php里定义的
function my_function() {
    // ...
}

调用的时候名字要一模一样。

检查命名空间

如果用了命名空间,要注意:

<?php
namespace App;

// 调用别的命名空间的函数
\OtherNamespace\my_function();

六、常见函数和对应扩展

函数 需要的扩展
mysqli_connect mysqli
curl_init curl
imagecreate gd
mb_strlen mbstring
openssl_encrypt openssl
pdo连接 pdo_mysql
json_encode json(默认有)
file_get_contents 不需要(默认有)

七、常见坑

坑1:mysql函数被废弃了

PHP7以后,mysql_* 函数都没了,要用mysqli或者PDO。

Call to undefined function mysql_connect()

解决: 换成mysqli或者PDO。

坑2:CLI和FPM装的扩展不一样

命令行里装了,网页上没有。

原因: CLI和FPM用不同的php.ini。

解决: 看phpinfo里的配置,装到对应的PHP版本里。

坑3:装了扩展没重启

装完忘了重启php-fpm。

解决:

systemctl restart php-fpm

坑4:函数名大小写

PHP函数名不区分大小写,但自己写的类方法区分。

坑5:Composer自动加载没生效

用了Composer的库,但没 vendor/autoload.php。

require 'vendor/autoload.php';

八、快速排查

第一步:看报错的函数名

Call to undefined function xxx()

第二步:查扩展

php -m | grep 扩展名

第三步:没装就装

yum install php-扩展名

第四步:重启

systemctl restart php-fpm

九、常用扩展安装

一次性装常用扩展

yum install php-mysqli php-curl php-gd php-mbstring php-xml php-json

Ubuntu

apt install php-mysqli php-curl php-gd php-mbstring php-xml

总结

记住:

  1. 报错会告诉你是哪个函数没找到
  2. 内置函数就查扩展装了没
  3. 自己写的就查文件引入了没
  4. 装完扩展要重启php-fpm
  5. mysql_* 函数PHP7没了,换mysqli

排查流程:

看报错函数名 → 判断是内置还是自己写的 → 内置查扩展 → 自己写的查引入 → 解决

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-8 08:38 

PHP mysqli连接MySQL,完整示例代码 PHP

前言

PHP连MySQL用mysqli扩展,比mysql扩展好用,支持预处理、事务等。本文写个完整的连接和增删改查示例。

一、连接数据库

面向过程写法

<?php
$host = '127.0.0.1';
$user = 'root';
$pass = '123456';
$dbname = 'test';
$port = 3306;

// 连接
$conn = mysqli_connect($host, $user, $pass, $dbname, $port);

// 检查连接
if (!$conn) {
    die('连接失败: ' . mysqli_connect_error());
}

echo '连接成功';

面向对象写法

<?php
$conn = new mysqli('127.0.0.1', 'root', '123456', 'test', 3306);

if ($conn->connect_error) {
    die('连接失败: ' . $conn->connect_error);
}

echo '连接成功';

二、设置字符集

mysqli_set_charset($conn, 'utf8mb4');
// 或者
$conn->set_charset('utf8mb4');

注意: 一定要设utf8mb4,不然中文表情存不进去。

三、查询数据(SELECT)

面向过程

$sql = "SELECT id, name, age FROM users WHERE status = 1";
$result = mysqli_query($conn, $sql);

if (mysqli_num_rows($result) > 0) {
    while ($row = mysqli_fetch_assoc($result)) {
        echo "ID: " . $row['id'] . " 姓名: " . $row['name'] . "<br>";
    }
} else {
    echo "没有数据";
}

面向对象

$sql = "SELECT id, name, age FROM users WHERE status = 1";
$result = $conn->query($sql);

if ($result->num_rows > 0) {
    while ($row = $result->fetch_assoc()) {
        echo "ID: " . $row['id'] . " 姓名: " . $row['name'] . "<br>";
    }
}

取所有数据为数组

$list = [];
while ($row = mysqli_fetch_assoc($result)) {
    $list[] = $row;
}

print_r($list);

四、插入数据(INSERT)

直接写SQL

$name = '张三';
$age = 20;

$sql = "INSERT INTO users (name, age) VALUES ('$name', $age)";

if (mysqli_query($conn, $sql)) {
    echo "插入成功,ID: " . mysqli_insert_id($conn);
} else {
    echo "插入失败: " . mysqli_error($conn);
}

预处理(防SQL注入,推荐)

$stmt = mysqli_prepare($conn, "INSERT INTO users (name, age) VALUES (?, ?)");

mysqli_stmt_bind_param($stmt, 'si', $name, $age);
// 'si' 表示:string, int

$name = '李四';
$age = 25;

if (mysqli_stmt_execute($stmt)) {
    echo "插入成功,ID: " . mysqli_insert_id($conn);
} else {
    echo "失败: " . mysqli_error($conn);
}

五、更新数据(UPDATE)

$id = 1;
$name = '王五';

$sql = "UPDATE users SET name = '$name' WHERE id = $id";

if (mysqli_query($conn, $sql)) {
    echo "更新成功,影响行数: " . mysqli_affected_rows($conn);
}

六、删除数据(DELETE)

$id = 1;

$sql = "DELETE FROM users WHERE id = $id";

if (mysqli_query($conn, $sql)) {
    echo "删除成功";
}

七、关闭连接

mysqli_close($conn);
// 或者
$conn->close();

八、完整示例封装

<?php
class DB
{
    private $conn;

    public function __construct()
    {
        $this->conn = new mysqli('127.0.0.1', 'root', '123456', 'test', 3306);
        if ($this->conn->connect_error) {
            die('连接失败');
        }
        $this->conn->set_charset('utf8mb4');
    }

    // 查询多行
    public function queryAll($sql)
    {
        $result = $this->conn->query($sql);
        $list = [];
        while ($row = $result->fetch_assoc()) {
            $list[] = $row;
        }
        return $list;
    }

    // 查询单行
    public function queryOne($sql)
    {
        $result = $this->conn->query($sql);
        return $result->fetch_assoc();
    }

    // 关闭
    public function __destruct()
    {
        $this->conn->close();
    }
}

// 使用
$db = new DB();
$users = $db->queryAll("SELECT * FROM users");
print_r($users);

九、常见坑

坑1:SQL注入

直接拼接变量到SQL里,有注入风险。

解决: 用预处理语句(?占位符)。

坑2:中文乱码

忘了设字符集。

解决: 连接后立刻 set_charset('utf8mb4')。

坑3:只取一行

用 mysqli_fetch_assoc 循环多次才取完。

注意: 这个函数每次只取一行,要循环。

坑4:连接失败没报错

生产环境关了错误显示。

解决: 手动检查 mysqli_connect_error()。

坑5:忘了关连接

频繁连接不关,占资源。

解决: 用完就关,或者用单例。

总结

记住:

  1. mysqli_connect 连接数据库
  2. set_charset('utf8mb4') 设字符集
  3. mysqli_query 执行SQL
  4. mysqli_fetch_assoc 取数据
  5. 防注入用预处理(?占位符)
  6. 用完 mysqli_close 关连接

最常用:

$conn = mysqli_connect('127.0.0.1', 'root', '123456', 'test', 3306);
mysqli_set_charset($conn, 'utf8mb4');

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-8 08:36 

PHP上传文件大小限制,修改php.ini PHP

前言

上传个大点的文件,提示"文件过大"或者直接报错?那是PHP上传限制太小了。本文讲怎么改php.ini调大上传限制。

一、默认限制多大

PHP默认上传限制一般是:

  • upload_max_filesize = 2M
  • post_max_size = 8M

传个10M的文件就不行了。

二、要改哪几个参数

1. upload_max_filesize

单个文件最大大小:

upload_max_filesize = 100M

2. post_max_size

整个POST请求最大大小:

post_max_size = 100M

注意: post_max_size要 >= upload_max_filesize。

3. memory_limit

脚本可用内存:

memory_limit = 128M

要比post_max_size大。

4. max_execution_time

脚本最大执行时间(秒):

max_execution_time = 300

传大文件要久一点,设长点。

5. max_input_time

接收数据最大时间(秒):

max_input_time = 300

三、找php.ini

php --ini

或者写个phpinfo:

<?php
phpinfo();
?>

看Loaded Configuration File。

四、修改php.ini

改成100M上传

upload_max_filesize = 100M
post_max_size = 100M
memory_limit = 128M
max_execution_time = 300
max_input_time = 300

改成50M上传

upload_max_filesize = 50M
post_max_size = 50M
memory_limit = 64M

五、改完重启

PHP-FPM

systemctl restart php-fpm

Apache

systemctl restart httpd

六、验证

写个phpinfo,看这几个参数改了没:

<?php
phpinfo();
?>

搜 upload_max_filesize,看是不是改过来了。

七、Nginx也要改

光改PHP不够,Nginx也有限制。

Nginx配置

client_max_body_size 100M;

改完重载

nginx -t
nginx -s reload

八、常见坑

坑1:改了php.ini不生效

改的不是实际加载的那个。

解决: 用phpinfo看实际加载的是哪个。

坑2:只改了upload_max_filesize

post_max_size没改,还是不行。

注意: 两个都要改,post_max_size >= upload_max_filesize。

坑3:Nginx挡了

PHP改了,Nginx的client_max_body_size没改,还是413错误。

解决: Nginx也改。

坑4:内存不够

Allowed memory size of ... bytes exhausted

解决: 加大memory_limit。

坑5:上传超时

大文件传一半就断了。

解决: 加大max_execution_time和max_input_time。

坑6:.htaccess里覆盖了

有些主机在.htaccess里设了php_value。

检查: 看看.htaccess里有没有。

九、快速排查

上传报错

  1. 先看PHP的upload_max_filesize够不够
  2. 再看post_max_size够不够
  3. 再看Nginx的client_max_body_size够不够
  4. 再看memory_limit够不够

十、推荐配置

一般网站(20M上传)

upload_max_filesize = 20M
post_max_size = 20M
memory_limit = 64M

文件站(100M上传)

upload_max_filesize = 100M
post_max_size = 100M
memory_limit = 128M
max_execution_time = 300
max_input_time = 300

Nginx对应

client_max_body_size 100M;

总结

记住:

  1. 改三个参数:upload_max_filesize、post_max_size、memory_limit
  2. post_max_size >= upload_max_filesize
  3. Nginx也要改client_max_body_size
  4. 改完重启php-fpm和reload nginx
  5. 大文件要加大超时时间

最常用:

upload_max_filesize = 100M
post_max_size = 100M
memory_limit = 128M

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-8 08:35 
'); })();