JavaScript — процесс загрузки — Иногда $ _SESSION [$ key] пусто

У меня Ubuntu 12.04 LTS и я использую PHP 5.5 с Apache2 для реализации процесса загрузки через процесс загрузки сеанса PHP.

Проблема в том, что иногда это работает, а иногда не работает. Я имею в виду, что иногда я получаю процент прогресса на 100% напрямую в начале загрузки, не заканчивая загрузку (что означает, что $ _SESSION [$ key] пуст в этих случаях, но почему ?!)

Я попытался включить значение session.upload_progress.cleanup в значение On и Off, но это ничего не изменило.

Вы можете попробовать сами по этому URL:
http://138.128.124.172/upload_progress

в php.ini, У меня есть следующие настройки, связанные с загрузкой:

;;;;;;;;;;;;;;;;
; File Uploads ;
;;;;;;;;;;;;;;;;

; Whether to allow HTTP file uploads.
; http://php.net/file-uploads
file_uploads = On

; Temporary directory for HTTP uploaded files (will use system default if not
; specified).
; http://php.net/upload-tmp-dir
;upload_tmp_dir =

; Maximum allowed size for uploaded files.
; http://php.net/upload-max-filesize
upload_max_filesize = 100M

; Maximum number of files that can be uploaded via a single request
max_file_uploads = 20; Enable upload progress tracking in $_SESSION
; Default Value: On
; Development Value: On
; Production Value: On
; http://php.net/session.upload-progress.enabled
session.upload_progress.enabled = On

; Cleanup the progress information as soon as all POST data has been read
; (i.e. upload completed).
; Default Value: On
; Development Value: On
; Production Value: On
; http://php.net/session.upload-progress.cleanup
session.upload_progress.cleanup = Off

; A prefix used for the upload progress key in $_SESSION
; Default Value: "upload_progress_"; Development Value: "upload_progress_"; Production Value: "upload_progress_"; http://php.net/session.upload-progress.prefix;session.upload_progress.prefix = "upload_progress_"
; The index name (concatenated with the prefix) in $_SESSION
; containing the upload progress information
; Default Value: "PHP_SESSION_UPLOAD_PROGRESS"; Development Value: "PHP_SESSION_UPLOAD_PROGRESS"; Production Value: "PHP_SESSION_UPLOAD_PROGRESS"; http://php.net/session.upload-progress.name
;session.upload_progress.name = "PHP_SESSION_UPLOAD_PROGRESS"
; How frequently the upload progress should be updated.
; Given either in percentages (per-file), or in bytes
; Default Value: "1%"; Development Value: "1%"; Production Value: "1%"; http://php.net/session.upload-progress.freq
;session.upload_progress.freq =  "1%"

; The minimum delay between updates, in seconds
; Default Value: 1
; Development Value: 1
; Production Value: 1
; http://php.net/session.upload-progress.min-freq
;session.upload_progress.min_freq = "1"

На стороне PHP: у меня есть код ниже на странице: progress.php:

session_start();
$key = ini_get("session.upload_progress.prefix") . "myForm";
if (!empty($_SESSION[$key])) {
$current = $_SESSION[$key]["bytes_processed"];
$total = $_SESSION[$key]["content_length"];
echo $current < $total ? ceil($current / $total * 100) : 100;
}
else {
echo 100;
}

На стороне клиента у меня есть код ниже на странице index.php

<?php

if ($_SERVER["REQUEST_METHOD"] == "POST" && !empty($_FILES["userfile"])) {
// move_uploaded_file()
}
?>

<style>
#bar_blank {
border: solid 1px #000;
height: 20px;
width: 300px;
}

#bar_color {
background-color: #006666;
height: 20px;
width: 0px;
}

#bar_blank, #hidden_iframe {
display: none;
}
</style><html>
<head>
<title>File Upload Progress Bar</title>
</head>
<body>
<div id="bar_blank">
<div id="bar_color"></div>
</div>
<div id="status"></div>
<form action="<?php echo $_SERVER["PHP_SELF"]; ?>" method="POST" id="myForm" enctype="multipart/form-data" target="hidden_iframe">
<input type="hidden" value="myForm" name="<?php echo ini_get("session.upload_progress.name"); ?>">
<input type="file" name="userfile"><br>
<input type="submit" value="Start Upload">
</form><iframe id="hidden_iframe" name="hidden_iframe" src="about:blank"></iframe>
</body>
</html><script>

function toggleBarVisibility() {
var e = document.getElementById("bar_blank");
e.style.display = (e.style.display == "block") ? "none" : "block";
}

