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();
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥100 在连接内网VPN时,如何同时保持互联网连接
  • ¥15 MATLAB中使用parfor,矩阵Removal的有效索引在parfor循环中受限制
  • ¥20 Win 10 LTSC 1809版本如何无损提升到20H1版本
  • ¥50 win10 LTSC 虚拟键盘不弹出
  • ¥30 关于PHP中POST获取数据的问题
  • ¥30 微信小程序请求失败,网页能正常带锁访问
  • ¥15 Python实现hog特征图可视化
  • ¥30 德飞莱51单片机实现C4炸弹
  • ¥50 CrossLink-LIF-MD6000 型 FPGA 的 CMOS 转 MIPI D-PHY IP 核功能使用异常
  • ¥15 proteus控制16x16LED点阵显示屏的设计