How to get the mime type of a file after using file_get_contents from a remote server
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 fr开发者_如何学Pythonom 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/
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.
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/");
$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";
}
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);
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");
}
}
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
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
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
精彩评论