function createRequestObject() {
var http;
if (navigator.appName == "Microsoft Internet Explorer") {
http = new ActiveXObject("Microsoft.XMLHTTP");
}
else {
http = new XMLHttpRequest();
}
return http;
}

function sendRequest() {
var http = createRequestObject();
http.open("GET", "progress.php");
http.onreadystatechange = function () { handleResponse(http) };
http.send(null);
}

function handleResponse(http) {
var response;
if (http.readyState == 4) {
response = http.responseText;  //alert(response);return;
document.getElementById("bar_color").style.width = response + "%";
document.getElementById("status").innerHTML = response + "%";

if (response < 100) {
setTimeout("sendRequest()", 1000);
}
else {
toggleBarVisibility();
document.getElementById("status").innerHTML = "Done.";

document.getElementById("bar_color").style.width = 0 + "%";

}
}
}

function startUpload() {
toggleBarVisibility();
setTimeout("sendRequest()", 1000);
}

(function () {
document.getElementById("myForm").onsubmit = startUpload;
})();

</script>

Меня не интересует HTML5, Jquery или flash. Я был бы благодарен, если бы вы намекнули также и о лучших подходах, чтобы получить надежный способ осуществить загрузку с индикатором выполнения.

Спасибо за вашу помощь!

2

Решение

Я использую часть ответа из-за размера ответа. Или размер некоторых деталей …
На самом деле у меня та же проблема: PHP 5.5.18 работает на Debian Whezzy.

Сделав несколько тестов и поместив журнал в файл progress.php, чтобы сохранить значения $ key, bytes_processed и content_length, я пришел к выводу:

Discovery 1: у нас нет пустого ключа. У нас есть ключ, показывающий нам информацию с bytes_processed = content_length

Discovery 2: если вы скачаете, например, 4 файла с различным размером, а затем посмотрите журнал вашего файла progress.php, вы увидите, что значение сеанса для второго файла даст вам результат для файла 1.

Пример:

Отправьте test.docx -> 500.000 байт. $ key пуст

Отправить house.jpg -> 4.000.000 байт. $ key дает bytes_processed = content_length = 500.000, так что результат предыдущего файла

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

 echo "<input type=hidden value=\"myForm\" name=\"";
echo ini_get("session.upload_progress.name");
echo "\" />\n";

И мы получаем данные, используя в progress.php:

 $key = ini_get("session.upload_progress.prefix") . "myForm";

имея в виду ВСЕ наш ключ $ имеет то же имя.
Я меняю на:

 $val = time();
echo "<input type=hidden value=\"".$val."\" name=\"";
echo ini_get("session.upload_progress.name");
echo "\" />\n";

а также

 $key = ini_get("session.upload_progress.prefix") . $_POST[ini_get("session.upload_progress.name")];

Теперь каждый раз у меня есть пустой ключ.
Мой вывод заключается в том, что у нас есть проблема с кешем, о которой говорит PHP.net:

Предупреждение
Чтобы это работало правильно, необходимо отключить буферизацию запросов веб-сервера, иначе PHP может увидеть загрузку файла только после полной загрузки. Известно, что такие серверы, как Nginx, буферизуют большие запросы.

0

Другие решения

Предыдущий пост, но я бы предложил две вещи:

  1. Сделать скрытое поле динамическим значением

$_SESSION['ukey'] = substr(md5(uniqid(rand(), true)),0,6);

<input type="hidden" value="<?php echo $_SESSION['ukey'] ?>" name="<?php echo ini_get("session.upload_progress.name"); ?>">

Этим вы добьетесь того, что сможете снова отправлять те же имена файлов, и это будет работать, вы получите уникальный идентификатор сеанса. Также вы можете использовать в php.ini Значение session.upload_progress.cleanup = Off поэтому данные в сеансе будут там после достижения 100%. В progres.php измените на $key = ini_get("session.upload_progress.prefix") . echo $_SESSION['ukey'];

  1. В процессе выполнения скрипта также эта часть кода вызывает проблемы:

else {
echo 100;
}

Причина в том, что может быть буферизация в каком-то промежуточном устройстве или Apache или в транзите, поэтому $_SESSION[$key] будет инициализирован даже после того, как браузер уже отправит все 100% данных POST. Это мой сценарий у некоторых интернет-провайдеров. Я удалил этот код, и он работает нормально. Тем самым вы добьетесь того, что AJAX будет всегда объединять данные и не зависать на этом. Вам нужно обрабатывать исключение только тогда, когда TCP по какой-то причине упал и AJAX будет бесконечно пытаться объединяться в пул, пока вы не закроете браузер. Но я не знаю, как часто это происходит / если это случается.

0

По вопросам рекламы [email protected]