如何在使用file_get_contents从远程服务器获取文件后获取文件的MIME类型

16

我在PHP中从Alfresco读取文件,然后将其输出到浏览器。唯一的问题是文件的MIME类型或扩展名。这是我正在使用的代码:

<?php
ob_start();
require_once("libs/AlfrescoConnect.php");

$nomeFile = rawurldecode($_GET['nomeFile']);    
$urlDownload = $_GET['urlDownload'];
$fileDownloadUrl =
    AlfrescoConnect::$serverPath. $urlDownload .
    "&attach=true&alf_ticket=".AlfrescoConnect::getTiket();
fb($fileDownloadUrl);

$cnt = file_get_contents($fileDownloadUrl);

header("Content-type: Application/octet-stream");
header('Cache-Control: must-revalidate');
header('Content-disposition: attachment; filename=' .$nomeFile);
echo($cnt);
exit();

echo("Impossibile trovare il file");
我从获取的内容中得到了文件名,因为我不知道如何从 Alfresco 中获取文件名。但是我必须想办法猜测 mimetype。如果我在第一字符处运行 echo $cnt,则会有关于它是 PDF 的参考(例如在屏幕上我看到:
%PDF-1.3 %âãÏÓ 2 0 obj << /Length 3 0 R /Filter /CCITTFaxDecode /DecodeParms << /K 0 /Columns 2480 /Rows 3508 >> /Type /XObject /Subtype /Image /Width 2480 /Height 3508 /BitsPerComponent 1 /ColorSpace /DeviceGray >> stream
因此必须有一种方法可以使用函数从中获取 mime type。感谢任何帮助!
编辑。如果有人感兴趣,这里是一个类,您可以使用它来从 mime type 中获取扩展名。 http://www.ustrem.org/en/articles/mime-type-by-extension-en/
7个回答

19

你可以使用finfo::buffer()方法:http://php.net/finfo_buffer

<?php
$finfo = new finfo(FILEINFO_MIME);
echo $finfo->buffer($cnt) . PHP_EOL;

注意: 如果您更喜欢使用过程式函数而不是面向对象的方法,您可以选择使用 finfo_buffer 函数。


1
如果使用了file_get_contents,这似乎是正确的方法。 - Kidades

10

您不必猜测(也称为自动检测)MIME类型。

使用$http_response_header来检索最后一个file_get_contents调用(或任何使用http[s]://包装器的调用)的标头。

$contents = file_get_contents("https://www.example.com/");
$headers = implode("\n", $http_response_header);
if (preg_match_all("/^content-type\s*:\s*(.*)$/mi", $headers, $matches)) {
    $content_type = end($matches[1]);
    echo "Content-Type is '$content_type'\n";
}

4
使用file_get_contents后解析$http_response_header在我的情况下非常不稳定。在某些情况下,当有大量请求时,我无法在头文件中找到'Content-Type'。但它们实际上是存在的。
因此,我使用以下解决方案:
$content = file_get_contents($url);
$fh = fopen('php://memory', 'w+b');
fwrite($fh, $content);

$contentType = mime_content_type($fh);

fclose($fh);

0
把这个放在一个类里面:
/**
 * Given a string ($data) with a file's contents, guess and return the mime type
 *
 * Uses the standard unix program /usr/bin/file to handle the magic (pun intended)
 *
 * @param string $data
 */
public static function get_string_mime_type($data) {
    $file_cmd = '/usr/bin/file --brief --mime-type --no-buffer -';
    return rtrim(self::exec_write_read($file_cmd, $data));
}

/**
 * Executes $cmd, writes to $cmd's stdin, then returns what $cmd wrote to stdout
 */
private static function exec_write_read($cmd, $write, $log_errors = false) {
    $descriptorspec = array(
        0 => array("pipe", "r"),  // stdin is a pipe that $cmd will read from
        1 => array("pipe", "w"),  // stdout is a pipe that $cmd will write to
        2 => array("pipe", "w"),  // stderr is a pipe that $cmd will write to
    );

    $process = proc_open($cmd, $descriptorspec, $pipes);
    if (is_resource($process)) {
        // $pipes now looks like this:
        // 0 => writeable handle connected to child stdin
        // 1 => readable handle connected to child stdout
        // 2 => readable handle connected to child stderr

        fwrite($pipes[0], $write);
        fclose($pipes[0]);

        $output = stream_get_contents($pipes[1]);
        fclose($pipes[1]);

        if( $log_errors ){
            error_log(stream_get_contents($pipes[2]));
        }
        fclose($pipes[2]);

        // It is important that you close any pipes before calling
        // proc_close in order to avoid a deadlock
        $exit_code = proc_close($process);

        return $output;
    }
    else {
        throw new Exception("Couldn't open $cmd");
    }
}

-1
这是Drupal中filefield_sources模块的cURL实现。它可能在任何地方都能工作:
<?php
  // Inspect the remote image
  // Check the headers to make sure it exists and is within the allowed size.
  $ch = curl_init();
  curl_setopt($ch, CURLOPT_URL, $url);
  curl_setopt($ch, CURLOPT_HEADER, TRUE);
  curl_setopt($ch, CURLOPT_NOBODY, TRUE);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
  curl_setopt($ch, CURLOPT_HEADERFUNCTION, '_filefield_source_remote_parse_header');
  // Causes a warning if PHP safe mode is on.
  @curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
  curl_exec($ch);
  $info = curl_getinfo($ch);
  curl_close($ch);

/**
 * Parse cURL header and record the filename specified in Content-Disposition.
 */
function _filefield_source_remote_parse_header(&$ch, $header) {
  if (preg_match('/Content-Disposition:.*?filename="(.+?)"/', $header, $matches)) {
    // Content-Disposition: attachment; filename="FILE NAME HERE"
    _filefield_source_remote_filename($matches[1]);
  }
  elseif (preg_match('/Content-Disposition:.*?filename=([^; ]+)/', $header, $matches)) {
    // Content-Disposition: attachment; filename=file.ext
    _filefield_source_remote_filename($matches[1]);
  }

  // This is required by cURL.
  return strlen($header);
}

/**
 * Get/set the remote file name in a static variable.
 */
function _filefield_source_remote_filename($curl_filename = NULL) {
  static $filename = NULL;
  if (isset($curl_filename)) {
    $filename = $curl_filename;
  }
  return $filename;
}

 ?>

获取MIME类型:
<?php
echo $info['content_type'];
?>

代码在这里:http://drupal.org/project/filefield_sources

-1

那假设远程服务器发送了正确的MIME类型。但它也可能对所有内容使用application/octet-stream。 - Marc B
在这种情况下它可以工作!这是我添加的代码:$ch = curl_init($fileDownloadUrl); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_exec($ch); $mime = curl_getinfo($ch, CURLINFO_CONTENT_TYPE); - Nicola Peluchetti
1
HTTP响应中的MIME类型可能不正确,而mime_content_type()是可信的,并且并没有像你所说的那样被弃用。 - Patrick Allaert

-3

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接