doudeng2025 2016-05-09 23:21
浏览 72
已采纳

告诉AJAX请求已完成而不取消文件上传

I am sorry if the title was misleading, there is no easy way to abridge my issue in a title. I am currently experimenting with AJAX file uploads; I had done standard file uploads before but now I am trying to make my application's interface a bit better by adding a progress bar that tracks the file upload progress and notifies the user when the video finishes uploading, finishes processing and is put into the database.

It is working mostly fine, except for the fact that Ajax is currently working for my script to finish execution. Basically, what's happening is that most of the calls are made from a single file called uploadfiles.php. I am using a while loop with feof and logging the progress to a file, which is then supposed to be fetched by another AJAX that loops until the file tells it that the request has changed/completed.

But, again, the progress bar doesn't move as for some reason the first AJAX request is waiting until uploadfiles.php fully finishes executing (Which would be when the file finishes uploading, processing and gets moved, and would make the progress bar pointless), and due to that doesn't let the next AJAX request that retrieves the log file contents. I have tried the following:

  • Did ob_start(); and ob_end_flush() just after the file is moved from PHP's tmp folder to my custom tmp folder
  • Did flush(), which I suppose is the exact same thing as the point above
  • Echoed something random and flushed again, hoping something would happen

I have also added ignore_user_abort() to ensure the request doesn't get aborted if the user leaves the page/the request ends or gets aborted.

**Here's the JS code:

    function uploadFiles()
{
    var data2 = new FormData($("#specialform")[0]);

    timestamp = new Date().getUTCMilliseconds();
    timestamp = timestamp.toString();

    data2.append('outputId', timestamp);

    console.log(data2);

    $.ajax({
        type        : "POST",
        url         : "actions/uploadfiles.php",
        data        : data2,
        processData : false,
        contentType : false,
        success: function(data)
        {
            alert('Finished first request');
            getLog();
        },
        error: function (xhr, ajaxOptions, thrownError)
        {
            alert(xhr.responseText);
            alert(thrownError);
        },
        xhr: function ()
        {
            var xhr = new window.XMLHttpRequest();

            xhr.addEventListener("progress", function (evt)
            {
                if (evt.lengthComputable)
                {
                        var percentComplete = evt.loaded / evt.total;
                        console.log(percentComplete);
                        var percentComplete = percentComplete * 100;

                        $("#progressBar").css({ width : percentComplete + '%' });

                        if ( percentComplete >= 100 )
                            xhr.abort();
                }
                else
                        console.log('unable to complete');
            }, false);

            return xhr;
        },
    })
    .fail(function(data)
    {
        console.log(data);
    });

    //return {'error' : 'No files', 'result' : null};
}

function getLog()
{
    if ( finished == false )
    {
        console.log("logs/" + timestamp);

        $.ajax({
            type        : "GET",
            url         : "logs/" + timestamp,
            processData : false,
            contentType : false,
            success: function(data)
            {
                if ( data == "processing" && !processed )
                {
                    alert('processing video');

                    $("#progressBar").css({ 'background-color' : 'yellow' });

                    processed = true;
                }

                if ( data == "done" )
                {
                    alert('finished conversion');

                    $("#progressBar").css({ 'background-color' : 'green' });

                    finished = true;
                }

                if ( $.isNumeric(data) )
                    $("#progressBar").css({ width : data + '%' });

                console.log(data);
            }
        });

        setTimeout(getLog, 1000);
    }
}

Here's the PHP code:

<?php

require '../Init.php';

define('TMP_PATH', PATH.'/tmp');
define('V_STORE', PATH.'/resources/videos');
define('FFMPEG_PATH', 'F:/Webserver/ffmpeg/bin/ffmpeg.exe');

// ...

ob_start();

echo "END";

ob_end_flush();
flush();

// ...

$remote = fopen($_FILES['file']['tmp_name'], 'r');
$local = fopen($filename, 'w');

$read_bytes = 0;

set_time_limit(28800000);
ignore_user_abort(true);

$interval = 0;

while( !feof($remote) )
{
    $buffer = fread($remote, 2048);
    fwrite($local, $buffer);

    $read_bytes += 2048;

    $progress = min(100, 100 * $read_bytes / $filesize);

    if ( $interval <= 0 )
    {
        file_put_contents('../logs/'.$logFile, $progress);

        $interval = 1000;
    }
    else
        $interval--;
}

// ...

$proc = popen(FFMPEG_PATH.' -i '.$filename.' -b '.$newBitrate.' '.V_STORE.'/'.$video_id.'.mp4', 'r');

while (!feof($proc))
{
    file_put_contents('../logs/'.$logFile, fread($proc, 4096));
}

file_put_contents('../logs/'.$logFile, "done");

sleep(5);

unlink('../logs/'.$logFile);

Don't worry about the Init.php as (In this case) it is only used for the PATH constant

Thanks in advance.

  • 写回答

1条回答 默认 最新

  • duanjiu1950 2016-05-09 23:28
    关注

    Are you using PHP file based sessions in your Init.php file (or elsewhere)? By default these files lock until the session is closed effectively only allowing one request to execute at a time.

    If so you need to close the session in your upload file using:

    session_write_close();
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 服务端控制goose报文控制块的发布问题
  • ¥15 学习指导与未来导向啊
  • ¥15 求多普勒频移瞬时表达式
  • ¥15 如果要做一个老年人平板有哪些需求
  • ¥15 k8s生产配置推荐配置及部署方案
  • ¥15 matlab提取运动物体的坐标
  • ¥15 人大金仓下载,有人知道怎么解决吗
  • ¥15 一个小问题,本人刚入门,哪位可以help
  • ¥30 python安卓开发
  • ¥15 使用R语言GD包一直不出结果