application/empty при отправке фэйкового файла в ларавел
Пишу http тест загрузки файла и получаю ошибку application/empty при запуске тестов
Мой тест:
public function testUploadContract() {
$user = User::where('id', '=', $this->companyId)->first();
$token = JWTAuth::fromUser($user);
Storage::fake('files');
$file = UploadedFile::fake()->create('file.pdf', 100, ['Content-Type' => 'application/pdf']);
$response = $this->withHeaders(['Authorization' => "Bearer $token", 'Content-Type' => 'application/pdf'])->withoutExceptionHandling()->post('/api/v2/company/documents/upload', ['file' => $file]);
$response->dump();
$response->assertStatus(200);
}
Мой контроллер:
public function upload(Request $request)
{
// dd($request);
if ($request->hasFile('file') == false) {
// dump($request->file());
return response()
->json([
'title' => 'Ошибка',
'message' => 'Не передан файл с реестром!'
], 400, [], JSON_UNESCAPED_UNICODE || JSON_UNESCAPED_SLASHES);
}
$validMimeTypes = [
'application/pdf',
];
$mimeType = mime_content_type($request->file->getPathname());
if (in_array($mimeType, $validMimeTypes) == false) {
return response()
->json([
'title' => 'Ошибка',
'message' => 'Плохой тип файла (' . $mimeType . ')'
], 400, [], JSON_UNESCAPED_UNICODE || JSON_UNESCAPED_SLASHES);
}
$path = Storage::disk('public')->putFile('temp', $request->file('file'));
$url = Storage::disk('public')->url($path);
Log::channel('debug')->debug("FILE IS $url");
return response()
->json([
'title' => 'Файл загружен',
'message' => 'Файл успешно загружен',
'path' => $path,
'preview' => Storage::disk('public')->url($path)
], 200, [], JSON_UNESCAPED_UNICODE || JSON_UNESCAPED_SLASHES);
}
Когда я загружаю файл с клиента как положено, то всё отлично, а в тестах такой вывод:


И последнее что могу приложить сейчас это дамп файла от фэйкера: 
Помогите пожалуйста чем можете, я уже правда не знаю, что с этим поделать(
Ответы (1 шт):
В тестах используется такая конструкция:
UploadedFile::fake()->create('file.pdf', 100, ['Content-Type' => 'application/pdf']);
Посмотрим в сорцах, что делает create():
public function create($name, $kilobytes = 0, $mimeType = null)
{
if (is_string($kilobytes)) {
return $this->createWithContent($name, $kilobytes);
}
return tap(new File($name, tmpfile()), function ($file) use ($kilobytes, $mimeType) {
$file->sizeToReport = $kilobytes * 1024;
$file->mimeTypeToReport = $mimeType;
});
}
Получается, mime-тип проставляется просто как свойство объекта UploadedFile, а содержимое файла - пустое.
Проверяем через тинкер: php artisan tinker:
$file = Illuminate\Http\UploadedFile::fake()->create('file.pdf', 100, ['Content-Type' => 'application/pdf']);
// "Content-Type" => "application/pdf" - передал клиент
$file->getMimeType();
// "" - пусто
$file->getContent();
// "application/x-empty"
mime_content_type($file->getRealPath());
В контроллере mime-тип определяется по содержимому (которое пустое):
mime_content_type($request->file->getPathname());
Поэтому application/x-empty.
Как исправить?
Нужно подготовить реальный pdf-файл, и использовать createWithContent(). При генерации фейковых изображений через image() именно так и делается.
Проверим снова через тинкер:
$file = Illuminate\Http\UploadedFile::fake()->createWithContent('file.pdf', file_get_contents(__DIR__ . '/file_1_k.pdf'));
// "application/pdf"
mime_content_type($file->getRealPath());
Также лучше исправить в контроллере определение типа на $request->file->getMimeType().
Тут также, как и в mime_content_type() происходит реальное определение типа файла по содержимому. Если посмотреть сорцы, используется finfo(), либо вызов оболочки file -b --mime - есть две реализации.