PHP to get long running process progress dynamically

English 简体中文 繁体中文 ภาษาไทย Tiếng Việt
Summary

Web applications frequently face challenges in providing dynamic progress updates for long-running backend processes, often leading to a poor user experience due to HTTP's stateless nature and the absence of multithreading in server-side scripting. A practical solution involves simulating real-time progress using PHP and jQuery AJAX. This approach utilizes a backend PHP script to execute the long process, periodically updating a session variable to store its progress, critically employing `session_write_close()` to release the session lock. Concurrently, a frontend script initiates the long process and then repeatedly polls a separate PHP endpoint via AJAX to fetch and display the current progress, keeping users informed. This method effectively enhances user experience by dynamically showing the status of extended operations.

บ่อยครั้งในเว็บแอปพลิเคชัน เราอาจมีคำขอไปยังระบบแบ็กเอนด์ซึ่งอาจทำให้เกิดกระบวนการทำงานที่ใช้เวลานาน เช่น การค้นหาข้อมูลจำนวนมหาศาลหรือกระบวนการฐานข้อมูลที่ใช้เวลานาน จากนั้นเว็บเพจฝั่งหน้าอาจหยุดทำงานและรอให้กระบวนการเสร็จสิ้น ในระหว่างกระบวนการนี้ หากเราสามารถให้ข้อมูลบางอย่างแก่ผู้ใช้เกี่ยวกับความคืบหน้าของกระบวนการแบ็กเอนด์ ก็อาจช่วยปรับปรุงประสบการณ์ของผู้ใช้ได้ น่าเสียดายที่ในเว็บแอปพลิเคชัน สิ่งนี้ดูเหมือนจะเป็นงานที่ไม่ง่ายนัก เนื่องจากภาษาสคริปต์เว็บไม่รองรับการทำงานแบบมัลติเธรดและ HTTP เป็นแบบไร้สถานะ  ตอนนี้เราสามารถใช้ AJAX เพื่อจำลองกระบวนการแบบเรียลไทม์ได้ วันนี้เราจะใช้ PHP+jQuery เพื่อจำลองกระบวนการในการรับความคืบหน้าของกระบวนการทำงานที่ใช้เวลานานแบบไดนามิก

เราต้องการไฟล์สามไฟล์:

<?php
    //long_process.php
    for($i=1;$i<=10;$i++){
        session_start();
        $_SESSION["progress"]=$i;
        session_write_close();
        sleep(1);
    }
?>


โค้ดข้างต้นคือ long_process.php ซึ่งจำลองกระบวนการทำงานที่ใช้เวลานาน จริงๆ แล้วมันมีลูป for ซึ่งจะวนลูปจาก 1 ถึง 10 และจะหยุดทำงานหนึ่งวินาทีหลังจากแต่ละลูป สิ่งสำคัญที่สุดที่นี่คือเราใช้ตัวแปรเซสชัน $_SESSION["progress"] เพื่อเก็บความคืบหน้า และอย่าลืมใช้ session_write_close() หลังจากแต่ละลูป เนื่องจากข้อมูลเซสชันมักจะถูกเก็บไว้หลังจากสคริปต์ของคุณสิ้นสุดลงโดยไม่จำเป็นต้องเรียกใช้ session_write_close() แต่เนื่องจากข้อมูลเซสชันถูกล็อกเพื่อป้องกันการเขียนพร้อมกัน สคริปต์เพียงสคริปต์เดียวเท่านั้นที่สามารถทำงานกับเซสชันได้ในแต่ละครั้ง เมื่อใช้เฟรมเซ็ตพร้อมกับเซสชัน คุณจะพบว่าเฟรมโหลดทีละเฟรมเนื่องจากการล็อกนี้ คุณสามารถลดเวลาที่ใช้ในการโหลดเฟรมทั้งหมดได้โดยการสิ้นสุดเซสชันทันทีที่การเปลี่ยนแปลงตัวแปรเซสชันทั้งหมดเสร็จสิ้น

