上传进度 - 有时$ _SESSION [$ key]为空

时间:2014-10-15 05:07:19

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

我有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不感兴趣。如果你提示我更好的方法来获得一个强大的方法来实现带有进度条的上传,我将非常感激。

感谢您的帮助!

2 个答案:

答案 0 :(得分:0)

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

在进行一些测试并在progress.php中放入一个日志以保存$ key,bytes_processed和content_length的值之后,这是我的结论:

发现1 :我们没有空密钥。我们有一个键,显示了bytes_processed = content_length

的信息

发现2 :如果您下载4个不同大小的文件,然后查看progress.php的日志,您会看到第二个文件的会话值会给你文件1的结果。

示例:

发送test.docx - &gt; 500.000字节。 $ key为空

发送house.jpg - &gt; 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";

我们使用in progress.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等服务器可以缓冲更大的请求。

答案 1 :(得分:0)

旧帖子,但我建议两件事:

  1. 制作隐藏字段动态值
  2. $_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"); ?>">

    通过这个你实现了你可以再次发送相同的文件名,它将工作,你将获得唯一的会话ID。您也可以在php.ini中使用值session.upload_progress.cleanup = Off,以便在达到100%后会话中的数据。在progres.php中更改为$key = ini_get("session.upload_progress.prefix") . echo $_SESSION['ukey'];

    1. 正在进行脚本中这部分代码也造成了麻烦:
    2. else { echo 100; }

      原因是某些中间设备或apache或传输中可能存在缓冲,因此即使浏览器已经发送了所有100%的POST数据,也会初始化$_SESSION[$key]。这是我在某些ISP的情况。我删除了这段代码,它运行正常。通过这种方式,您可以实现AJAX将始终汇集数据而不是挂起。你只需要在出于某种原因丢弃TCP时处理异常,并且AJAX会在你关闭浏览器之前不断尝试汇集。但我不知道这种情况会发生多久或是否发生。