04.09.2010, 13:39
|
Новичок на форуме
|
|
Регистрация: 04.09.2010
Сообщений: 3
|
|
Открытия ссылки "на скачивания" и отслеживания статус загрузки файла браузером.
Доброе время суток!
У меня возникли сложности в процессе написания не большого JavaScript-а, а именно, есть некий процесс:
- пользователь выделяет файлы на web странице, JS обрабатывает это выделение, получает ID элемента( для каждого файла оно будет уникальным), собирает массив JS, перевожу его этот объект в формат JSON и отправляю данные на сервер (не большой PHP скрипт)
- сервер получив эти данные обрабатывает, выбирает нужные файлы по ID (полная информация о файлах храниться в БД). Упаковывает выбранные файлы в архив zip и перемещает во временную public директорию для скачивания, дальше серверный сценарий отвечает обратно в браузер в формате JSON, в одном из параметров как раз и будет ссылка на этот архив.
Вот как это выглядит у меня:
function GetSelectedFiles(id){
if(id){
selectedIDs.length = 0;
uncheckSelection();
selectedIDs.push(id);
}
if(selectedIDs.length > 0 ){
oSendingData.file_list = selectedIDs;
$.post(php_download_link,JSON.stringify(oSendingData),onDownload,'json');
}
else{
printStatusbar("Выберите файл(ы) для скачнивания");
}
// Если скачиваем по иконки, то отчищаем массив
if(id)
selectedIDs.length = 0;
function onDownload(responce_json){
// Проверка ответа от сервера
checkAuthAndError(responce_json);
// Если получили ссылку на файл!
window.location.href = responce_json.download_link;
};
};
Собственно в чем проблема, после того как скрипт получил данные от сервера, я отдаю ссылку на «временный» файл в браузер, что бы конечно пользователь мог её скачать, это происходит вот в этой строке:
window.location.href = responce_json.download_link;
Так вот именно тут возникают две не понятки.
1) Если я даю ссылку не в на .ZIP архив, а на файл .JPEG, то браузер почему то открывает эту ссылку в ЭТОМ же окне и отображает картинку в браузере. Возможно ли как-нибудь заставить браузер открывать ссылку всегда с предложением для скачивания?
2) Пока временные файлы лежат во временном каталоге и я их удаляю периодический в ручную, думал вешать на сервере скрипт на perl\bash\php под cron-ом, который удалял бы файлы через N-кол-во времени, но это не совсем хороший способ, по многим причинам. Итак вопрос, возможно ли при помощи JS отследить, был ли скачен файл или нет? Если бы была возможность, то я бы просто после скачивания файла отправлял бы не большой запрос на сервер с подтверждением скачивания файла, и на сервере удалял бы его из временного каталога.
Помогите, плз может кто сталкивался с подобной задачей
|
|
04.09.2010, 13:57
|
|
Пионэр
|
|
Регистрация: 16.11.2009
Сообщений: 1,322
|
|
Чтобы браузер предложил скачать фаил, а не открыл его, нужно отдать его с http-заголовком
Код:
|
Content-Disposition: attachment |
либо
Код:
|
Content-Disposition: attachment; filename=my_file.tar.gz |
Во втором случае браузер предложит сохранить его именно с таким именем.
Все это делается на сервере, естесственно.
|
|
04.09.2010, 14:12
|
Новичок на форуме
|
|
Регистрация: 04.09.2010
Сообщений: 3
|
|
Сообщение от subzey
|
Чтобы браузер предложил скачать фаил, а не открыл его, нужно отдать его с http-заголовком
Код:
|
Content-Disposition: attachment |
либо
Код:
|
Content-Disposition: attachment; filename=my_file.tar.gz |
Во втором случае браузер предложит сохранить его именно с таким именем.
Все это делается на сервере, естесственно.
|
Да, это я уже в гугле вычитал, написал даже уже не большую функцию на php, которая делает правильные заголовки, но обратите внимания, в моем коде я делаю AJAX запрос методом POST, с указанием формата данных JSON и функцией обратного вызова. Т.е. в данном примере если я на стороне сервера скажем сделаю так:
header('Pragma: public'); // required
header('Expires: 0'); // no cache
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Last-Modified: '.gmdate ('D, d M Y H:i:s', filemtime ($file_name)).' GMT');
header('Cache-Control: private',false);
header("Content-Type: application/zip\n");
header('Content-Disposition: attachment; filename="'.basename($file_name).'"');
header('Content-Transfer-Encoding: binary');
header('Content-Length: '.filesize($file_name));
header('Connection: close');
readfile($file_name);
То в браузер почему то этого не понимает, хотя если я сделаю GET\POST к серверному файлу в ручную, то браузер нормально понимает этот HTTP заголовок.
Да и кроме того в моем случае в ответе от сервера (в формате JSON), существует еще дополнительная информация кроме как ссылка на файл.
Хотя я тут сейчас подумал, может быть действительно сделать дополнительную обработку данных с сервера, и отдельный сценарий на сервере который принимал бы данные о файле в GET-е отдавал их на скачку(как-нибудь в так: window.location = 'get_file.php?filename=XXXX.zip', т.е. что бы не использовать AJAX вызов ), после чего удалял бы.
|
|
04.09.2010, 15:10
|
|
Пионэр
|
|
Регистрация: 16.11.2009
Сообщений: 1,322
|
|
У php есть функция, которая открывает файл и отдает его содержимое клиенту (название не помню, но искать следует рядом с fpassthru). Также, есть функция с названием вроде is_client_aborted, которая проверяет, не отключился ли клиент.
Соответственно, если после вывода содержимого клиент не отключился, то файл скачан.
Сорри, конкретных имен функций не назову - я с телефона.
|
|
04.09.2010, 15:46
|
Новичок на форуме
|
|
Регистрация: 04.09.2010
Сообщений: 3
|
|
Сообщение от subzey
|
У php есть функция, которая открывает файл и отдает его содержимое клиенту (название не помню, но искать следует рядом с fpassthru). Также, есть функция с названием вроде is_client_aborted, которая проверяет, не отключился ли клиент.
Соответственно, если после вывода содержимого клиент не отключился, то файл скачан.
Сорри, конкретных имен функций не назову - я с телефона.
|
так я выше описал что если я делаю GET\POST из AJAX, то что бы я не делал в PHP(имею ввиду с заголовками), то файл не понятно куда скачивается(подозреваю где то в кеше браузера лежит), см. внимательно мой код выше.
Вообщем решил проблему:
var sname = getParam("sname");
var sid = getParam(sname);
var add_url = 'PHPSESSID=' + sid + '&sname=' + sname;
var php_get_dl_link = '../php/json_get_file.php';
var php_download_file = '../php/download.php?' + add_url;
var oSendingData = new Object();
oSendingData.session_id = sid;
oSendingData.session_name = sname;
function GetSelectedFiles(id){
if(id){
selectedIDs.length = 0;
uncheckSelection();
selectedIDs.push(id);
}
if(selectedIDs.length > 0 ){
oSendingData.file_list = selectedIDs;
$.post(php_get_dl_link,JSON.stringify(oSendingData),onDownload,'json');
}
else{
printStatusbar("Выберите файл(ы) для скачивания");
}
// Если скачиваем по иконки, то отчищаем массив
if(id)
selectedIDs.length = 0;
function onDownload(responce_json){
// Проверка ответа от сервера
checkAuthAndError(responce_json);
// Если получили ссылку на файл!
window.location.href = php_download_file + '&dl_file='+responce_json.download_link;
};
};
json_get_file.php
// Тут идет обработка файла, проверка авторизации и так далее ....
// Сохраняю путь к временному файлу, что бы его ни кто другой не спер!
$_SESSION['download_tmp_file'] = $file_name;
// .....
ну и потом сам download.php
<?php
ini_set('display_errors',1);
error_reporting(E_ALL);
ini_set('session.use_cookies',0);
// Подключаю настройки
include("./include/g_settings.inc.php");
$sname = $_GET['sname'];
$sid = $_GET['PHPSESSID'];
$filename = $_GET['dl_file'];
session_id($sid);
session_name($sname);
session_start(); // Запускам сессию
// Проверяем что сессия активна!
if(!isset($_SESSION['is_auth']) || $_SESSION['is_auth'] == 0){ // Если сессия не активна
$s_status = 0;
session_unset();
session_destroy();
Header("Location: ../index.html");
exit(1);
}
// Если установлена переменная сессия с ссылкой на скачку файла
if(isset($_SESSION['download_tmp_file'])){
// Проверяем что поступил запрос на скачку именно этого файла!
if($_SESSION['download_tmp_file'] == $filename){
header('Pragma: public'); // required
header('Expires: 0'); // no cache
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Last-Modified: '.gmdate ('D, d M Y H:i:s', filemtime ($filename)).' GMT');
header('Cache-Control: private',false);
header("Content-Type: application/zip\n");
header('Content-Disposition: attachment; filename="'.basename($filename).'"');
header('Content-Transfer-Encoding: binary');
header('Content-Length: '.filesize($filename));
header('Connection: close');
// Отдаем файл в браузер
ob_clean();
flush();
if(readfile($filename)){
if(!unlink($filename)) // Удаляем файл, если не получилось то сообщаем об ошибки
echo "<h1>Error on remove file! Please contact a system administrator!</h1>"; // TODO: syslog
else
unset($_SESSION['download_tmp_file']); // Хотя все равно перезапишется!
}
else
echo "<h1>Error on download file! Please contact a system administrator!</h1>";
// TODO: syslog
}
else
{
echo "<h1>access denied!!!</h1>";
// TODO: syslog
}
}else{
echo "<h1>File not found!!!</h1>";
// TODO: syslog
}
?>
|
|
04.09.2010, 15:56
|
Новичок на форуме
|
|
Регистрация: 19.02.2008
Сообщений: 9,177
|
|
Сообщение от doom_man
|
если я делаю GET\POST из AJAX, то что бы я не делал в PHP(имею ввиду с заголовками), то файл не понятно куда скачивается
|
Не надо делать ajax-запрос, если хотите скачать файл.
|
|
10.09.2010, 19:16
|
|
Профессор
|
|
Регистрация: 10.09.2009
Сообщений: 1,578
|
|
Сообщение от Kolyaj
|
Не надо делать ajax-запрос, если хотите скачать файл.
|
То есть никак - никак?
|
|
10.09.2010, 20:15
|
|
Профессор
|
|
Регистрация: 10.09.2009
Сообщений: 1,578
|
|
Создаю в общем файл(надо чтобы у пользователя появилось "Сохранить как" ...), а имя его в сессии. Создал страничку, которая его отдаст:
session_start();
$f = (isset($_SESSION['loadfile'])) ? $_SESSION['loadfile'] : 'xxx.xxx';
unset($_SESSION['loadfile']);
if (file_exists('./data/' . $f)) {
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment;filename=" . $f);
echo file_get_contents('./data/' . $f);
}
В своем же ajax-приложении, мне надо открыть этот адрес. Делаю так:
var w = window.open('savefile.php');
появляется окошко о заблокированных окнах. Можно как то лучше это сделать? Пробовал ссылку с target="_blank" на jQuery кликнуть($('#aaa').click()) - не действует.
|
|
10.09.2010, 21:20
|
Новичок на форуме
|
|
Регистрация: 19.02.2008
Сообщений: 9,177
|
|
Просто location.href = 'savefile.php';
|
|
|
|