当前位置: 首页 > 面试题库 >

使用PHP服务文件的最快方法

高夜洛
2023-03-14
问题内容

我试图将一个函数接收一个文件路径,确定它是什么,设置适当的标头,并像Apache一样提供服务。

我这样做的原因是因为在提供文件之前,我需要使用PHP处理有关请求的某些信息。

速度至关重要

virtual()不是一个选择

必须在用户无法控制Web服务器(Apache / nginx等)的共享托管环境中工作

到目前为止,这是我得到的:

File::output($path);

<?php
class File {
static function output($path) {
    // Check if the file exists
    if(!File::exists($path)) {
        header('HTTP/1.0 404 Not Found');
        exit();
    }

    // Set the content-type header
    header('Content-Type: '.File::mimeType($path));

    // Handle caching
    $fileModificationTime = gmdate('D, d M Y H:i:s', File::modificationTime($path)).' GMT';
    $headers = getallheaders();
    if(isset($headers['If-Modified-Since']) && $headers['If-Modified-Since'] == $fileModificationTime) {
        header('HTTP/1.1 304 Not Modified');
        exit();
    }
    header('Last-Modified: '.$fileModificationTime);

    // Read the file
    readfile($path);

    exit();
}

static function mimeType($path) {
    preg_match("|\.([a-z0-9]{2,4})$|i", $path, $fileSuffix);

    switch(strtolower($fileSuffix[1])) {
        case 'js' :
            return 'application/x-javascript';
        case 'json' :
            return 'application/json';
        case 'jpg' :
        case 'jpeg' :
        case 'jpe' :
            return 'image/jpg';
        case 'png' :
        case 'gif' :
        case 'bmp' :
        case 'tiff' :
            return 'image/'.strtolower($fileSuffix[1]);
        case 'css' :
            return 'text/css';
        case 'xml' :
            return 'application/xml';
        case 'doc' :
        case 'docx' :
            return 'application/msword';
        case 'xls' :
        case 'xlt' :
        case 'xlm' :
        case 'xld' :
        case 'xla' :
        case 'xlc' :
        case 'xlw' :
        case 'xll' :
            return 'application/vnd.ms-excel';
        case 'ppt' :
        case 'pps' :
            return 'application/vnd.ms-powerpoint';
        case 'rtf' :
            return 'application/rtf';
        case 'pdf' :
            return 'application/pdf';
        case 'html' :
        case 'htm' :
        case 'php' :
            return 'text/html';
        case 'txt' :
            return 'text/plain';
        case 'mpeg' :
        case 'mpg' :
        case 'mpe' :
            return 'video/mpeg';
        case 'mp3' :
            return 'audio/mpeg3';
        case 'wav' :
            return 'audio/wav';
        case 'aiff' :
        case 'aif' :
            return 'audio/aiff';
        case 'avi' :
            return 'video/msvideo';
        case 'wmv' :
            return 'video/x-ms-wmv';
        case 'mov' :
            return 'video/quicktime';
        case 'zip' :
            return 'application/zip';
        case 'tar' :
            return 'application/x-tar';
        case 'swf' :
            return 'application/x-shockwave-flash';
        default :
            if(function_exists('mime_content_type')) {
                $fileSuffix = mime_content_type($path);
            }
            return 'unknown/' . trim($fileSuffix[0], '.');
    }
}
}
?>

问题答案:

我以前的回答是不完整的,没有很好的记录,这里是更新,其中总结了该解决方案以及讨论中其他人员的解决方案。

从最佳解决方案到最坏解决方案的顺序排列,也从需要对Web服务器进行最多控制的解决方案到需要较少控制的解决方案进行排序。拥有一个既快速又可以在任何地方工作的解决方案似乎并不是一个简单的方法。

使用X-SendFile标头

正如其他人所记录的那样,这实际上是最好的方法。其基础是您使用php进行访问控制,然后您自己告诉文件服务器,而不是自己发送文件。

基本的php代码是:

header("X-Sendfile: $file_name");
header("Content-type: application/octet-stream");
header('Content-Disposition: attachment; filename="' . basename($file_name) . '"');

$file_name文件系统上的完整路径在哪里。

该解决方案的主要问题在于,它必须由Web服务器允许,或者默认情况下未安装(apache),默认情况下未激活(lighttpd),或者需要特定的配置(nginx)。

apache

在apache下,如果您使用mod_php,则需要安装一个名为mod_xsendfile的模块,然后对其)进行配置(如果允许,可以在apacheconfig或.htaccess中)

