9

I'm reading a file in PHP from Alfresco and then outputting it to the browser. The only problem is the mime type or the extension of the file. This is the code I'm using:

<?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");

I receive the name of the file from the get because, I don't know how to get the name from alfresco. But I have to guess the mimetype somehow. If I echo $cnt in the first characters, there are references to the fact that it is a PDF (for example on screen I see

%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

So there must be a way to get the mime type from it with a function.

Any help is appreciated!

Edit. If anyone is interested here is a class that you can use to get the extension from the mime type. http://www.ustrem.org/en/articles/mime-type-by-extension-en/

Martin Prikryl
  • 147,050
  • 42
  • 335
  • 704
Nicola Peluchetti
  • 72,169
  • 29
  • 129
  • 186

7 Answers7

11

You can use the finfo::buffer() method: http://php.net/finfo_buffer.

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

NOTE: You could optionally use the finfo_buffer procedural function if that suites you better than using the object-oriented methodology.

helvete
  • 1,416
  • 5
  • 26
  • 26
Wil Moore III
  • 6,427
  • 3
  • 31
  • 45
6

You do not have to guess (aka autodetect) the MIME type.

Use $http_response_header to retrieve headers of the last file_get_contents call (or any call with http[s]:// wrapper).

$contents = file_get_contents("https://www.example.com/");
$pattern = "/^content-type\s*:\s*(.*)$/i";
if (($header = preg_grep($pattern, $http_response_header)) &&
    (preg_match($pattern, array_shift(array_values($header)), $match) !== false))
{
    $content_type = $match[1];
    echo "Content-Type is '$content_type'\n";
}
Martin Prikryl
  • 147,050
  • 42
  • 335
  • 704
2

Parsing $http_response_header after file_get_contents is very unstable for me. In some cases, with very large number of requests one of another, I can't find 'Content-Type' in headers. But they were there.

So, I use such solution:

$content = file_get_contents($url);
$fh = fopen('php://memory', 'w+b');
fwrite($fh, $content);

$contentType = mime_content_type($fh);

fclose($fh);
toxxxa
  • 121
  • 3
0

Put this in a class:

/**
 * 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");
    }
}
Greg
  • 9,849
  • 5
  • 26
  • 33
-1

Use cURL instead of file_get_contents, then you can see the response header, which will hopefully have the mime type.

Or you could try using this http://www.php.net/manual/en/ref.fileinfo.php or this deprecated function http://php.net/manual/en/function.mime-content-type.php

profitphp
  • 7,689
  • 2
  • 24
  • 21
  • I tried all of them and it didn't work. Itried fileinfo e mime_content_type and it doesn't work (it outputs nothing). I tried curl as seen here (http://stackoverflow.com/questions/2610713/get-mime-type-of-external-file-using-curl-and-php) and it doesn't work – Nicola Peluchetti Jan 12 '11 at 17:19
  • Sorry, i had an error when trying with curl and now it works!!! Thanx for your answer, it made me think again on what i already tried and i found the error – Nicola Peluchetti Jan 12 '11 at 17:23
  • What do you mean it didn't work? If you can see the mime type with liveHTTP headers when getting it in the browser, you can certainly see the same response header if using cURL. – profitphp Jan 12 '11 at 17:23
  • That presumes the remote server is sending the correct mime type, though. It could just use application/octet-stream for everything. – Marc B Jan 12 '11 at 17:37
  • In this case it works! this is the code i added: $ch = curl_init($fileDownloadUrl); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_exec($ch); $mime = curl_getinfo($ch, CURLINFO_CONTENT_TYPE); – Nicola Peluchetti Jan 12 '11 at 17:42
  • 1
    Mime type in HTTP response may be incorrect, while mime_content_type() can be trusted and is NOT deprecated as you say. – Patrick Allaert Nov 19 '19 at 15:42
-1

Here is a curl implementation from the filefield_sources module in Drupal. It can probably work anywhere:

<?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;
}

 ?>

To get the mime:

<?php
echo $info['content_type'];
?>

Code is here: http://drupal.org/project/filefield_sources

Joe Hyde
  • 959
  • 7
  • 17
-2

BE CAREFULL ! NOT ONLY CHECK the mimetype, but check it for malicious code !!!!!!!!!

details: PHP: How to get mimeType of a image with file_get_contents

Community
  • 1
  • 1
T.Todua
  • 44,747
  • 17
  • 195
  • 185