这个导致的问题是项目内测vendor有多个先加载了旧版的GuzzleHttp\Psr7\Utils 旧版的 GuzzleHttp\Psr7\Utils 没有 redactUserInfo 导致报错
实际就是多个vendor版本冲突,建议整合下composer,保留一个vendor处于加载状态即可
这个导致的问题是项目内测vendor有多个先加载了旧版的GuzzleHttp\Psr7\Utils 旧版的 GuzzleHttp\Psr7\Utils 没有 redactUserInfo 导致报错
实际就是多个vendor版本冲突,建议整合下composer,保留一个vendor处于加载状态即可
/etc/systemd/system/ (用户自定义配置)/usr/lib/systemd/system/ 中的同名文件)# 查看目录内容示例
ls -la /etc/systemd/system/
/usr/lib/systemd/system/ (系统默认配置)# 查看已安装服务的默认配置
ls -la /usr/lib/systemd/system/
/run/systemd/system/ (运行时配置)/etc/systemd/system/.service)定义系统服务的行为:
[Unit]
Description=My Application Service
After=network.target
[Service]
Type=simple
User=www-data
ExecStart=/usr/bin/php /var/www/html/artisan queue:work
Restart=always
[Install]
WantedBy=multi-user.target
.path)监控文件或目录变化:
[Unit]
Description=Watch config file changes
[Path]
PathChanged=/var/www/html/config.php
Unit=myapp.service
[Install]
WantedBy=multi-user.target
.timer)定时任务(类似 cron):
[Unit]
Description=Run backup daily
[Timer]
OnCalendar=daily
Persistent=true
[Install]
WantedBy=timers.target
.target)分组管理服务(类似运行级别):
multi-user.target – 多用户文本模式graphical.target – 图形界面模式network.target – 网络就绪# 重载 systemd 配置(修改配置后必须执行)
sudo systemctl daemon-reload
# 启用服务(开机启动)
sudo systemctl enable myapp.service
# 启动服务
sudo systemctl start myapp.service
# 停止服务
sudo systemctl stop myapp.service
# 重启服务
sudo systemctl restart myapp.service
# 查看服务状态
sudo systemctl status myapp.service
# 查看服务日志
sudo journalctl -u myapp.service -f
# 禁用服务
sudo systemctl disable myapp.service
# 列出所有失败的服务
sudo systemctl --failed
# 查看服务依赖关系
systemctl list-dependencies myapp.service
# 查看启用的所有服务
systemctl list-unit-files --type=service --state=enabled
/run/systemd/system/ (最高优先级)
↓
/etc/systemd/system/ (用户配置,推荐修改此处)
↓
/usr/lib/systemd/system/ (最低优先级,软件包默认配置)
# 1. 创建服务文件
sudo vim /etc/systemd/system/myapp.service
# 2. 重载配置
sudo systemctl daemon-reload
# 3. 启用并启动服务
sudo systemctl enable --now myapp.service
# 创建覆盖配置(不修改原文件)
sudo systemctl edit nginx
# 这会在 /etc/systemd/system/nginx.service.d/override.conf
# 添加自定义配置片段
# 测试服务配置是否正确
systemd-analyze verify /etc/systemd/system/myapp.service
# 查看服务启动时间分析
systemd-analyze blame
基于您的项目结构,如果要为 WordPress 或相关服务创建 systemd 配置:
示例:WordPress Cron 服务
# /etc/systemd/system/wp-cron.service
[Unit]
Description=WordPress Cron Handler
After=network.target mysql.service
[Service]
Type=oneshot
User=www-data
WorkingDirectory=/var/www/html
ExecStart=/usr/bin/php wp-cron.php
[Install]
WantedBy=multi-user.target
示例:监控配置文件变化
# /etc/systemd/system/wp-config-monitor.path
[Unit]
Description=Monitor wp-config.php changes
[Path]
PathChanged=/var/www/html/wp-config.php
Unit=php-fpm.service
[Install]
WantedBy=multi-user.target
需要我帮您创建具体的 systemd 配置文件吗?
我来为您详细说明 MySQL 中长度较大的 VARCHAR 字段的索引限制问题。
MySQL 对索引长度有以下主要限制:
innodb_large_prefix)DYNAMIC 或 COMPRESSED 行格式不同字符集下,VARCHAR 字段能创建的最大索引长度不同:
单字节字符集 (latin1):
- 767 字节限制:VARCHAR(767)
- 3072 字节限制:VARCHAR(3072)
多字节字符集 (utf8mb4):
- 每个字符最多 4 字节
- 767 字节限制:VARCHAR(191) [767 ÷ 4 = 191.75]
- 3072 字节限制:VARCHAR(768) [3072 ÷ 4 = 768]
-- ❌ 在 utf8mb4 字符集下会报错
CREATE TABLE users (
name VARCHAR(500),
INDEX idx_name (name) -- 错误:索引长度 2000 字节 > 767 字节
);
-- ✅ 安全的做法
CREATE TABLE users (
name VARCHAR(191),
INDEX idx_name (name) -- 正确:191 × 4 = 764 字节 < 767 字节
);
方案 1: 使用前缀索引
-- 只对字段的前 N 个字符创建索引
CREATE TABLE articles (
title VARCHAR(500),
INDEX idx_title_prefix (title(191)) -- 只索引前 191 个字符
);
方案 2: 升级配置 (MySQL 5.7+)
-- 1. 设置 innodb_large_prefix
SET GLOBAL innodb_large_prefix = ON;
-- 2. 使用 DYNAMIC 行格式
CREATE TABLE users (
name VARCHAR(500),
INDEX idx_name (name)
) ROW_FORMAT=DYNAMIC;
-- 3. 或者修改现有表
ALTER TABLE users ROW_FORMAT=DYNAMIC;
方案 3: 使用全文索引 (适合长文本搜索)
CREATE TABLE articles (
content TEXT,
FULLTEXT INDEX ft_content (content)
);
-- 查看 innodb_large_prefix 设置
SHOW VARIABLES LIKE 'innodb_large_prefix';
-- 查看表的行格式
SHOW TABLE STATUS LIKE 'your_table_name';
-- 查看数据库字符集
SHOW VARIABLES LIKE 'character_set_database';
-- 查看索引长度限制
SHOW VARIABLES LIKE 'innodb_default_row_format';
Error 1071: Specified key was too long; max key length is 767 bytes
Error 1170: BLOB/TEXT column 'xxx' used in key specification without a key length
如果您需要针对具体的业务场景选择合适的索引策略,请告诉我您的具体需求(如字段用途、查询模式等),我可以给出更精准的建议。
MySQL 表分区的不同通常不会影响正常使用,但有一些需要注意的地方:
查询性能
唯一键限制
外键约束
维护操作
如果你考虑使用表分区,需要确保:
mysqldump -h 123.3.3.3 --compress --single-transaction --quick -u OOOK -pPP01 OOOK | mysql -h 127.0.0.3 -u OOOK -pPP01 OOOK
127.0.0.3 适用于连接 OOOK@%
--quick 用于省内存
--compress 用于压缩传输
--single-transaction 防止锁库
# 输入:
var_dump(basename("xf/中文qq.zip"));
# 输出:
string(12) "qq.zip"
# 期待的输出为:
string(12) "中文qq.zip"
可以发现中文部分丢失,使用下面的方法解决,或者手动拆分字符串
解决办法:
setlocale(LC_ALL, 'zh_CN.UTF-8');
var_dump(basename("xf/中文qq.zip"));
// ❌ 默认情况下,中文可能丢失
setlocale(LC_ALL, 'C'); // 或 'POSIX'
var_dump(basename('/path/文件.pdf')); // Linux下可能输出乱码 string(4) ".pdf"
// ✅ 设置正确的 locale 后
setlocale(LC_ALL, 'zh_CN.UTF-8');
var_dump(basename('/path/文件.pdf')); // 正确输出:string(10) "文件.pdf"
public function curls()
{
cli_set_process_title(__FILE__ . ':curls');
$file_mtime = $this->file_mtime();
$st = time();
error_reporting(E_ALL);
ini_set('swoole.display_errors', 'On');
\Swoole\Coroutine::set(['hook_flags' => SWOOLE_HOOK_ALL]);
\Swoole\Coroutine\run(function () use ($st, $file_mtime) {
$channel = new \Swoole\Coroutine\Channel(1);
$exit = null;
\Swoole\Coroutine::create(function () use ($channel, $st, $file_mtime, &$exit) {
$redis = \services\iRedis::getInstance();
while (true) {
$task = $redis->blPop('curl_queue', 5);
if (!empty($task)) $channel->push($task[1]);
if ($file_mtime != $this->file_mtime()) break;
if (time() - $st > 3600) break;
}
$exit = true;
});
for ($i = 0; $i < 5; $i++) {
\Swoole\Coroutine::create(function () use ($channel, &$exit) {
while (true) {
$task = $channel->pop(5);
if (!empty($task)) {
$json = json_decode($task, true);
if ($json) {
$method = $json['method'];
$uri = $json['uri'];
$headers = $json['headers'] ?? [];
$body = $json['body'] ?? null;
$result = \services\Tools::curl($method, $uri, $body, $headers);
}
}
if ($exit && $channel->isEmpty()) break;
}
});
}
});
}
openssl 实现:
$result = openssl_decrypt(base64_decode($data),
"AES-128-CBC",
base64_decode($key),
OPENSSL_RAW_DATA,
base64_decode($iv));
var_dump($result);
mcrypt 实现
$module = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
//用密钥key、初始化向量初始化
mcrypt_generic_init($module, base64_decode($key), base64_decode($iv));
//**执行解密**(得到带有PKCS#7填充的半原文,所以要去除填充)
$result = mdecrypt_generic($module, base64_decode($data));
//清理工作与关闭解密
mcrypt_generic_deinit($module);
mcrypt_module_close($module);
//去除填充
$lastByte = substr($result, -1);
$result = substr($result, 0, strlen($result) - ord($lastByte));
var_dump($result);
class Locker
{
private static array $lockers = [];
/**
* 获取锁
* @param string $key 锁的唯一标识
* @param int $timeout 超时时间(秒),0表示无限等待
* @return bool 是否获取到锁
*/
public static function wait(string $key, int $timeout = 0): bool
{
$file = sys_get_temp_dir() . "/.lock_" . md5($key) . ".tmp";
$start_time = time();
while (true) {
// 检查是否超时
if ($timeout > 0 && (time() - $start_time) >= $timeout) {
return false;
}
// 尝试打开文件
$fp = @fopen($file, "c+");
if (!$fp) {
usleep(10000); // 等待10毫秒
continue;
}
// 尝试获取锁
if (flock($fp, LOCK_EX | LOCK_NB)) {
// 获取锁成功
self::$lockers[$key] = $fp;
return true;
} else {
// 获取锁失败,关闭文件句柄
fclose($fp);
usleep(10000); // 等待10毫秒后重试
}
}
}
/**
* 释放锁
* @param string $key 锁的唯一标识
* @return bool 是否成功释放
*/
public static function release(string $key): bool
{
if (!isset(self::$lockers[$key])) {
return false;
}
$fp = self::$lockers[$key];
if (is_resource($fp)) {
flock($fp, LOCK_UN); // 释放文件锁
fclose($fp); // 关闭文件句柄
}
unset(self::$lockers[$key]);
return true;
}
/**
* 检查是否持有某个锁
* @param string $key 锁的唯一标识
* @return bool 是否持有锁
*/
public static function isLocked(string $key): bool
{
return isset(self::$lockers[$key]) && is_resource(self::$lockers[$key]);
}
/**
* 析构时释放所有锁
*/
public function __destruct()
{
foreach (array_keys(self::$lockers) as $key) {
self::release($key);
}
}
}
使用:
if (!Locker::wait(md5("key"), 3)) {
recordlog("3秒内获取不到锁返回提示 请勿重复请求 ");
# 3秒内获取不到锁返回提示
exit_json(0, '请勿重复请求');
}
已email字段为例,改成latin1_bin :
alter table resume
modify email varchar(255) collate latin1_bin not null comment ’email’;
或者取左边一部分来做索引
CREATE INDEX fff ON resume(email (10));