PHP 常用设计模式
PHP 常用设计模式
设计模式是写好代码的经验总结,常用的几种要掌握。
1. 单例模式
整个项目只有一个实例,比如数据库连接。
class Db
{
private static $instance = null;
private function __construct() {}
public static function getInstance()
{
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
}
$db = Db::getInstance();
2. 工厂模式
根据参数创建不同的对象。
class Factory
{
public static function make($type)
{
$class = ucfirst($type);
return new $class();
}
}
$user = Factory::make('user');
$order = Factory::make('order');
3. 观察者模式
一个对象状态变化,通知所有观察者。
interface Observer
{
public function update($event);
}
class Event
{
private $observers = [];
public function add(Observer $observer)
{
$this->observers[] = $observer;
}
public function trigger($event)
{
foreach ($this->observers as $ob) {
$ob->update($event);
}
}
}
4. 常用场景
- 单例: 数据库、日志、配置
- 工厂: 创建不同类的对象
- 观察者: 事件触发、消息通知
- 策略: 不同支付方式
- 适配器: 兼容不同接口
5. 设计原则
- 单一职责:一个类只做一件事
- 开闭原则:对扩展开放,对修改关闭
- 依赖倒置:依赖抽象不依赖具体
总结
PHP 常用设计模式要点:
- 单例模式:只创建一个实例
- 工厂模式:统一创建对象
- 观察者:事件通知
- 理解设计原则
- 不要为了模式而模式
设计模式是工具,解决问题才是目的。
Linux 防火墙配置详解
Linux 防火墙配置详解
服务器安全第一步就是防火墙,学会配置很重要。
1. firewalld(CentOS 7+)
查看状态:
systemctl status firewalld
开启/关闭:
# 开启
systemctl start firewalld
# 关闭
systemctl stop firewalld
# 开机自启
systemctl enable firewalld
2. 开放端口
开放单个端口:
firewall-cmd --zone=public --add-port=80/tcp --permanent
开放多个端口:
firewall-cmd --zone=public --add-port=80-90/tcp --permanent
重新加载生效:
firewall-cmd --reload
3. 查看端口
# 查看所有开放端口
firewall-cmd --list-ports
# 查看某个端口是否开放
firewall-cmd --query-port=80/tcp
4. 关闭端口
firewall-cmd --zone=public --remove-port=80/tcp --permanent
firewall-cmd --reload
5. iptables(旧版)
查看规则:
iptables -L -n
开放端口:
iptables -I INPUT -p tcp --dport 80 -j ACCEPT
保存规则:
service iptables save
6. 常用端口
# 常用端口
22 SSH
80 HTTP
443 HTTPS
3306 MySQL
6379 Redis
8080 Tomcat
7. 常见问题
1)端口开了还是访问不了:
- 检查云服务商安全组
- 检查服务器内部防火墙
2)远程连接不上:
- 检查 22 端口是否开放
- 检查 sshd 是否启动
总结
Linux 防火墙要点:
- firewalld 管理端口
- --permanent 永久生效
- --reload 重新加载
- 记得开放安全组
- 常用端口按需开放
做运维,防火墙是基本功。
PHP Composer 使用指南
PHP Composer 使用指南
Composer 是 PHP 的依赖管理工具,做开发必备。
1. 安装 Composer
# 下载安装
curl -sS https://getcomposer.org/installer | php
# 移动到全局
mv composer.phar /usr/local/bin/composer
# 验证
composer -V
2. 国内镜像加速
# 阿里镜像
composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/
3. 常用命令
1)初始化项目:
composer init
2)安装依赖:
# 安装所有依赖
composer install
# 安装指定包
composer require monolog/monolog
# 安装开发依赖
composer require --dev phpunit/phpunit
3)更新依赖:
# 更新所有依赖
composer update
# 更新指定包
composer update monolog/monolog
4)删除依赖:
composer remove monolog/monolog
4. composer.json 说明
{
"name": "test/project",
"description": "测试项目",
"require": {
"php": ">=7.0",
"monolog/monolog": "^2.0"
},
"autoload": {
"psr-4": {
"App\\": "src/"
}
}
}
5. 自动加载
// 引入自动加载
require __DIR__ . '/vendor/autoload.php';
// 使用类
$log = new Monolog\Logger('name');
6. 常用操作
composer install:根据 lock 文件安装composer update:更新依赖composer dump-autoload:重新生成自动加载
总结
Composer 使用要点:
- 安装 Composer
- 配置国内镜像
- require 安装依赖
- autoload 自动加载
- install/update 管理依赖
做 PHP 开发,Composer 一定要会用。
MySQL 慢查询优化实战
MySQL 慢查询优化实战
数据库慢查询是性能瓶颈的常见原因,学会优化很重要。
1. 开启慢查询日志
-- 查看是否开启
SHOW VARIABLES LIKE 'slow_query_log';
-- 开启慢查询
SET GLOBAL slow_query_log = ON;
-- 设置慢查询时间(秒)
SET GLOBAL long_query_time = 1;
2. 分析慢查询
用 EXPLAIN 分析:
EXPLAIN SELECT * FROM users WHERE name = '张三';
重点看:
- type:访问类型,ALL 是全表扫描,要优化
- key:用了哪个索引
- rows:扫描行数
3. 常见优化方法
1)加索引:
-- 加索引
ALTER TABLE users ADD INDEX idx_name(name);
*2)避免 SELECT :**
-- 不好
SELECT * FROM users;
-- 好
SELECT id, name FROM users;
3)避免在索引字段上做运算:
-- 不好
SELECT * FROM users WHERE YEAR(create_time) = 2026;
-- 好
SELECT * FROM users WHERE create_time >= '2026-01-01' AND create_time < '2027-01-01';
4)避免 LIKE 左模糊:
-- 不好(用不到索引)
SELECT * FROM users WHERE name LIKE '%张%';
-- 好
SELECT * FROM users WHERE name LIKE '张%';
4. 分页优化
-- 不好(大偏移量慢)
SELECT * FROM users LIMIT 100000, 10;
-- 好(用子查询)
SELECT * FROM users WHERE id >= (
SELECT id FROM users LIMIT 100000, 1
) LIMIT 10;
5. 常见慢查询原因
- 没加索引
- 索引失效
- 关联查询太多
- 数据量太大
- 大表分页
总结
MySQL 慢查询优化要点:
- 开启慢查询日志
- 用 EXPLAIN 分析
- 合理加索引
- 避免全表扫描
- 优化分页查询
数据库优化是个细活,多分析多测试。
Nginx 日志分析技巧
Nginx 日志分析技巧
Nginx 日志是排查问题的重要工具,学会分析日志很重要。
1. 日志位置
默认日志路径:
# 访问日志
/var/log/nginx/access.log
# 错误日志
/var/log/nginx/error.log
2. 日志格式
默认日志格式:
log_format access '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent"';
3. 常用分析命令
1)查看访问量最多的IP:
awk '{print $1}' access.log | sort | uniq -c | sort -nr | head 10
2)查看访问最多的页面:
awk '{print $7}' access.log | sort | uniq -c | sort -nr | head 10
3)查看状态码分布:
awk '{print $9}' access.log | sort | uniq -c | sort -nr
4)查看404错误:
awk '$9 == 404 {print $7}' access.log | sort | uniq -c | sort -nr
4. 排查常用
1)查看哪个IP访问频繁:
grep "127.0.0.1" access.log
2)查看某个时间段日志:
grep "08/Oct/2026:07" access.log
3)查看错误日志:
tail -f error.log
5. 日志切割
用 logrotate 自动切割:
# /etc/logrotate.d/nginx
/var/log/nginx/*.log {
daily
missingok
rotate 30
compress
notifempty
create 0640 nginx adm
postrotate
systemctl reload nginx
endscript
}
6. 常用场景
- 被攻击了:查访问量最多的IP
- 页面报错:查404/500
- 流量突增:查访问最多的页面
- 爬虫多:查 User-Agent
总结
Nginx 日志分析要点:
- 访问日志查访问情况
- 错误日志排查问题
- awk 统计数据
- 日志自动切割
- 定期分析日志
做运维,看日志是基本功。
Redis 缓存雪崩解决
Redis 缓存雪崩解决
缓存雪崩是指大量缓存同时失效,请求全部打到数据库,数据库直接挂掉。
1. 什么是缓存雪崩
原理:
- 大量 key 同时过期
- 请求都查数据库
- 数据库压力瞬间暴增
- 数据库扛不住挂掉
和缓存穿透的区别:
- 穿透:查询不存在的数据
- 雪崩:大量缓存同时失效
2. 产生原因
1)缓存大面积过期:
- 大量数据设置了相同过期时间
- 到时间一起失效
2)Redis 宕机:
- Redis 服务挂了
- 所有请求都走数据库
3. 解决方案
方案一:过期时间加随机值
// 不要设置相同过期时间
$expire = 3600 + rand(0, 600);
$redis->setex("key", $expire, $value);
加随机值,让 key 分散过期,不会同时失效。
方案二:缓存永不过期
- 热点数据不设置过期时间
- 更新数据时主动更新缓存
- 异步更新缓存
方案三:Redis 高可用
- 搭建 Redis 集群
- 主从复制
- 哨兵模式
- 一台挂了还有其他的
方案四:熔断降级
- 请求量太大时直接返回默认值
- 不让请求打到数据库
- 保护数据库
4. 代码示例
function getData($id) {
global $redis, $db;
$key = "data:".$id;
$data = $redis->get($key);
if ($data) {
return json_decode($data, true);
}
// 查数据库
$data = $db->query("SELECT * FROM table WHERE id=$id");
// 缓存,过期时间加随机值
$expire = 3600 + rand(0, 600);
$redis->setex($key, $expire, json_encode($data));
return $data;
}
5. 最佳实践
- 过期时间加随机值
- 搭建 Redis 集群
- 热点数据永不过期
- 加熔断降级机制
- 数据库做限流
总结
缓存雪崩解决要点:
- 过期时间加随机值,不要同时失效
- Redis 做主从高可用
- 热点数据不设置过期
- 做好降级兜底
做高并发系统,缓存雪崩一定要防。
Nginx HTTPS 配置详解
Nginx HTTPS 配置详解
现在网站都要上 HTTPS,Nginx 配置 SSL 很简单。
1. 准备证书
免费证书可以用:
- Let's Encrypt
- 阿里云免费证书
- 腾讯云免费证书
下载后有两个文件:
- 证书文件:xxx.pem
- 私钥文件:xxx.key
2. 基础配置
server {
listen 443 ssl;
server_name www.example.com;
ssl_certificate /etc/nginx/ssl/xxx.pem;
ssl_certificate_key /etc/nginx/ssl/xxx.key;
location / {
root /www/wwwroot/html;
index index.html;
}
}
3. HTTP 跳转 HTTPS
# HTTP 重定向到 HTTPS
server {
listen 80;
server_name www.example.com;
return 301 https://$server_name$request_uri;
}
4. 优化配置
server {
listen 443 ssl http2;
server_name www.example.com;
ssl_certificate /etc/nginx/ssl/xxx.pem;
ssl_certificate_key /etc/nginx/ssl/xxx.key;
# SSL 优化
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
location / {
root /www/wwwroot/html;
index index.html;
}
}
5. 验证配置
# 检查配置是否正确
nginx -t
# 重载配置
nginx -s reload
6. 常见问题
1)证书不生效:
- 检查证书路径对不对
- 检查证书文件名
- 重载 Nginx
2)浏览器提示不安全:
- 证书域名不对
- 证书过期了
- 缺少中间证书
3)HTTP 打不开:
- 检查 80 端口是否放行
- 检查防火墙
7. Let's Encrypt 免费证书
用 certbot 自动申请:
# 安装
yum install certbot python3-certbot-nginx
# 自动申请并配置
certbot --nginx -d www.example.com
# 自动续期
certbot renew
总结
Nginx HTTPS 配置要点:
- 443 端口监听 SSL
- 配置证书和私钥路径
- HTTP 跳转 HTTPS
- 开启 http2 提升性能
- 定期续期证书
现在做网站,HTTPS 是标配。
MySQL 备份恢复实战
MySQL 备份恢复实战
数据库备份是运维的基本功,数据丢了就找不回来了。
1. 备份方式
1)物理备份:
- 直接拷贝数据文件
- 速度快,适合大数据库
2)逻辑备份:
- 导出 SQL 语句
- 体积小,跨平台
2. mysqldump 备份
备份整个数据库:
mysqldump -u root -p 数据库名 > backup.sql
备份单个表:
mysqldump -u root -p 数据库名 表名 > table.sql
备份所有数据库:
mysqldump -u root -p --all-databases > all.sql
3. 恢复数据
mysql -u root -p 数据库名 < backup.sql
注意: 恢复前要先创建数据库。
4. 压缩备份
# 备份并压缩
mysqldump -u root -p 数据库名 | gzip > backup.sql.gz
# 恢复压缩文件
gunzip < backup.sql.gz | mysql -u root -p 数据库名
5. 定时备份脚本
#!/bin/bash
# 数据库备份脚本
DB_USER="root"
DB_PASS="123456"
DB_NAME="test"
BACKUP_DIR="/data/backup"
DATE=$(date +%Y%m%d)
# 创建备份目录
mkdir -p $BACKUP_DIR
# 备份
mysqldump -u$DB_USER -p$DB_PASS $DB_NAME | gzip > $BACKUP_DIR/$DB_NAME_$DATE.sql.gz
# 删除7天前的备份
find $BACKUP_DIR -name "*.sql.gz" -mtime +7 -delete
加 crontab 定时执行:
# 每天凌晨3点备份
0 3 * * * /bin/bash /root/backup.sh
6. 常见问题
1)备份太大:
- 用 --quick 参数
- 压缩备份
2)备份报错:
- 检查用户名密码
- 检查权限
3)恢复失败:
- 检查 SQL 文件是否完整
- 检查数据库字符集
7. 最佳实践
- 每天定时备份
- 备份文件存到异地
- 定期测试恢复
- 重要数据做双备份
总结
MySQL 备份恢复要点:
- mysqldump 导出 SQL
- gzip 压缩减小体积
- crontab 定时执行
- 定期测试恢复
做运维,数据备份永远是第一位的。
MySQL索引失效常见场景,避免踩坑
明明建了索引,查询还是很慢?十有八九是索引失效了。MySQL 索引失效是开发中最常见的坑,下面整理了最容易导致索引失效的场景,写SQL的时候一定要避开。
1. 对索引字段做函数操作
-- 索引失效
SELECT * FROM user WHERE DATE(create_time) = '2026-10-01';
-- 正确写法,走索引
SELECT * FROM user WHERE create_time >= '2026-10-01' AND create_time < '2026-10-02';
对索引字段用了 DATE()、YEAR()、SUBSTRING() 等函数,索引就失效了。
2. 隐式类型转换
-- 假设 phone 是 varchar 类型
-- 索引失效(数字和字符串比较,MySQL自动转换)
SELECT * FROM user WHERE phone = 13800138000;
-- 正确写法,走索引
SELECT * FROM user WHERE phone = '13800138000';
字符串类型的字段,查询条件一定要加引号。
3. 联合索引不满足最左匹配原则
-- 联合索引:(a, b, c)
-- 走索引
SELECT * FROM t WHERE a = 1 AND b = 2;
-- 不走索引(跳过了a)
SELECT * FROM t WHERE b = 2 AND c = 3;
-- 走部分索引(a走,b和c不走)
SELECT * FROM t WHERE a = 1 AND c = 3;
联合索引必须从最左边的列开始用,不能跳过。
4. 使用了 != 或 <>
-- 索引大概率失效
SELECT * FROM user WHERE status != 1;
-- 可以改成范围查询
SELECT * FROM user WHERE status < 1 OR status > 1;
不等于操作通常会导致全表扫描,因为要返回的结果太多了。
5. LIKE 以 % 开头
-- 索引失效
SELECT * FROM user WHERE name LIKE '%张';
-- 走索引
SELECT * FROM user WHERE name LIKE '张%';
模糊查询左边带 %,索引就用不上了。
6. OR 连接的条件有一个没索引
-- name 有索引,age 没索引 → 整个SQL不走索引
SELECT * FROM user WHERE name = '张三' OR age = 20;
OR 两边只要有一个字段没索引,整个查询就不走索引。
7. 用 explain 验证索引是否生效
EXPLAIN SELECT * FROM user WHERE name = '张三';
看 key 列:
- 显示索引名 → 走索引了
- 显示 NULL → 没走索引
看 type 列:
ref、eq_ref→ 正常ALL→ 全表扫描,索引失效了
常见坑总结
- 不要在索引字段上做运算:
WHERE age + 1 = 20→ 改成WHERE age = 19 - 不要用 NOT IN / NOT EXISTS:大数据量下很慢
- **不要用 SELECT ***:只查需要的字段,覆盖索引更快
- 数据量小的表不要建索引:全表扫描可能比索引还快
遇到问题加QQ23979811 协助处理
PHP 会话管理详解
PHP 会话管理详解
Session 是 PHP 做用户登录状态管理的核心功能,搞懂它很重要。
1. 什么是 Session
- Cookie: 存在客户端(浏览器)
- Session: 存在服务器端
- 通过 SessionID 关联用户
2. 基础用法
// 开启会话(必须放在最前面)
session_start();
// 存数据
$_SESSION['user_id'] = 1;
$_SESSION['username'] = "test";
// 取数据
echo $_SESSION['username'];
// 判断是否登录
if (isset($_SESSION['user_id'])) {
echo "已登录";
} else {
echo "未登录";
}
// 销毁会话
session_destroy();
3. 登录验证示例
// 登录页
session_start();
if ($_POST['password'] == "123456") {
$_SESSION['user'] = $_POST['username'];
header("Location: dashboard.php");
}
// 验证页
session_start();
if (!isset($_SESSION['user'])) {
header("Location: login.php");
exit;
}
4. 常用配置
php.ini 里的配置:
; 会话有效期(分钟)
session.gc_maxlifetime = 1440
; Cookie 有效期(秒)
session.cookie_lifetime = 0
; 是否只允许 HTTP 访问 Cookie
session.cookie_httponly = On
5. 常见问题
1)session 丢失:
- 检查是否有输出(session_start 前不能有空格)
- 检查 Cookie 是否被禁用
2)多服务器共享 Session:
- 存在数据库里
- 存在 Redis 里
- 不要用文件 Session
3)安全问题:
- 登录后重新生成 SessionID
session_regenerate_id(); - 防止 Session 固定攻击
6. Cookie vs Session
| 对比 | Cookie | Session |
|---|---|---|
| 存储位置 | 客户端 | 服务器端 |
| 大小限制 | 4KB | 无限制 |
| 安全性 | 低 | 高 |
| 生命周期 | 可长期保存 | 浏览器关闭就没了 |
7. 登出销毁
session_start();
// 清除所有 session 变量
$_SESSION = array();
// 清除 session cookie
if (isset($_COOKIE[session_name()])) {
setcookie(session_name(), '', time()-42000, '/');
}
// 销毁 session
session_destroy();
总结
PHP 会话管理要点:
- session_start() 必须在最前面
- 登录验证用 $_SESSION 判断
- 生产环境用 Redis 存 Session
- 登录后重新生成 SessionID 防攻击
做用户系统,Session 是必须掌握的。
Docker 镜像加速配置
Docker 镜像加速配置
国内拉取 Docker 镜像很慢,配置镜像加速器很有必要。
1. 为什么要加速
Docker Hub 在国外,国内拉镜像经常超时,配置加速器能快很多。
2. 配置方法
Linux(CentOS/Ubuntu):
编辑配置文件:
mkdir -p /etc/docker
vi /etc/docker/daemon.json
写入内容:
{
"registry-mirrors": [
"https://docker.mirrors.ustc.edu.cn",
"https://hub-mirror.c.163.com"
]
}
重启生效:
systemctl daemon-reload
systemctl restart docker
3. 常用加速器
# 中科大
https://docker.mirrors.ustc.edu.cn
# 网易
https://hub-mirror.c.163.com
# 阿里(需要自己的地址)
https://xxxx.mirror.aliyuncs.com
4. 验证是否生效
docker info
看到 Registry Mirrors 下面有地址就说明成功了。
5. 常见问题
1)拉取还是很慢:
- 换个加速器试试
- 网络问题
2)配置不生效:
- 检查 json 格式对不对
- 重启 docker
3)企业内网:
- 可以自己搭建私有镜像仓库
- 或者用阿里云私有镜像服务
6. 常用镜像源
# 官方
docker pull nginx
docker pull mysql
docker pull redis
# 指定版本
docker pull nginx:1.25
docker pull mysql:8.0
总结
Docker 镜像加速核心:
- 配置 daemon.json
- 用国内加速器地址
- 重启 docker 生效
- docker info 验证
做运维开发,Docker 镜像加速是第一步。
PHP 错误处理机制
PHP 错误处理机制
做开发离不开错误处理,搞懂 PHP 的错误机制才能写出健壮的代码。
1. 错误级别
PHP 错误分几个级别:
1)致命错误(E_ERROR)
- 脚本停止执行
- 比如调用不存在的类、方法
2)警告(E_WARNING)
- 脚本继续执行
- 比如包含不存在的文件
3)注意(E_NOTICE)
- 不影响执行
- 比如使用未定义的变量
2. 错误报告配置
php.ini 里的配置:
; 开发环境:显示所有错误
display_errors = On
error_reporting = E_ALL
; 生产环境:不显示错误,记录日志
display_errors = Off
log_errors = On
error_reporting = E_ALL & ~E_NOTICE
3. 自定义错误处理
// 设置错误报告级别
error_reporting(E_ALL);
// 自定义错误处理函数
set_error_handler(function($errno, $errstr, $errfile, $errline) {
echo "错误:[$errno] $errstr 在 $errfile 第 $errline 行";
return true; // 阻止默认错误处理
});
// 测试
echo $undefined_var;
4. 异常处理
try {
if (!file_exists("test.txt")) {
throw new Exception("文件不存在");
}
$file = fopen("test.txt", "r");
} catch (Exception $e) {
echo "错误:" . $e->getMessage();
} finally {
echo "\n执行完成";
}
5. 错误日志
// 记录错误日志
error_log("这是一条错误日志", 3, "/tmp/php_errors.log");
// 手动触发错误
trigger_error("自定义错误", E_USER_WARNING);
6. 开发 vs 生产
开发环境:
- 显示错误
- 所有错误都报告
- 方便调试
生产环境:
- 不显示错误(防止泄露敏感信息)
- 记录错误日志
- 只报告致命错误和警告
7. 常用技巧
1)错误抑制符 @
// 不推荐,会影响性能
@include("config.php");
2)die/exit
// 简单粗暴
if (! $db) {
die("数据库连接失败");
}
3)抛异常
- 推荐用异常处理
- 代码更清晰,容易维护
总结
PHP 错误处理要点:
- 开发环境显示错误,生产环境记录日志
- 用 try-catch 处理异常
- 错误日志要记录,方便排查
- 不要用 @ 错误抑制符
写代码多做错误处理,线上少踩坑。
Linux 查看系统资源
Linux 查看系统资源
服务器卡了慢了,得知道哪个进程占资源多。整理常用的查看命令。
1. 查看内存使用
# 查看内存使用情况
free -h
# 持续查看
free -h 1
输出说明:
- total:总内存
- used:已使用
- free:空闲
- buff/cache:缓存
- available:可用
2. 查看 CPU 负载
# 查看 CPU 信息
top
# 按 q 退出
top 常用快捷键:
- P:按 CPU 排序
- M:按内存排序
- 1:查看每个核心
3. 查看磁盘使用
# 查看磁盘空间
df -h
# 查看目录大小
du -sh /www/
# 查看当前目录下每个文件大小
du -sh *
4. 查看进程
# 查看所有进程
ps aux
# 查看 PHP 进程
ps aux | grep php
# 查看端口占用
netstat -tlnp
5. 查看系统信息
# 查看系统版本
cat /etc/os-release
# 查看内核版本
uname -a
# 查看 CPU 核心数
nproc
# 查看内存大小
cat /proc/meminfo | head -5
6. 查找大文件
# 查找大于100M的文件
find / -type f -size +100M
# 查找最近7天修改的文件
find /www -type f -mtime -7
7. 常用场景
网站卡了:
- top 看 CPU 和内存
- df -h 看磁盘满没满
- 看日志
内存不够用:
- free -h 看内存
- top 按 M 排序找占内存大的进程
总结
常用命令记这几个:
- 内存:free -h
- CPU:top
- 磁盘:df -h / du -sh
- 进程:ps aux
- 端口:netstat
做运维这些命令天天用,必须熟。
PHP 数组常用函数
PHP 数组常用函数
数组是 PHP 最常用的数据结构,数组函数用熟了开发效率翻倍。整理一份常用清单。
1. 数组创建和遍历
// 索引数组
$arr1 = [1, 2, 3];
// 关联数组
$arr2 = ['name' => '张三', 'age' => 25];
// 遍历
foreach ($arr2 as $key => $value) {
echo "$key: $value\n";
}
2. 数组增删改查
// 追加元素
$arr[] = 4;
array_push($arr, 5, 6);
// 头部插入
array_unshift($arr, 0);
// 删除末尾元素
array_pop($arr);
// 删除头部元素
array_shift($arr);
// 删除指定元素
unset($arr[0]);
3. 数组合并和拆分
// 合并数组
$arr1 = [1, 2];
$arr2 = [3, 4];
$merged = array_merge($arr1, $arr2); // [1,2,3,4]
// 拆分
$slice = array_slice($arr, 0, 2);
4. 查找和过滤
// 判断键是否存在
array_key_exists('name', $arr);
// 判断值是否存在
in_array('张三', $arr);
// 查找值对应的键
array_search('张三', $arr);
// 数组过滤
$filtered = array_filter([1, 2, 3, 4], function($n) {
return $n > 2;
}); // [3,4]
5. 排序
sort($arr); // 升序
rsort($arr); // 降序
asort($arr); // 按值升序,保留键
ksort($arr); // 按键升序
6. 常用操作
// 数组长度
count($arr);
// 去重
array_unique($arr);
// 反转
array_reverse($arr);
// 随机取一个
array_rand($arr);
7. 实际应用
统计数组中出现次数:
$counts = array_count_values(['a', 'b', 'a', 'c', 'a']);
// ['a' => 3, 'b' => 1, 'c' => 1]
二维数组按某列排序:
$users = [
['name' => '张三', 'age' => 25],
['name' => '李四', 'age' => 20]
];
array_multisort(array_column($users, 'age'), SORT_ASC, $users);
总结
PHP 数组函数非常多,日常开发记住这些常用的就够了:
- 增删改查:array_push / array_pop / unset
- 合并拆分:array_merge / array_slice
- 查找过滤:in_array / array_filter
- 排序:sort / asort / ksort
数组是 PHP 的灵魂,多用多练就熟了。
MySQL慢查询开启,定位慢SQL语句方法
前言
网站越来越慢,不知道哪条 SQL 拖后腿。MySQL 自带慢查询日志功能,能把执行慢的 SQL 记录下来,方便优化。
什么是慢查询
就是执行时间超过某个阈值的 SQL 语句。默认阈值是 10 秒,太久了,一般改成 1 秒或者 2 秒。
临时开启(重启不丢)
登录 MySQL:
mysql -u root -p
开启慢查询:
-- 开启慢查询
SET GLOBAL slow_query_log = ON;
-- 设置超过1秒就记录
SET GLOBAL long_query_time = 1;
-- 查看慢查询日志位置
SHOW VARIABLES LIKE 'slow_query_log_file';
永久开启(改配置文件)
改 my.cnf:
vi /etc/my.cnf
加上:
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1
重启 MySQL:
systemctl restart mysqld
慢查询日志长什么样
# Time: 2026-10-07T07:00:00.000000Z
# User@Host: root[root] @ localhost [] Id: 1234
# Query_time: 5.234567 Lock_time: 0.000123 Rows_sent: 1000 Rows_examined: 1000000
SET timestamp=1728270000;
SELECT * FROM users WHERE name LIKE '%张%';
重点看:
Query_time:执行时间Rows_examined:扫描了多少行- 最后一行就是慢 SQL 语句
分析慢查询日志
用 mysqldumpslow 工具:
# 找出最慢的10条SQL
mysqldumpslow -s t -t 10 /var/log/mysql/slow.log
# 找出返回数据最多的10条
mysqldumpslow -s r -t 10 /var/log/mysql/slow.log
参数说明:
| 参数 | 说明 |
|---|---|
-s t |
按时间排序 |
-s r |
按返回行数排序 |
-t 10 |
显示前10条 |
常见坑
坑1:没开启慢查询
不知道怎么开,或者开了忘了。
解决: 用 SHOW VARIABLES LIKE 'slow_query_log'; 确认一下。
坑2:阈值设太大
默认是 10 秒,10 秒以下的慢 SQL 都没记录到。
解决: 改成 1 秒,够用了。
坑3:日志太大占磁盘
慢查询日志一直写,磁盘满了。
解决: 配 logrotate 定期切割。
坑4:没记录没走索引的SQL
有些 SQL 虽然快,但没走索引,数据量一大就慢了。
解决: 加上这个参数,没走索引的也记录:
log_queries_not_using_indexes = 1
总结
三步开启慢查询:
- 开
slow_query_log - 设
long_query_time - 用
mysqldumpslow分析
记住: 慢查询日志是优化数据库的第一步,先开了再说。
遇到问题加QQ23979811 协助处理
Nginx报"no input file specified"错误解决
前言
访问 PHP 页面,直接报 "No input file specified",意思是 PHP-FPM 找不到要执行的 PHP 文件。这是 Nginx 配置里 root 路径不对导致的。
报错长什么样
页面上直接显示:
No input file specified.
没有其他信息,就这么一句话。
常见原因
原因1:root 路径不对
PHP location 里的 root 和 server 里的 root 不一致。
错误示例:
server {
root /var/www/html;
location ~ \.php$ {
fastcgi_param SCRIPT_FILENAME /var/www/php$fastcgi_script_name;
}
}
这样 PHP 找文件的时候就找错目录了。
正确做法:
server {
root /var/www/html;
location ~ \.php$ {
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
用 $document_root 自动取 server 里的 root。
原因2:文件真的不存在
URL 对应的 PHP 文件根本就没有。
检查:
ls /var/www/html/test.php
原因3:文件权限不对
文件存在,但 Nginx/PHP-FPM 读不了。
解决: 确保文件权限是 644,目录是 755,属主是 www。
完整正确的配置
server {
listen 80;
server_name www.example.com;
root /var/www/html;
index index.php index.html;
location / {
try_files $uri $uri/ =404;
}
location ~ \.php$ {
fastcgi_pass unix:/run/php-fpm/www.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
排查步骤
第一步:确认文件在不在
ls /var/www/html/test.php
第二步:看 Nginx 错误日志
tail -f /var/log/nginx/error.log
访问一下报错的页面,看日志里写的路径是什么。
第三步:确认 root 路径
grep root /etc/nginx/conf.d/你的站点.conf
常见坑
坑1:fastcgi_param 写错了
写成了 $request_filename 或者其他变量。
解决: 一定要用 $document_root$fastcgi_script_name。
坑2:伪静态和 PHP 冲突
配了伪静态,导致 PHP 请求被重写到别的地方了。
解决: 确保伪静态规则在 PHP location 之前,而且 PHP location 能正常匹配到 .php 请求。
坑3:多站点 root 不一致
A 站点的 PHP 请求跑到 B 站点去了。
原因: 多个站点的 root 配置不对。
解决: 每个站点的 root 都写清楚,别共用。
坑4:PHP-FPM 配置不对
PHP-FPM 的 www.conf 里的 listen 路径和 Nginx 配置的不一致。
解决: 确认两边的 socket 路径一样。
总结
90% 的情况都是 root 路径不对。
检查这三点:
- root 路径写对了没
- 文件真的存在不
- 文件权限对不对
记住: PHP 配置里一定要用 $document_root$fastcgi_script_name,别写死路径。
遇到问题加QQ23979811 协助处理
Nginx配置访问密码,限制后台访问
前言
网站后台地址公开,谁都能访问,容易被别人扫到然后暴力破解。给后台加一层 Nginx 访问密码,多一道防护。
什么是访问密码
就是访问某个目录前,浏览器先弹一个登录框,输入用户名密码才能进去。和网站本身的登录是两回事。
第一步:生成密码文件
用 htpasswd 命令生成密码文件:
htpasswd -c /etc/nginx/.htpasswd admin
第一次加 -c 创建文件,输入两次密码。
不加 -c 是追加新用户:
htpasswd /etc/nginx/.htpasswd user2
如果没有 htpasswd 命令,先装:
yum install -y httpd-tools
第二步:Nginx 配置
给后台目录加密码:
location /admin/ {
auth_basic "Admin Login";
auth_basic_user_file /etc/nginx/.htpasswd;
}
完整配置示例
server {
listen 80;
server_name www.example.com;
root /var/www/html;
index index.php index.html;
# 后台加密码
location /admin/ {
auth_basic "Admin Login";
auth_basic_user_file /etc/nginx/.htpasswd;
# 后台本身的 PHP 配置
location ~ \.php$ {
fastcgi_pass unix:/run/php-fpm/www.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
# 前台正常访问
location / {
try_files $uri $uri/ =404;
}
}
重载生效
nginx -t
nginx -s reload
常见坑
坑1:.htpasswd 文件权限不对
Nginx 读不到密码文件。
解决: 确保文件权限是 644,属主是 www:
chown www:www /etc/nginx/.htpasswd
chmod 644 /etc/nginx/.htpasswd
坑2:PHP 文件不弹密码
访问 /admin/index.php 直接就进了,没弹密码框。
原因: PHP 的 location 把请求拦截了,没走 auth_basic。
解决: 把 auth_basic 配置放到 PHP 的 location 里,或者放到 server 级别。
坑3:忘记密码
自己把密码忘了。
解决: 重新生成:
htpasswd -b /etc/nginx/.htpasswd admin 新密码
坑4:密码文件放网站目录里
把 .htpasswd 放在了网站根目录下,别人能直接下载。
解决: 密码文件放在网站目录外面,比如 /etc/nginx/ 下面。
总结
两步搞定:
htpasswd生成密码文件- Nginx 加
auth_basic配置
记住: 密码文件别放网站目录里,放在外面安全。
遇到问题加QQ23979811 协助处理
Nginx日志切割,按天切割nginx日志
前言
Nginx 的访问日志一直写在一个文件里,越写越大,几百GB都有可能。磁盘满了网站就挂了。本文讲一下怎么用 logrotate 自动按天切割 Nginx 日志。
为什么要切割日志
- 日志太大占磁盘
- 分析大文件慢
- 出问题查日志不方便
方法一:用系统自带的 logrotate
CentOS 自带 logrotate,直接配就行。
第一步:写配置文件
vi /etc/logrotate.d/nginx
内容:
/var/log/nginx/*.log {
daily
missingok
rotate 30
compress
notifempty
create 0644 www www
postrotate
/bin/kill -USR1 `cat /run/nginx.pid 2>/dev/null` 2>/dev/null || true
endscript
}
参数说明:
| 参数 | 说明 |
|---|---|
daily |
按天切割 |
rotate 30 |
保留30天的日志 |
compress |
压缩旧日志 |
notifempty |
空文件不切割 |
missingok |
日志文件不存在不报错 |
第二步:测试一下
logrotate -d /etc/logrotate.d/nginx
-d 是调试模式,不会真执行,看一下有没有报错。
第三步:立即执行一次
logrotate -f /etc/logrotate.d/nginx
方法二:自己写脚本
不想用 logrotate,自己写个 shell 脚本:
vi /root/nginx_log.sh
内容:
#!/bin/bash
LOG_PATH=/var/log/nginx
YESTERDAY=$(date -d "yesterday" +%Y%m%d)
cd $LOG_PATH
mv access.log access_$YESTERDAY.log
mv error.log error_$YESTERDAY.log
nginx -s reopen
加执行权限:
chmod +x /root/nginx_log.sh
加到 crontab,每天凌晨执行:
crontab -e
加一行:
0 0 * * * /root/nginx_log.sh
常见坑
坑1:切割后日志不写了
把日志文件改名了,Nginx 还往旧文件写。
原因: Nginx 打开的是文件句柄,改名后它不知道。
解决: 切割后要通知 Nginx 重新打开日志文件:
nginx -s reopen
坑2:旧日志没删,磁盘还是满的
配了切割,但旧日志还留着。
原因: 没配 rotate 参数。
解决: 加上 rotate 30,自动只保留30天。
坑3:压缩太占CPU
所有日志都压缩,CPU 飙高。
解决: 错峰压缩,比如凌晨3点再压缩,或者用 delaycompress 延迟一天再压缩。
坑4:日志权限不对
切割后新日志文件属主不对,Nginx 写不了。
解决: logrotate 配置里加 create 0644 www www。
总结
推荐用 logrotate,系统自带,不用自己维护脚本。
核心配置就这些:
/var/log/nginx/*.log {
daily
rotate 30
compress
postrotate
/bin/kill -USR1 `cat /run/nginx.pid`
endscript
}
记住: 切割完一定要通知 Nginx 重新打开日志文件,不然新日志不写。
遇到问题加QQ23979811 协助处理
Nginx配置websocket反向代理
前言
做实时聊天、推送、在线游戏,需要用 WebSocket。Nginx 当反向代理的时候,默认不支持 WebSocket 协议,需要额外配置。本文讲一下怎么配。
WebSocket 是什么
WebSocket 是一种全双工通信协议,浏览器和服务器建立连接后,可以一直保持连接,互相实时推送消息。
为什么需要特殊配置
普通 HTTP 请求是短连接,请求完就断了。WebSocket 是长连接,而且用的是 Upgrade 协议头。Nginx 默认的反向代理不支持这种升级,需要加特殊配置。
基础配置
location /ws/ {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
关键就是这三行:
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
完整配置示例
server {
listen 80;
server_name www.example.com;
root /var/www/html;
index index.html;
# WebSocket 代理
location /ws/ {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_read_timeout 300s;
}
# 普通 HTTP 代理
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
超时配置
WebSocket 是长连接,默认超时时间短了会自动断开。
proxy_read_timeout 300s;
proxy_send_timeout 300s;
意思是:5分钟没有数据传输才断开。
常见坑
坑1:WebSocket 连接失败
前端连 WebSocket 一直失败。
原因: Nginx 没配 Upgrade 和 Connection 头。
解决: 加上那三行关键配置。
坑2:连接几秒就自动断了
连上了,过一会儿就断了。
原因: Nginx 默认超时时间太短(60秒)。
解决: 调大 proxy_read_timeout。
坑3:HTTPS 下 WebSocket 连不上
HTTP 下正常,HTTPS 下连不上。
原因: 前端用了 ws://,但网站是 https 的,浏览器不让。
解决: 前端用 wss://(加密的 WebSocket)。
坑4:连接数太多被拒
很多人同时在线,新的连接被拒了。
原因: Nginx 或后端服务器连接数限制。
解决: 调大 Nginx 和后端的连接数限制。
总结
WebSocket 代理就三行核心配置:
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
记住: WebSocket 是长连接,记得调大超时时间,别让它自动断了。
遇到问题加QQ23979811 协助处理
Nginx防盗链配置,防止图片被别人盗用
前言
网站的图片被别人盗链了,他的网站直接用你的图片地址,流量全从你服务器走,白白消耗带宽。Nginx 可以配置防盗链,防止这种情况。
什么是盗链
就是别人在自己网站里直接引用你服务器上的图片。用户看他的网站,实际图片是从你服务器加载的。
防盗链原理
Nginx 检查请求头里的 Referer 字段,看是从哪个页面过来的。如果不是自己网站的 Referer,就拒绝或者返回一张提示图。
基础配置
location ~* \.(jpg|png|gif|jpeg)$ {
valid_referers none blocked www.example.com example.com;
if ($invalid_referer) {
return 403;
}
}
解释:
valid_referers:允许哪些来源访问none:允许直接输入地址访问blocked:允许伪装的 Refererwww.example.com:自己的域名
配置示例
server {
listen 80;
server_name www.example.com;
root /var/www/html;
index index.html;
# 防盗链
location ~* \.(jpg|png|gif|jpeg|webp)$ {
valid_referers none blocked www.example.com example.com *.example.com;
if ($invalid_referer) {
return 403;
}
}
}
替换成提示图
不想直接 403,可以返回一张"禁止盗链"的提示图:
location ~* \.(jpg|png|gif|jpeg)$ {
valid_referers none blocked www.example.com example.com;
if ($invalid_referer) {
rewrite ^/.*\.(jpg|png|gif)$ /no-hotlink.png last;
}
}
这样别人盗链就显示一张提示图。
常见坑
坑1:自己网站图片也加载不出来
配了防盗链,自己网站的图片也打不开了。
原因: valid_referers 里没写全自己的域名。
解决: 把 http 和 https 的域名都写上:
valid_referers none blocked www.example.com example.com;
坑2:搜索引擎图片也被挡了
百度图片搜不到你的图片了。
原因: 防盗链把搜索引擎也挡了。
解决: 加上搜索引擎的 Referer:
valid_referers none blocked www.example.com example.com *.baidu.com *.google.com;
坑3:CDN 后面防盗链不生效
用了 CDN,防盗链配置不生效。
原因: 请求经过 CDN,Referer 是 CDN 的。
解决: CDN 那边配置防盗链,或者把 CDN 的 Referer 加到白名单。
坑4:微信里打开图片不显示
在微信里打开自己的文章,图片显示不出来。
原因: 微信的 Referer 被挡了。
解决: 加上微信的 Referer:
valid_referers none blocked www.example.com example.com *.weixin.qq.com;
总结
防盗链就三行配置:
valid_referers none blocked www.example.com example.com;
if ($invalid_referer) {
return 403;
}
记住: 配完防盗链,先测试一下自己网站图片能不能正常打开。
遇到问题加QQ23979811 协助处理