XSendFile on
XSendFilePath /home/www/example.com/htdocs/files/

使用此模块,文件路径可以是绝对路径,也可以是相对于指定路径的路径XSendFilePath

Lighttpd

在配置时,mod_fastcgi支持此功能

"allow-x-send-file" => "enable"

该功能的文档位于lighttpd Wiki上,它们记录了X-LIGHTTPD-send-file标头,但X-Sendfile名称也起作用

Nginx的

在Nginx上,您不能使用X-Sendfile标题,而必须使用自己的标题为的标题X-Accel-Redirect。默认情况下启用它,唯一的真正区别是它的参数应该是URI而不是文件系统。结果是您必须在配置中定义一个标记为内部的位置,以避免客户端找到真实的文件url并直接进入该URL,他们的Wiki对此做了很好的解释。

符号链接和位置标题

您可以使用符号链接并将其重定向到它们,只需在授权用户访问文件并将文件重定向至该文件时,使用随机名称创建指向文件的符号链接即可:

header("Location: " . $url_of_symlink);

显然,当调用创建它们的脚本时或通过cron(如果可以访问,请在计算机上,否则通过某些Webcron服务),您将需要一种修剪它们的方法。

在apache下,您需要能够FollowSymLinks.htaccess或apache配置中启用。

另一个技巧是从php生成apache访问文件,从而允许显式用户IP。在apache下,这意味着使用mod_authz_hostmod_accessAllow from命令。

问题在于,锁定对文件的访问(因为多个用户可能希望同时执行此操作)并非易事,并且可能导致某些用户等待很长时间。而且您仍然需要修剪该文件。

显然,另一个问题是同一IP后面的多个人可能会访问该文件。

当其他一切都失败了

如果您真的没有办法让您的Web服务器来帮助您,则剩下的唯一解决方案是readfile,它可以在当前使用的所有php版本中使用,并且运行良好(但效率不高)。

组合解决方案

好的,如果您希望自己的php代码在任何地方都可以使用,那么真正快速发送文件的最佳方法是在某处有一个可配置的选项,其中说明了如何根据Web服务器激活它的说明以及安装过程中的自动检测脚本。

这与许多软件中完成的工作非常相似

  • 清理网址(mod_rewrite针对Apache)
  • 加密函数(mcryptphp模块)
  • 多字节字符串支持(mbstringphp模块)


 类似资料:
  • 我使用了一种相当丑陋的方法: 正确的方法是什么?

  • 本文向大家介绍PHP使用NuSOAP调用Web服务的方法,包括了PHP使用NuSOAP调用Web服务的方法的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了PHP使用NuSOAP调用Web服务的方法。分享给大家供大家参考。具体如下: Steps: 1. Download nusoap library from internet. 2. Pass parameter list in your

  • 问题内容: 我有多个3 GB的制表符分隔文件。每个文件中有2000万行。所有行都必须独立处理,任何两行之间都没有关系。我的问题是,什么会更快A.使用以下命令逐行阅读: 还是B.将文件分块读取到内存中并进行处理,例如一次250 MB? 处理不是很复杂,我只是在column1到column2的值中抓取值,等等。可能需要将一些列值加在一起。 我在具有30GB内存的Linux机器上使用python 2.7

  • 问题内容: 我做了一个方法,需要一个和一个。它用该字符串作为内容的新文件替换该文件。 这就是我所做的: 但是,它非常缓慢。有时需要一分钟以上。 如何写出包含成千上万个字符的大文件? 问题答案: 确保分配了足够大的缓冲区: 您正在运行哪种操作系统?那也可以有很大的不同。但是,花一 分钟 时间写出一个小于大小的文件听起来像是系统问题。在Linux或其他* ix系统上,您可以使用类似的方法来查看JVM是

  • 在两个Ubuntu web服务器之间传输文件的最快方法是什么?这些服务器彼此是本地的。使用共享驱动器更好还是使用传输协议更好?最好使用PHP来方便两个文件之间的传输。

  • 本文向大家介绍使用 Iisext.vbs 启用Web服务扩展文件的方法,包括了使用 Iisext.vbs 启用Web服务扩展文件的方法的使用技巧和注意事项,需要的朋友参考一下 应用到: Windows Server 2003, Windows Server 2003 R2, Windows Server 2003 with SP1 可使用命令行脚本 iisext.vbs(存储在 systemroo