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;
    //&lt;script&gt;alert(&quot;恶意代码&quot;);&lt;/script&gt;

    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 协议》,转载必须注明作者和本文链接
遇强则强,太强另说
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 1
location ~* \.(jpg|jpeg|png|gif)$ {
  expires 30d; //30天后缓存过期
  add_header Cache-Control "public";
}

nginx 缓存设置后,但是当前页很多图片,导致部分图片无法加载怎么解决

1年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!