AJAX continous response of PHP script output

白昼怎懂夜的黑 提交于 2021-01-27 20:30:32

问题


I have problem with AJAX response of my PHP script...

I've created "Status" div, where I want to output response of PHP script. It works good, but the response shows up only, when whole script finishes, and I would like to output each echo "live"..

Here are my files:

form.php

<!-- left column -->
<div class="col-md-6">
    <!-- general form elements -->
    <div class="card card-primary">
        <div class="card-header">
            <h3 class="card-title"><?php echo $xmlData->name ?></h3>
        </div>
        <!-- /.card-header -->
        <!-- form start -->
        <form id="upload_form" enctype="multipart/form-data" method="post">
            <div class="card-body">
                <div class="form-group">
                    <label for="debFile">Deb file</label>
                    <span id="debMSG"></span>
                    <div class="input-group">
                        <div class="custom-file">
                            <input name="debFile" type="file" class="custom-file-input" id="debFile">
                            <label class="custom-file-label" for="debFile">Choose .deb file</label>
                        </div>
                    </div>
                </div>
                <div class="form-group">
                    <label for="version">Version</label>
                    <input type="text" name="version" id="version" class="form-control" value="<?php echo ver_up($xmlData->changelogs->change->version); ?>">
                </div>
                <div class="form-group">
                    <label for="log">Log</label>
                    <input type="text" name="log" id="log" class="form-control" value="Bug fix">
                </div>
                <div class="form-check">
                    <input name="tweet" type="checkbox" class="form-check-input" id="tweet" value="1">
                    <label class="form-check-label" for="tweet">Auto-post on Twitter</label>
                </div>
            </div>
            <!-- /.card-body -->

            <div class="card-footer">
                <button id="submit" name="upload" type="submit" class="btn btn-primary">Update</button>
            </div>
        </form>
    </div>
    <!-- /.card -->
</div>
<!-- Status -->
<div id="status" class="col-md-6" style="display:none;">
    <div class="card card-default">
        <div class="card-header">
            <h3 class="card-title">Status:</h3>
        </div>
        <div class="alert alert-default">
            <ul id="output" class="list-group"></ul>
        </div>
    </div>
</div>
<!--/.col (right) -->

ajax in form.php

<script type="text/javascript">
$(document).ready(function () {
    bsCustomFileInput.init();

    const Toast = Swal.mixin({
        toast: true,
        position: 'top-end',
        showConfirmButton: false,
        timer: 5000
    });

    $(document).on('submit', '#upload_form', function(event){
        event.preventDefault();

        if($('#debFile').val() == '')
        {
            $('#debMSG').html('<div class="alert alert-danger">Enter .deb file!</div>');
            $('#debMSG').show();
            setTimeout(function() {
                $('#debMSG').fadeOut('fast');
            }, 5000);
            return false;
        }
        else
        {

            $.ajax({
                type: 'POST',
                url: 'scripts/test.php',
                data: new FormData(this),
                // async: true,
                cache: false,
                processData: false,
                contentType: false,
                beforeSend:function()
                {
                    $('#debMSG').hide();
                    $('#submit').attr('disabled', 'disabled');
                    // $('#status').fadeIn('slow');
                }
            })
            .done(function(data) {
                // console.log(data);
                $('#output').append(data);
                $('#status').fadeIn('slow');
                // if(!data.success){
                //  $('#submit').removeClass('btn-primary').addClass('btn-danger');
                //  $('#submit').attr('disabled', false);
                //  $('#submit').removeAttr('name type');
                //  $('#submit').attr('onClick', 'location.reload();');
                //  $('#submit').html('Reload');
                //  Toast.fire({
                //      icon: 'error',
                //      title: 'There was an error while updating tweak!'
                //  })
                // } else {
                    $('#submit').removeClass('btn-primary').addClass('btn-success');
                    $('#submit').attr('disabled', false);
                    $('#submit').removeAttr('name type');
                    $('#submit').attr('onClick', 'window.location.href = "manage-packages.php";');
                    $('#submit').html('Finish');
                    Toast.fire({
                        icon: 'success',
                        title: 'Tweak has been successfully updated!'
                    })
                // }
            })
            .fail(function(data) {
                console.log(data);
                $('#output').append("There was an error while updating tweak!");
                // $('#output').removeClass('alert-success').addClass('alert-danger');
                $('#status').fadeIn('slow');
                $('#submit').removeClass('btn-primary').addClass('btn-danger');
                $('#submit').attr('disabled', false);
                $('#submit').removeAttr('name type');
                $('#submit').attr('onClick', 'location.reload();');
                $('#submit').html('Reload');
                Toast.fire({
                    icon: 'error',
                    title: 'There was an error while updating tweak!'
                })
            });
        }
    });
});
</script>

