【问题标题】:Upload Progress - Sometimes $_SESSION[$key] is Empty上传进度 - 有时 $_SESSION[$key] 为空
【发布时间】:2014-12-10 01:49:18
【问题描述】:

我有 Ubuntu 12.04 LTS 并使用 PHP 5.5 和 Apache2 通过 PHP 会话上传进度来实现上传进度。

问题是它有时有效,有时无效。我的意思是有时我在上传开始时直接获得 100% 的进度百分比而没有完成上传(这意味着 $_SESSION[$key] 在这种情况下是空的,但是为什么?!)

我尝试将 session.upload_progress.cleanup 的值设置为 On 和 Off,但没有任何改变。

您可以在此网址上亲自尝试:
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 不感兴趣。如果您还提示我有关更好的方法来获得使用进度条实现上传的稳健方法,我将不胜感激。

感谢您的帮助!

【问题讨论】:

  • 我遇到了同样的问题,发现了一个奇怪的(奇怪!!)点。事实上,当你说“我在上传开始时直接获得 100% 的进度百分比而没有完成上传(这意味着 $_SESSION[$key] 是空的”你错了。如果你记录他的数据,你会看到,在第一次调用时,bytes_processed=content_length。我现在不知道为什么...... :(

标签: javascript php session file-upload progress-bar


【解决方案1】:

由于答案的大小,我使用回复部分。或者,一些细节的大小...... 事实上我也有同样的问题,在 Debian Whezzy 上运行 PHP 5.5.18。

为了保存$key、bytes_processed和content_length的值,做了一些测试并在progress.php中放了一个日志,这是我的结论:

发现 1:我们没有空键。我们有一个向我们显示信息的密钥 bytes_processed = content_length

发现 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";

我们使用inprogress.php获取数据:

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

意思是所有我们的$key有相同的名字。 我改变了:

 $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 所说的:

警告 必须禁用 Web 服务器的请求缓冲才能正常工作,否则 PHP 可能仅在完全上传后才能看到文件上传。众所周知,像 Nginx 这样的服务器会缓冲较大的请求。

【讨论】:

    【解决方案2】:

    较早的帖子,但我建议两件事:

    1. 使隐藏字段动态值

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

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

    通过这种方式,您可以再次发送相同的文件名并且它会起作用,您将获得唯一的会话 ID。您也可以在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 或传输中可能存在缓冲,因此即使浏览器已经发送了所有 100% 的 POST 数据,$_SESSION[$key] 也会被初始化。这是我在某些 ISP 的情况。我删除了这段代码,它工作正常。通过这种方式,您可以实现 AJAX 将始终汇集数据而不是挂在此之上。您只需要在 TCP 出于某种原因丢弃并且 AJAX 将无休止地尝试池直到您关闭浏览器时处理异常。但我不知道这种情况发生的频率/是否发生。

    【讨论】:

      猜你喜欢
      • 2013-10-27
      • 1970-01-01
      • 1970-01-01
      • 2021-06-24
      • 1970-01-01
      • 1970-01-01
      • 2013-07-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多