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 协议》,转载必须注明作者和本文链接
遇强则强,太强另说
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
讨论数量: 1
location ~* \.(jpg|jpeg|png|gif)$ {
  expires 30d; //30天后缓存过期
  add_header Cache-Control "public";
}

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

1年前 评论

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