Почему метод Laravel getMimeType() идентифицирует файл как application/octet-stream, когда файл имеет атрибут типа audio/mpeg?

Я пытаюсь загрузить файл MP3 в приложение Laravel и столкнулся с проблемой, когда, хотя атрибут файла имеет значение «аудио/mpeg», он загружается как «приложение/октет-поток» (.bin) файл. Когда я пытаюсь умереть и вывести файл на серверный код с помощью:

dd($request->file('file'));

Я получил:

UploadedFile {#187 ▼
  -test: false
  -originalName: "CUS12309821-20-AUG-2016-13-48-13.mp3"
  -mimeType: "audio/mpeg"
  -size: 47000471
  -error: 0
  path: "/private/var/folders/c7/6ws0lxy95dd_lhz1k067_zkc0000gn/T"
  filename: "phpyZCsbU"
  basename: "phpyZCsbU"
  pathname: "/private/var/folders/c7/6ws0lxy95dd_lhz1k067_zkc0000gn/T/phpyZCsbU"
  extension: ""
  realPath: "/private/var/folders/c7/6ws0lxy95dd_lhz1k067_zkc0000gn/T/phpyZCsbU"
  aTime: 2016-09-20 12:56:00
  mTime: 2016-09-20 12:56:00
  cTime: 2016-09-20 12:56:00
  inode: 4565593
  size: 47000471
  perms: 0100600
  owner: 501
  group: 20
  type: "file"
  writable: true
  readable: true
  executable: false
  file: true
  dir: false
  link: false
}

Посмотрите, как, когда я использую этот метод, он действительно говорит, что атрибут файла для mimeType является правильным форматом «аудио/мпег». Однако, когда я вызываю метод getMimeType() для файла после его загрузки, я получаю:

"application/octet-stream"

Вот код маршрутизируемого метода:

/**
 * Store a newly created resource in storage.
 *
 * @param  \Illuminate\Http\Request  $request
 * @return \Illuminate\Http\Response
 */
public function store(Request $request)
{
    $file = $request->all();

    $filePath = Storage::putFile('file', $request->file('files'));

    dd($request->file('file')->getMimeType());

    $file['path'] = Storage::url($filePath);
    $file['size'] = Storage::size($filePath);
    $file['type'] = $request->file('file')->getMimeType();

    return $file;
}

Эта проблема, по-видимому, уникальна тем, что я использую инфраструктуру Laravel, тогда как другие с этой проблемой используют ванильный PHP. Кроме того, файл excel, который другие могли сообщить нам как приложение/октетный поток, а не файл excel. Наконец, я полагаю, что это может быть проблема с методом предположения (), который вызывается методом getMethodType (). Кто-то с большим опытом работы с Laravel, вероятно, мог бы это подтвердить.


person Kirkland    schedule 20.09.2016    source источник
comment
Возможный дубликат Почему я получение MIME-типа файла .csv как application/octet-stream?   -  person L00_Cyph3r    schedule 20.09.2016
comment
Я не согласен. Я использую фреймворк Laravel, а он использует ванильный PHP. Кроме того, его файл excel мог сообщить о себе как о приложении/октетном потоке вместо файла excel. Наконец, я полагаю, что это может быть проблема с методом предположения (), который вызывается методом getMethodType (). Кто-то с большим опытом работы с Laravel, вероятно, мог бы это подтвердить.   -  person Kirkland    schedule 20.09.2016
comment
Я только что доказал, что это проблема Laravel, а не проблема механизма загрузки PHP, создав ванильную форму загрузки PHP и загрузив файл. Результат var_dump($_FILES): array(1) { [fileToUpload]=> array(5) { [name]=> string(15) CUS12309821-20-AUG-2016-13-48-13.mp3 [ type]=›string(10) audio/mpeg [tmp_name]=›string(66) /private/var/folders/c7/6ws0lxy95dd_lhz1k067_zkc0000gn/T/phpf6cwMf [error]=› int(0) [size]=› int( 40340291) } }   -  person Kirkland    schedule 20.09.2016
comment
@Kirkland: у меня похожая проблема, и мой вопрос здесь: stackoverflow.com/questions/65868417/. Как вы наконец решили свою проблему? Конечно, я мог бы использовать php-функции вместо валидатора Laravel, но это совсем не элегантно. Я скорее хотел бы видеть, что Laravel делает это правильно и не ошибается. Что вы думаете?   -  person Steevie    schedule 24.01.2021


Ответы (2)


Объект UploadedFile в конечном итоге расширяется от Symfony\Component\HttpFoundation\File\UploadedFile, который получает/устанавливает mimeType от The type of the file as provided by PHP.

Чтобы получить доступ к этому mimeType, вам нужно будет вызвать $file->getClientMimeType()

Однако в докблоке Symfony для функции он предлагает:

Тип mime клиента извлекается из запроса, из которого был загружен файл, поэтому его не следует рассматривать как безопасное значение.

Для доверенного типа mime вместо этого используйте getMimeType() (который угадывает тип mime на основе содержимого файла).

