PHP[快问快答系列]
怎么解决防盗链?
Referrer白名单:设置Nginx只允许来自指定域名的请求,其他来源的请求将被拒绝。
location ~* \.(jpg|jpeg|png|gif)$ { valid_referers none blocked example.com; if ($invalid_referer) { return 403; } }
Referer黑名单:设置Nginx只允许来自指定域名以外的请求,其他来源的请求将被拒绝。
location ~* \.(jpg|jpeg|png|gif)$ { valid_referers none blocked; if ($invalid_referer) { return 403; } if ($http_referer ~* (badsite1.com|badsite2.com)) { return 403; } }
设置图片的时效性:可以通过Nginx的add_header指令设置图片的过期时间,从而防止其他网站永久使用你的图片。
location ~* \.(jpg|jpeg|png|gif)$ { expires 30d; //30天后缓存过期 add_header Cache-Control "public"; }
Rewrite防盗链:使用Nginx的rewrite模块,将请求的URL中的来源进行判断,如果来源不正确,就跳转到错误页面。
location /images/ { if ($http_referer !~ "^https?://(www\.)?example\.com") { rewrite ^/images/(.*)$ /error.png last; } }
PHP的垃圾回收机制?
PHP的垃圾回收机制主要是基于引用计数(reference counting)算法实现的。每当有一个变量引用一个对象时,对象的引用计数就会加一。每当一个变量不再引用该对象时,对象的引用计数就会减一。当对象的引用计数降为零时,对象就会被标记为垃圾,等待垃圾收集器的回收。
PHP 7.3之后,引入了一种新的垃圾收集器——“Zend GC”,它是一种全局垃圾回收机制,可以更快地检测和回收垃圾。
如何获取客户端真实IP?
if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$client_ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
} elseif (!empty($_SERVER['HTTP_CLIENT_IP'])) {
$client_ip = $_SERVER['HTTP_CLIENT_IP'];
} else {
$client_ip = $_SERVER['REMOTE_ADDR'];
}
需要注意的是,$_SERVER['HTTP_X_FORWARDED_FOR']
和 $_SERVER['HTTP_CLIENT_IP']
的值可能是一个逗号分隔的 IP 地址列表,其中第一个 IP 地址是客户端的真实 IP 地址。
如何防范CSRF攻击
使用 CSRF Token
#client <form action="submit.php" method="post"> <input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token']; ?>"> <!-- 其他表单元素 --> <button type="submit">提交</button> </form> #server session_start(); if ($_POST['csrf_token'] !== $_SESSION['csrf_token']) { die('CSRF 验证失败'); }
检查 Referer
if (strpos($_SERVER['HTTP_REFERER'], 'example.com') === false) { die('CSRF 验证失败'); }
添加验证码
PHP如何防范XSS攻击
对用户输入进行过滤和转义
$raw_input = '<script>alert("恶意代码");</script>'; $filtered_input = htmlspecialchars($raw_input, ENT_QUOTES, 'UTF-8'); echo $filtered_input; //<script>alert("恶意代码");</script>
htmlspecialchars()
函数只能防止 HTML 注入,对于其他类型的注入攻击(例如 JavaScript、CSS、SQL 注入等),需要使用相应的转义函数或过滤器。使用 Content Security Policy
header("Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'");
对输出内容进行过滤和转义
在输出内容之前,使用 htmlspecialchars() 函数对内容进行 HTML 转义。
如果两个文件大小都超过了 1G,而 PHP 最大允许的内存只有 255M,那么不能将整个文件读入内存中进行比较。一种可行的做法是对两个文件进行分块处理,将每个块读入内存中进行比较,以此找到相同的行。
对两个文件进行分块处理,将每个块读入内存中进行比较,以此找到相同的行
<?php
// 定义块大小
define('BLOCK_SIZE', 1024 * 1024 * 256); // 256M
// 打开文件
$fp1 = fopen('file1.txt', 'r');
$fp2 = fopen('file2.txt', 'r');
$fp3 = fopen('result.txt', 'w');
// 初始化变量
$buffer1 = '';
$buffer2 = '';
$pos1 = 0;
$pos2 = 0;
// 读取文件块并比较
while (!feof($fp1) || !feof($fp2)) {
// 读取文件块
$buffer1 = fread($fp1, BLOCK_SIZE);
$buffer2 = fread($fp2, BLOCK_SIZE);
// 比较文件块
$lines1 = explode("\n", $buffer1);
$lines2 = explode("\n", $buffer2);
$count1 = count($lines1);
$count2 = count($lines2);
// 如果是块的第一行,则修正当前位置
if ($pos1 == 0) {
$pos1 += strlen($lines1[0]) + 1;
}
if ($pos2 == 0) {
$pos2 += strlen($lines2[0]) + 1;
}
// 比较行数据
for ($i = 0; $i < min($count1, $count2); $i++) {
if ($lines1[$i] == $lines2[$i]) {
// 如果行数据相同,则将该行写入新文件
fwrite($fp3, $lines1[$i] . "\n");
}
// 更新位置信息
$pos1 += strlen($lines1[$i]) + 1;
$pos2 += strlen($lines2[$i]) + 1;
}
// 如果文件1比文件2多出一行,需要将最后一行重新拼接到下一个块的开头
if ($count1 > $count2) {
$buffer1 = $lines1[$count2] . "\n";
$pos1 -= strlen($buffer1);
}
// 如果文件2比文件1多出一行,需要将最后一行重新拼接到下一个块的开头
if ($count2 > $count1) {
$buffer2 = $lines2[$count1] . "\n";
$pos2 -= strlen($buffer2);
}
// 定位文件指针
fseek($fp1, $pos1);
fseek($fp2, $pos2);
}
// 关闭文件句柄
fclose($fp1);
fclose($fp2);
fclose($fp3);
10g 文件,用 php 查看它的行数
处理大文件时,使用 PHP 的内存占用可能会非常高,甚至可能导致脚本执行时间过长或崩溃。为了避免这种情况,可以使用 PHP 的 SplFileObject 类,它支持迭代器模式,可以逐行读取文件,不会一次性将整个文件读入内存。
<?php
// 打开文件
$file = new SplFileObject('large_file.txt');
// 初始化行数为 0
$lineCount = 0;
// 迭代文件中的每一行
foreach ($file as $line) {
// 每读取一行,行数加一
$lineCount++;
}
// 输出行数
echo "The file has $lineCount lines.\n";
?>
php7 性能为什么提升这么高?
PHP7 的性能提升主要来自于引擎优化和代码优化。引入 JIT 编译器和改进垃圾回收机制,使得 PHP7 可以更快地执行代码。在标准库和函数方面进行优化,也有助于提高 PHP7 的执行效率。
有一个 1G 大小的一个文件,里面每一行是一个词,词的大小不超过 16 个字节,内存限制大小是 1M。返回频数最高的 100 个词
可以使用 PHP 的 SplFileObject 类进行逐行读取,并将词频统计到一个数组中。
<?php
$file = new SplFileObject('large_file.txt'); // 打开文件
$wordCount = array(); // 初始化词频统计数组
while (!$file->eof()) { // 逐行读取文件内容
$line = $file->fgets(); // 读取一行内容
$words = explode(' ', trim($line)); // 将一行内容按空格分割成词
foreach ($words as $word) {
if (isset($wordCount[$word])) { // 如果词已经存在,增加频率
$wordCount[$word]++;
} else { // 否则,添加新的词并初始化频率为 1
$wordCount[$word] = 1;
}
}
}
arsort($wordCount); // 对词频统计数组按值(频率)进行降序排序
$i = 0;
foreach ($wordCount as $word => $count) { // 输出频率最高的 100 个词
echo "$word: $count\n";
$i++;
if ($i >= 100) break;
}
?>
OOP面向对象是什么?
怎么防止重复下单?
- 前端校验:在用户点击“提交订单”按钮后,可以禁用该按钮,避免用户多次点击。
- 后端校验:hash加密 用户ID+商品ID+数量 作为依据,存在redis,设置过期时间,下单之前查询是否有重复的key
- token:前端在提交订单时,需要先向后端发起请求,获取一个唯一的 token 或者 session ID,然后将该 token 或者 session ID 一起提交给后端。后端在处理订单请求时,会先根据该 token 或者 session ID 判断是否是重复提交的订单。如果是网页端还可以避免crsf攻击
如果微信支付回调出现故障,怎么解决?
本作品采用《CC 协议》,转载必须注明作者和本文链接
nginx 缓存设置后,但是当前页很多图片,导致部分图片无法加载怎么解决