Я принял решение, которое мне кажется лучшим. Я должен признаться, что основной причиной использования функции getimagesize () было получение MIME-типа файла (чтобы убедиться, что это изображение). Получение размера является дополнительным бонусом, но я мог бы так же легко сформулировать вопрос о функции exif_imagetype () . Проблема была бы та же, потому что обе функции принимают только файл name ; не содержимое файла.
Итак, в основном я посмотрел исходный код PHP и увидел, как exif_imagetype () читает информацию MIME. Оказывается, он читает только первые 12 байтов файла. Я повторил его функциональность так:
function GetConstMimeArray()
{
// MIME type markers (taken from PHP sourcecode consts in \ext\standard\image.c starting at line 39).
return array
(
'gif' => array(ord('G'), ord('I'), ord('F')),
'psd' => array(ord('8'), ord('B'), ord('P'), ord('S')),
'bmp' => array(ord('B'), ord('M')),
'swf' => array(ord('F'), ord('W'), ord('S')),
'swc' => array(ord('C'), ord('W'), ord('S')),
'jpg' => array(0xff, 0xd8, 0xff),
'png' => array(0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a),
'tif_ii' => array(ord('I'), ord('I'), 0x2a, 0x00),
'tif_mm' => array(ord('M'), ord('M'), 0x00, 0x2a),
'jpc' => array(0xff, 0x4f, 0xff),
'jp2' => array(0x00, 0x00, 0x00, 0x0c, 0x6a, 0x50, 0x20, 0x20, 0x0d, 0x0a, 0x87, 0x0a),
'iff' => array(ord('F'), ord('O'), ord('R'), ord('M')),
'ico' => array(0x00, 0x00, 0x01, 0x00)
);
}
И
// Get an array of known MIME headers.
$MimeTypeConsts = GetConstMimeArray();
// Get first 12 bytes of file from stream to do a MIME check.
$File = file_get_contents('php://input', null, null, 0, 12);
if(strlen($File) < 12)
return;
// Scan first 12 bytes of file for known MIME headers.
$MatchedMime = '';
foreach($MimeTypeConsts as $Type => $Bytes)
{
$NumMatching = 0;
$NumBytes = count($Bytes);
for($i = 0; $i < $NumBytes; $i++)
{
if(ord($File[$i]) == $Bytes[$i])
$NumMatching++;
else
break;
}
if($NumMatching == $NumBytes)
{
$MatchedMime = $Type;
break;
}
}
// Check if the file does NOT have one of the known MIME types.
if(strlen($MatchedMime) <= 0)
return;
// If we fix up TIF_TT and TIF_MM, you can use $MatchedMime in lieu
// of the extension on the file name.
if($MatchedMime == 'tif_ii' || $MatchedMime == 'tif_mm')
$MatchedMime = 'tif';
// What's the max size allowed to upload?
$MaxSize = min(ReturnBytes(ini_get('post_max_size')), MAX_UPLOAD_SIZE);
// Get full file.
$File = file_get_contents('php://input', null, null, 0, $MaxSize + 8);
// Get file size.
$Size = strlen($File);
if($Size > $MaxSize)
return;
// Get hash of the file contents.
$Hash = hash('SHA1', $File, true);
file_put_contents(UPLOADS_DIR.'/'.bin2hex($Hash).'.'.$MatchedMime, $File);
Файл теперь будет сохранен в UPLOADS_DIR с использованием хеша в качестве имени и типа MIME в качестве его расширения. (Независимо от того, какое расширение было изначально в имени файла, оно игнорируется и не используется.)