В вашем случае, однако, $file->getMimeType(), которому следует доверять, и он угадывает тип mime из содержимого, однако он возвращает что-то, как если бы он не мог определить тип mime, будучи приложением/октетным потоком

Дополнительная информация

Чтобы помочь вам решить. В основном getClientMimeType() будет возвращать тип mime, установленный браузером.

Вызов getMimeType угадывает тип пантомимы, используя два разных метода, которые я вижу:

  1. Используя технику двоичного типа mime, просматривая вывод следующей команды file -b --mime %s 2>/dev/null, если она поддерживается.

  2. Второй метод заключается в использовании команды finfo_open, если она существует внутри php.

Если в вашей системе есть и 1., и 2., насколько я вижу, 2. будет иметь преимущество, а 1. будет резервным.

Лично я предпочел бы результаты getMimeType() из соображений безопасности. Тем не менее, было бы еще один интересный вопрос: насколько надежно определение типа пантомимы браузера и какие методы используются :-)

Обновленный пример

Я включаю пример для вас.

Для меня, проверяющего DropboxInstalled.dmg, вот мои результаты:

  1. использование file -b --mime DropboxInstaller.dmg из командной строки (терминала) возвращает application/octet-stream

  2. используя функциональность finfo_open

$finfo = new \finfo(FILEINFO_MIME_TYPE);
echo $finfo->file('./DropboxInstaller.dmg');

возвращает application/x-iso9660-image

person Leon Vismer    schedule 20.09.2016
comment
Очень интересно! Я все еще обдумываю то, что вы упомянули, но я думаю, что в конечном итоге это будет ответ. Я хотел бы спросить, что вы думаете о рисках, связанных с использованием метода getClientMimeType(). Пока расширение файла и MIME-тип совпадают, и он помечен как неисполняемый, какие риски, по вашему мнению, могут существовать? - person Kirkland; 20.09.2016
comment
Я скорее добавлю свой ответ вместо неформатированного комментария. - person Leon Vismer; 20.09.2016
comment
Если это должен быть собственный новый вопрос, дайте мне знать. Что вы думаете об использовании тегов ID3 ​​в качестве альтернативы среднего уровня между этими двумя? - person Kirkland; 22.09.2016
comment
Вы могли бы получить больше пробега, если бы это был его собственный вопрос. Вы не упомянули свою платформу, и если вам удалось увидеть, какой метод угадывания будет использоваться по умолчанию для вашей платформы. Вы можете заглянуть внутрь vendor/symfony/http-foundation/File/MimeType/MimeTypeGuesser.php и добавить несколько отладочных сообщений. Я думаю, что догадка будет точной. Не уверен в вашем конкретном случае использования, но если вы хотите дважды проверить конкретно mp3, если угадывающий возвращает поток октетов для файла и у него есть данные ID3, то есть довольно большая вероятность, что это mp3. - person Leon Vismer; 23.09.2016
comment
для меня это бросает FileNotFoundException внутри метода предположения в экземпляре MimeTypeGuesser, есть идеи? Кроме того, я понимаю ваш пост, но все еще не имеет для меня смысла, именно laravel должен решить проблему определения типа mimetype, а не автоматически устанавливать его в поток октетов (например, вызывая метод getMimeType(), когда создание экземпляра объекта UploadedFile) - person Fabiotk; 04.08.2018
comment
Я сталкиваюсь с аналогичными проблемами при загрузке файлов Adobe Illustrator (.ai). Файлы AI распознаются как PDF, поэтому тип mime клиента = application/postscript, но тип mime возвращает application/pdf. Это не только это, но и использование хранилища Laravel также сохраняет файл в формате .pdf вместо исходного .ai. Мое единственное решение сейчас - перезаписать расширение. Это действительно головная боль, когда он автоматически меняет расширение файла в зависимости от типа mime. - person Bill L.; 24.04.2020

У меня была эта проблема с Laravel 5.4. Я исправил, установив post_max_size и upload_max_filesize в моем php.ini более высокое значение.

После этого мне фактически пришлось выполнить жесткий перезапуск OSX, прежде чем он действительно правильно отразился в приложении.

person james2doyle    schedule 10.03.2017
comment
Вам, конечно, не нужно было делать жесткий перезапуск, вы просто не перезапустили apache (или вы пытались перезапустить, но перезапустили стоковый). - person Kyslik; 27.06.2017
comment
@Kyslik Я не использую apache. Я использую Nginx. Я перезапустил службу PHP и Nginx. Это все еще не применялось. Отсюда мой комментарий о явном жестком перезапуске. - person james2doyle; 27.06.2017
comment
Вы имели в виду php-fpm? Я настроил множество серверов (и сам работаю с/на OS X), и я никогда не слышал о необходимости полной перезагрузки, потому что служба не принимает новую конфигурацию. Конечно, это странно. Теперь все работает, так что это не имеет значения, я думаю. В любом случае ваш ответ не отвечает на вопрос ОП. - person Kyslik; 28.06.2017