test.php

<?php

header('Content-type: text/html; charset=utf-8');

require_once("../../src/config-ssh.php");
require_once("../../src/functions.php");

$deb_dir = "/var/www/html/debs/";
$repo_dir = "/var/www/html/";

function output($val) {
    echo nl2br ($val);
    flush();
    ob_flush();
    sleep(1);
}

try {
    if (isset($_FILES["debFile"]["name"])) {
        $debFile = $_FILES["debFile"]["tmp_name"];
        $deb_file = $deb_dir . basename($_FILES["debFile"]["name"]);

        if (!file_exists($deb_file)) {
            output("<li class=\"list-group-item list-group-item-success\">DEB file \"". basename( $_FILES["debFile"]["name"]). "\" has been uploaded.</li>");
        } else {
            throw new Exception("<li class=\"list-group-item list-group-item-danger\">DEB file \"". basename( $_FILES["debFile"]["name"]). "\" already exists!</li>");
        }
    } else {
        throw new Exception("<li class=\"list-group-item list-group-item-danger\">You didn't choose any DEB file!</li>");
    }

    preg_match('/(.*)_(.*)_(.*)\.deb/', basename($_FILES["debFile"]["name"]), $deb_reg);
    $dirname = $deb_reg[1];
    $prev_ver = ver_down($deb_reg[2]);
    $exten = $deb_reg[3] . ".deb";
    $prev_deb_name = $dirname."_".$prev_ver."_".$exten;
    $prev_deb = $deb_dir . $prev_deb_name;

    if (isset($_POST['version']) && isset($_POST['log'])) {
        output("<li class=\"list-group-item list-group-item-success\">Values were added to XML!</li>");
    }

    if (file_exists($prev_deb)) {
        output("<li class=\"list-group-item list-group-item-success\">Previous version of DEB file (\"". $prev_deb_name . "\") was deleted!</li>");
    } else {
        throw new Exception("<li class=\"list-group-item list-group-item-danger\">DEB file \"". $prev_deb_name . "\" wasn't deleted!</li>");
    }


    // Run a command
    output("<li class=\"list-group-item list-group-item-info\">Running Repo update script...</li>");
        output("<li class=\"list-group-item list-group-item-success\">Script finished successfully.</li>");

    // Auto-post Tweet
    if (isset($_POST['tweet'])) {
        output("$msg");
        output("<li class=\"list-group-item list-group-item-success\">Tweet has been successfully posted.</li>");
    }

    exit();
}

catch( Exception $e ) {
    $message = $e->getMessage();

    die( "ERROR: " . $message );
}

?>

Finally, it prints this status output:

I've already tried several tutorials, but none of them are working for this...

Thanks for your advices!


回答1:


You need to bind a handler to the progress event of XmlHttpRequest object. jQuery doesn't provide a native interface to do this, but if you still want to do your AJAX call with jQuery instead of using XmlHttpRequest object directly, you can alter the underlying XmlHttpRequest object with the xhr callback function adding your handler this way:

$.ajax({
    ...
    xhr: function() {
        // get the native XmlHttpRequest object
        const xhr = $.ajaxSettings.xhr();
        // set the onprogress event handler
        xhr.onprogress = function() {
            // replace the '#output' element inner HTML with the received part of the response
            $('#output').html(xhr.responseText);
        }
        return xhr;
    }
})
.done(function(data) {
    ...
})
.fail(function(data) {
    ...
});

It is quite hard to figure out from the current version of XMLHttpRequest standard, but the archived one says that this event is fired about every 50ms or for every byte received, whichever is least frequent.

The other changes you should do to your javascript code are

  • uncomment the $('#status').fadeIn('slow'); line in the beforeSend function and remove it from the other functions;
  • remove the $('#output').append(data); line from the done event handler function, all the received data should be already injected via the onprogress handler function.

The last but not least part is about buffering. I assume you are using nginx with the PHP-FPM since you add the nginx tag to your question. You already use flush() and ob_flush() PHP functions, and you are right, you need both of them in order to flush the PHP buffers. However there is one more buffering mechanism - an nginx itself. You can turn off nginx FastCGI buffering completely with the fastcgi_buffering off; directive, but it doesn't look like a good idea. Fortunately, nginx allows to turn off response buffering via the special X-Accel-Buffering header, so your AJAX PHP handler should start with

<?php

header('Content-type: text/html; charset=utf-8');
header('X-Accel-Buffering: no');

...


来源:https://stackoverflow.com/questions/64680445/ajax-continous-response-of-php-script-output

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!