# 输入:
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"));
# 输入:
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"));
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) {
for ($i = 0; $i < 5; $i++) {
\Swoole\Coroutine::create(function () use ($i, $st, $file_mtime) {
$redis = new Redis();
$redis->connect('10.29.185.7', 6383);
while (true) {
$task = $redis->blPop('curl_queue', 5);
if (!empty($task)) {
[$key, $val] = $task;
$json = json_decode($val, true);
if ($json) {
$method = $json['method'];
$uri = $json['uri'];
$headers = $json['headers'] ?? [];
$body = $json['body'] ?? null;
$ch = curl_init();
if ($method === 'POST') {
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
}
if (count($headers)) {
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
}
curl_setopt($ch, CURLOPT_URL, $uri);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$result = curl_exec($ch);
curl_close($ch);
}
}
if ($file_mtime != $this->file_mtime()) break;
if (time() - $st > 3600) 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, '请勿重复请求');
}
下载:
wget https://openssl.org/source/openssl-1.1.1u.tar.gz tar -xzvf openssl-1.1.1u.tar.gz cd openssl-1.1.1u
编译安装:
./config --prefix=/usr/local/openssl1.1 --openssldir=/usr/local/openssl1.1/ssl
make -j$(nproc)
make install
临时改环境变量:
export PATH=/usr/local/openssl1.1/bin:$PATH
export LD_LIBRARY_PATH=/usr/local/openssl1.1/lib:$LD_LIBRARY_PATH
configure php:
./configure --with-mysqli --with-pdo-mysql --enable-mbstring --enable-fpm --with-gd=/usr --with-curl --with-mcrypt --with-openssl --with-freetype-dir --with-zlib --with-jpeg-dir --with-png-dir --with-xpm-dir --enable-pcntl --with-gmp --enable-zip --enable-bcmath --with-openssl=/usr/local/openssl1.1/ --with-openssl-dir=/usr/local/openssl1.1/
编译安装:(略)
在PHP中,switch语句如果不加break会导致”case穿透”现象。具体表现如下:
当匹配到某个case后,如果没有break语句,代码会继续执行后续所有case中的语句,直到遇到break或switch结束
这种特性有时会被故意利用来实现多个case共享同一段代码的逻辑
示例说明:
switch ($value) {
case 1:
echo "这是1";
// 这里没有break
case 2:
echo "这是2";
break;
case 3:
echo "这是3";
break;
}
当$value=1时,输出会是:
“这是1这是2”
因为匹配到case 1后,没有break阻止,所以继续执行了case 2的代码。
建议:除非有特殊需求,否则每个case后都应该加上break语句以避免意外行为。
+运算符把右边的数组元素附加到左边的数组后面,两个数组中都有的键名,则只用左边数组中的,右边的被忽略。


public static function getIpX(): ?string {
[$ip] = self::getIp();
return $ip;
}
public static function getIp(): array {
$ip0 = $ip = $_SERVER['REMOTE_ADDR'] ?? null;
if (in_array($ip, [
'10.29.185.7', '127.0.0.1', '172.17.0.1', '172.31.242.237', # 可信IP列表
])) {
$ip1 = $_SERVER['HTTP_X_FORWARDED_FOR'] ?? null;
if ($ip1) {
$ip0 = $ip1;
$ip = explode(',', $ip1)[0];
}
}
if (!$ip) {
$ip = $_SERVER['REMOTE_ADDR'] ?? null;
}
return [$ip, $ip0];
}
nginx:
client_max_body_size 1G;
php.ini:
upload_max_filesize = 1G
post_max_size = 1G
$fp = fopen(sprintf("tmp/wk_exam_examination.%d.lock", $userid % 10), "w");
if (!flock($fp, LOCK_EX | LOCK_NB)) {
?>
<style>
#info {
text-align: center;
margin: 50px 0;
}
#info td {
font-size: 36px;
color: seagreen;
}
</style>
<div id='info'></div>
<script>
let sec = 5000
setTimeout(function () {
window.location.reload()
}, sec)
setInterval(function () {
sec -= 100
if (sec >= 0) {
let ok = sec / 1000
document.getElementById('info').innerHTML = `<table style="margin: 0 auto;">
<tr><td style='width: 50%; text-align: right;'>页面排队中...</td>
<td style="width: 2em; text-align: center;">${ok}</td><td>秒后将重试!</td></tr></table>`;
}
}, 100)
</script><?php
die;
}