Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Сохранить pdf-файл из просмотрщика Chrome (https://javascript.ru/forum/misc/80999-sokhranit-pdf-fajjl-iz-prosmotrshhika-chrome.html)

slan 10.09.2020 10:46

Сохранить pdf-файл из просмотрщика Chrome
 
Добрый день. Ситуация такая: по запросу из браузера клиента на сервере генерится pdf, который потом отдаётся в браузер клиента, в новое окно для просмотра.
Код:

function send_pdf_file($file_name,$contents)
{
  header("Content-Length: ".strlen($contents));
  header("Content-Type: application/pdf; name=\"".$file_name."\"");
  header("Content-Disposition: inline; filename=\"".$file_name."\"");
  header("expires: 0");
  echo $contents;   
}

Всё хорошо отрабатывает: в браузере пользователя открывается окно с просмотром pdf-файла.
Если нажать на кнопку Сохранить, то в случае браузера Firefox всё отрабатывается корректно - пользователь получает запрос на сохранение pdf-файла и сохраняет его, в любой момент gjrf jnrhsnj jryj просмотрщика.
В случае же браузера Chrome (и Edge), если на кнопку успеть нажать в первые 5 секунд после открытия просмотрщика - то всё тоже ок , если же нажать после истечения 5 секунд - то открывается запрос на сохранение не pdf-файла, а php-скрипта, который дёргался для формирования этого pdf.
Подскажите, как победить эту ситуацию с Chrome?

Vlasenko Fedor 10.09.2020 10:54

Content-Disposition: attachment
попробуйте

slan 10.09.2020 11:06

Цитата:

Сообщение от Vlasenko Fedor (Сообщение 528722)
Content-Disposition: attachment
попробуйте

В этом случае сразу открывается диалог сохранения pdf-файла. Работает корректно. Но цель стоит другая - в любом случае открывать pdf-файл для просмотра, и чтобы из этого просмотрщика пользователь мог и сохранить при желании.

voraa 10.09.2020 11:56

A какой URL имеет то самое окно, в котором открывается pdf?
Наверно того самого скрипта, который его формирует.
Но есть
header("expires: 0");
Хром может из-за этого для сохранения заново обратится по указанному URL.
А скрипт по этому URL пошлет снова документ и все заголовки, включая
header("Content-Type: application/pdf; name=\"".$file_name."\"");
header("Content-Disposition: inline; filename=\"".$file_name."\"");

Vlasenko Fedor 10.09.2020 11:56

Цитата:

Сообщение от slan (Сообщение 528724)
в любом случае открывать pdf-файл для просмотра

это зависит от настроек браузера, есть ли унего просмотрщик пдф, активирован ли он

laimas 10.09.2020 12:06

Цитата:

Сообщение от Vlasenko Fedor
это зависит от настроек браузера, есть ли унего просмотрщик пдф

Вот это в точку, ибо никаких проблем не будет он создавать от заголовков ни в хроме, ни в других. Вообще-то достаточно и двух.

header('Content-Type: application/pdf');
header("Content-Disposition: inline; filename=name.pdf");

slan 10.09.2020 12:11

Цитата:

Сообщение от voraa (Сообщение 528727)
A какой URL имеет то самое окно, в котором открывается pdf?
Наверно того самого скрипта, который его формирует.
Но есть
header("expires: 0");
Хром может из-за этого для сохранения заново обратится по указанному URL.
А скрипт по этому URL пошлет снова документ и все заголовки, включая
header("Content-Type: application/pdf; name=\"".$file_name."\"");
header("Content-Disposition: inline; filename=\"".$file_name."\"");

Вы правы, в том окне URL скрипта.
Проверил - наличие header("expires: 0") никак не влияет на поведение хрома: при сохранении в первые 5 секунд выдаётся диалог на сохранение pdf, в последующие диалог на сохранение скрипта php. Если попробовать сохранить скрипт, то хром выдаёт Ошибка: ошибка сети. При этом никаких запросов на вкладке Network в Инструментах разработчика не появляется.
Похоже как-то эти самые 5 секунд связаны с наличием в Response Headers такого хедера Keep-Alive: timeout=5, max=100.

slan 10.09.2020 12:12

Цитата:

Сообщение от Vlasenko Fedor (Сообщение 528728)
это зависит от настроек браузера, есть ли унего просмотрщик пдф, активирован ли он

Это всё понятно. Но как тогда объяснить странное поведение хрома при этом?

laimas 10.09.2020 12:16

Цитата:

Сообщение от slan
Но как тогда объяснить странное поведение хрома при этом?

Странности не в хроме, а скорее всего в работе скрипта вашего, нет проблем в хроме. Можете проверить прямой ссылкой на файл.

slan 10.09.2020 12:19

Цитата:

Сообщение от laimas (Сообщение 528732)
Странности не в хроме, а скорее всего в работе скрипта вашего, нет проблем в хроме. Можете проверить прямой ссылкой на файл.

Наверное так и есть, правда нееясно, почему же в Firefox всё отрабатывает как нужно.
Файла не сохраняется на сервере, он генерится и сразу отдаётся.

laimas 10.09.2020 12:33

Цитата:

Сообщение от slan
Файла не сохраняется на сервере, он генерится и сразу отдаётся.

Какая проблема его сохранить для проверки или взять любой готовый? Ведь в таком случае уже сервер автоматом передаст браузеру необходимые заголовки, а главный из них это тип файла, все остальные можно было бы и опустить, так как после передачи последнего байта сервер закроет соединение, это и будет размер. А просмотр отдает на сохранение ранее загруженное. А имя файла по умолчанию (document) можно и исправить. То есть в самом механизме нет проблемы, хоть по прямой ссылке, хоть отдавая контент скриптом. Была бы здесь возможность вставлять видео, мог бы и снять такое с простым примером, чтобы убедиться в отсутствии проблем в Хроме.

У вас какие-то проблемы в логике скрипта надо полагать.

slan 10.09.2020 13:20

Цитата:

Сообщение от laimas (Сообщение 528734)
У вас какие-то проблемы в логике скрипта надо полагать.

Я тоже так думаю. К сожалению не могу понять какие.

slan 10.09.2020 14:10

Цитата:

Сообщение от laimas (Сообщение 528734)
Какая проблема его сохранить для проверки или взять любой готовый?

Положил на сервер готовый файл 1.pdf.
сделал в скрипте вот так:
header("Content-Type: application/pdf; name=\"1.pdf\"");
  header("Content-Disposition: inline; filename=\"1.pdf\"");
  readfile("../1.pdf");

Результат тот же самый. 5 секунд скачивается pdf, после хром предлагает скачать сам скрипт.

laimas 10.09.2020 14:14

Цитата:

Сообщение от slan
не могу понять какие

Ну а остальным тем более не ведомо, как у вас построен сам диалог клиент-сервер. Ведь сам браузер работает так - если в нем есть средство просмотра фала, то он его откроет, если нет, то предложит диалог для сохранения или открытия его в ПО на компьютере. А по прямой ли это ссылке или контент отдается скриптом, это не так и важно в данном случае.

laimas 10.09.2020 14:16

Цитата:

Сообщение от slan
Положил на сервер готовый файл 1.pdf.
сделал в скрипте вот так

Вы ничего не изменили этим примером. Отдать по прямой ссылке, это <a href=file...

slan 10.09.2020 14:51

Цитата:

Сообщение от laimas (Сообщение 528740)
Ну а остальным тем более не ведомо, как у вас построен сам диалог клиент-сервер. Ведь сам браузер работает так - если в нем есть средство просмотра фала, то он его откроет, если нет, то предложит диалог для сохранения или открытия его в ПО на компьютере. А по прямой ли это ссылке или контент отдается скриптом, это не так и важно в данном случае.

Я же вроде бы сразу написал, что сам файл браузером Chrome к просмотру открывается и отображается корректно. Некорректно происходит скачивание этого файла из просмотрщика по кнопке Сохранить после того как прошло 5 секунд.

slan 10.09.2020 14:52

Цитата:

Сообщение от laimas (Сообщение 528741)
Вы ничего не изменили этим примером. Отдать по прямой ссылке, это <a href=file...

Я не совсем понимаю этого эксперимента. Мне не нужно по прямой ссылке, ибо понятное дело так работать будет.

laimas 10.09.2020 15:50

Цитата:

Сообщение от slan
Я не совсем понимаю этого эксперимента

Если логика (запрос клиента->окно->...) вашего скрипта страдает, то проблемы будут и с прямой ссылкой.

slan 10.09.2020 16:26

laimas,
Спасибо за помощь. Посмотрел ваше видео, у вас отрабатывает так как нужно.
Положил готовый pdf на сервер, на кнопку повесил href. В этом случае отрабатывает как надо, файл скачивается в любой момент времени.
В моем же случае, вида
window.open("/get_pdf.php", "_blank");

отрабатывает не так как хотелось бы.

laimas 10.09.2020 16:29

Цитата:

Сообщение от slan
В моем же случае, вида

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

laimas 10.09.2020 16:35

Цитата:

Сообщение от slan
"_blank"

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

slan 10.09.2020 16:55

Пробовал ставить туда разные значения, изменений не было.

laimas 10.09.2020 17:28

Цитата:

Сообщение от slan
ставить туда разные значения

Если вы хотите вкладку, значит достаточно только первого параметра, а если окно, то нужно указать его параметры.

voraa 10.09.2020 18:15

Цитата:

Сообщение от slan
Положил на сервер готовый файл 1.pdf.
сделал в скрипте вот так:
header("Content-Type: application/pdf; name=\"1.pdf\"");
  header("Content-Disposition: inline; filename=\"1.pdf\"");
  readfile("../1.pdf");

Результат тот же самый. 5 секунд скачивается pdf, после хром предлагает скачать сам скрипт.

Провел эксперимент
Положил на сервер
HTML

<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="Content-type" content="text/html; charset=utf-8" lang="ru">
  <meta name="viewport" content="width=device-width, initial-scale=1.0" >
  <title>TESTE </title>
</head>

<body>

<button id='gpdf'>Load pdf</button>

<script>
document.getElementById('gpdf').addEventListener('click', ()=> {
window.open('gpdf.php','fpdf')
})
</script>
</body>
</html>


Вот такой gpdf.php

<?php
header("Content-Type: application/pdf; name=\"file.pdf\"");
header("Content-Disposition: inline; filename=\"file.pdf\"");
readfile("file.pdf");
?>

и какой то file.pdf

Все в хроме нормально работает. В новой вкладке открывается pdf.
Сохраняется, как pdf хоть через 5 сек, хоть через 50

laimas 10.09.2020 18:23

Цитата:

Сообщение от voraa
header("Content-Type: application/pdf; name=\"file.pdf\"");

Зачем в типе передавать имя, оно там совсем не нужно.

voraa 10.09.2020 18:42

Цитата:

Сообщение от laimas
Зачем в типе передавать имя, оно там совсем не нужно.

Просто взял код приведенный автором

slan 11.09.2020 10:51

Всем спасибо за помощь. На другом сервере (nginx) всё отработало как надо.
Проблемы возникают на apache, в нём присутствует в Response Headers заголовок Keep-Alive: timeout=5, max=100. Вот эти 5 секунд.
Если в скрипте написать вот так:
header("Connection: close");

то файл не скачивается из просмотрщика прямо сразу, предлагает скачать скрипт.

voraa 11.09.2020 11:51

Цитата:

Сообщение от slan
Если в скрипте написать вот так:
header("Connection: close");

то файл не скачивается из просмотрщика прямо сразу, предлагает скачать скрипт.

Опять провел тест на своем сервере.
Поставил в скрипт указанный заголовок
Все равно приходит и скачивается pdf. Хоть через 5 сек, хоть через 50.

Вот, что имеем в сети

General

Request URL: http://localhost/teste/xtests/testpdf1/gpdf.php
Request Method: GET
Status Code: 200 OK
Remote Address: 127.0.0.1:80
Referrer Policy: no-referrer-when-downgrade

Response Headers

Connection: close
Content-Disposition: inline; filename="file.pdf"
Content-Type: application/pdf; name="file.pdf"
Date: Fri, 11 Sep 2020 08:58:01 GMT
Server: Apache
Transfer-Encoding: chunked

Request Headers

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate, br
Accept-Language: ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7
Cache-Control: no-cache
Connection: keep-alive
DNT: 1
Host: localhost
Pragma: no-cache
Referer: http://localhost/teste/xtests/testpdf1/indexa.html
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36


Часовой пояс GMT +3, время: 07:34.