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();
    
    点赞 打赏 评论

相关推荐 更多相似问题