ไฟล์อีกไฟล์หนึ่งคือ progress.php

<?php
    //progress.php
    session_start();
    echo $_SESSION["progress"];
?>

สิ่งที่มันทำนั้นง่ายมาก เพียงแค่แสดงความคืบหน้าไปยังไคลเอนต์ ตัวแปรความคืบหน้านี้คือตัวแปรเซสชันที่อัปเดตใน long_process.php

ไฟล์ PHP ไฟล์สุดท้าย:

<script type="text/javascript">
    //Start the long running process
    $.ajax({
        url: 'long_process.php',
        success: function(data) {
        }
    });
    //Start receiving progress
    function getProgress(){
        $.ajax({
            url: 'progress.php',
            success: function(data) {
                $("#progress").html(data);
                if(data<10){
                    getProgress();
                }
            }
        });
    }
    getProgress();
</script>
<div id="progress"></div>

โค้ดข้างต้นมีเพียงโค้ดที่อยู่ภายใน (ฉันละเว้นโค้ดที่เหลือ) และจริงๆ แล้วเป็นจุดเริ่มต้นของการจำลอง มันใช้ AJAX เพื่อส่งคำขอสองคำขอไปยังเซิร์ฟเวอร์ คำขอหนึ่งคือการเริ่มต้นกระบวนการทำงานที่ใช้เวลานาน และอีกคำขอหนึ่งคือการสอบถามเซิร์ฟเวอร์เพื่อรับความคืบหน้า และหลังจากได้รับความคืบหน้าแล้ว มันจะอัปเดตความคืบหน้าบนหน้าเว็บ

แน่นอนว่ามีวิธีอื่นๆ ในการจัดเก็บตัวแปรความคืบหน้า เช่น ฐานข้อมูลหรือไฟล์ xml เป็นต้น คุณสามารถเลือกวิธีที่คุณต้องการหรือวิธีที่คุณคิดว่ามีประสิทธิภาพที่สุด นอกจากนี้ นอกเหนือจากโค้ด PHP บริสุทธิ์แล้ว คุณยังสามารถใช้แฟลชหรือแอปเพล็ต Java เพื่อประมวลผลและสอบถามกระบวนการทำงานที่ใช้เวลานานผ่าน TCP หรือ UDP ซึ่งเว็บไซต์จำนวนมากใช้

หากคุณมีวิธีที่ดีกว่านี้ คุณสามารถแบ่งปันกับเราได้

PHP AJAX DEMO PROGRESS LONG PROCESS

  RELATED

  COMMENTS

10
Yongd
Apr 17, 2014 at 9:27 am

Thank you,this's very helpful to me!

Pi Ke
Apr 17, 2014 at 9:54 am

It's my pleasure

Alexander Avakov
Feb 17, 2015 at 6:03 am

Nice tutorial. Thank you!

alea123
May 7, 2015 at 2:22 am

rly nice.. thank you!

samas
Jun 23, 2015 at 2:14 am

nice article, care to put up a complete working demo... full source code which can be easily adapted...?

verjas
Aug 21, 2015 at 2:51 am

I've just tested it on a project.

Works like a charm! Good job! 

Patrick
Nov 25, 2015 at 8:40 am

Very nice!!! Saved me hours!

Maksim Pol
Jan 10, 2016 at 2:55 am

It sometimes starts wrong. After page refresh, progress percent stays, but script working in background. If i make refresh again, then will run 2 scripts at one time. 

Anonymous
Jul 19, 2020 at 4:04 am

I had this similar issue.

I solved it by;

1. If() statement to prevent the long running script starting when the session variables already exist.

2. Unset() the session variables when the long script is complete and the last Ajax request has been called.

Maksim Pol
Jan 10, 2016 at 2:55 am

How it can be fixed? Anyway, thanks for the tutorial. :)