Обновление
Похоже, это каким-то образом связано с чтением потока при выводе. Функция, используемая Slim для вывода тела, выглядит следующим образом: $ body реализует StreamInterface, а $ this-> responseChunkSize имеет значение 4096:
$amountToRead = $body->getSize();
while ($amountToRead > 0 && !$body->eof()) {
$length = min($this->responseChunkSize, $amountToRead);
$data = $body->read($length);
echo $data;
$amountToRead -= strlen($data);
if (connection_status() !== CONNECTION_NORMAL) {
break;
}
}
Появляется вызов $ body-> eof () (который просто оболочка для функции PHP feof () возвращает true, даже если весь файл не был прочитан. Не уверен, почему это было бы все же. Я также проверил, что этого не происходит, если я просто делаю fopen () для файла и создаю из него поток, а затем запускаю тот же код. Это происходит только тогда, когда поток является продуктом внешнего вызова REST API через Guzzle.
Исходное сообщение
У меня есть служба, созданная с использованием Slim (v4.4), которая вызывает внешний REST API с использованием Guzzle (v6.5.3), который возвращает файл. Это работает в Windows, веб-сервер IIS / FastCGI (я знаю, необычно). PHP версия 7.3.10. При обращении Slim к внешнему REST API файл извлекается просто отлично, но когда мое приложение вызывает службу, некоторые файлы повреждаются, кажется, что некоторые данные теряются в зависимости от того, что я вижу в размере файла. Вызов службы из внешнего API REST довольно прост:
$file_response = $guzzleClient->request('GET', "{$base_url}/docs/{$file_id}", [
'headers' => [
'Authorization' => "token {$token}"
]
]);
Вышеуказанный вызов работает нормально и возвращает файл правильно, я могу либо отобразить его на экране, либо использовать опцию 'sink' в Guzzle чтобы сохранить в файл, он работает нормально. Но когда я пытаюсь вызвать сервис, который оборачивает этот вызов, он терпит неудачу. Я попробовал пару вещей. Во-первых, я просто возвращал ответ как есть, поскольку он в любом случае соответствует требуемому интерфейсу. Мой Slim-маршрут выглядит следующим образом:
$app->group('/files', function (Group $group) {
$group->get('/{file_id}', GetFileAction::class);
});
Класс GetFileAction имеет такой метод:
public function __invoke(Request $request, Response $response, $args): Response {
...Guzzle request returning $file_response here...
return $file_response;
}
Мое приложение также использует Guzzle для вызова службы, вызов выглядит следующим образом :
$guzzleClient->request(
'GET',
"{$base_url}/files/{$file_id}",
[
'auth' => [$username, $password],
'sink' => $file_path
]
);
Мне было интересно, может ли возврат ответа Guzzle в Slim вызвать какой-то неожиданный результат, поэтому я попытался вернуть его в службу:
return $response->withBody(new \Slim\Psr7\Stream($file_response->getBody()->detach()));
Тот же результат. Очевидно, что если кто-то, кто столкнулся с точно такой же проблемой, может помочь, это было бы здорово, но если бы не несколько указаний о том, как я мог бы попытаться отладить обработку потоков, вероятно, было бы полезно.