continue processing php after sending http response

后端 未结 12 795
旧时难觅i
旧时难觅i 2020-11-22 13:06

My script is called by server. From server I\'ll receive ID_OF_MESSAGE and TEXT_OF_MESSAGE.

In my script I\'ll handle incoming text and ge

相关标签:
12条回答
  • 2020-11-22 13:16

    I've seen a lot of responses on here that suggest using ignore_user_abort(true); but this code is not necessary. All this does is ensure your script continues executing before a response is sent in the event that the user aborts (by closing their browser or pressing escape to stop the request). But that's not what you're asking. You're asking to continue execution AFTER a response is sent. All you need is the following:

        // Buffer all upcoming output...
        ob_start();
    
        // Send your response.
        echo "Here be response";
    
        // Get the size of the output.
        $size = ob_get_length();
    
        // Disable compression (in case content length is compressed).
        header("Content-Encoding: none");
    
        // Set the content length of the response.
        header("Content-Length: {$size}");
    
        // Close the connection.
        header("Connection: close");
    
        // Flush all output.
        ob_end_flush();
        ob_flush();
        flush();
    
        // Close current session (if it exists).
        if(session_id()) session_write_close();
    
        // Start your background work here.
        ...
    

    If you're concerned that your background work will take longer than PHP's default script execution time limit, then stick set_time_limit(0); at the top.

    0 讨论(0)
  • 2020-11-22 13:17

    I know it's an old one, but possibly usefull at this point.

    With this answer i don't support the actual question but how to solve this problem correctly. Hope it helps other people to solve problems like this.

    I would suggest to use RabbitMQ or similar services and run the background workload using worker instances. There is a package called amqplib for php which does all the work for you to use RabbitMQ.

    Pro's:

    1. It's high performant
    2. Nicly structured and maintainable
    3. It's absolutly scalable with worker instances

    Neg's:

    1. RabbitMQ must be installed on the server, this can be a problem with some web hoster.
    0 讨论(0)
  • 2020-11-22 13:19

    I spent a few hours on this issue and I have come with this function which works on Apache and Nginx:

    /**
     * respondOK.
     */
    protected function respondOK()
    {
        // check if fastcgi_finish_request is callable
        if (is_callable('fastcgi_finish_request')) {
            /*
             * This works in Nginx but the next approach not
             */
            session_write_close();
            fastcgi_finish_request();
    
            return;
        }
    
        ignore_user_abort(true);
    
        ob_start();
        $serverProtocole = filter_input(INPUT_SERVER, 'SERVER_PROTOCOL', FILTER_SANITIZE_STRING);
        header($serverProtocole.' 200 OK');
        header('Content-Encoding: none');
        header('Content-Length: '.ob_get_length());
        header('Connection: close');
    
        ob_end_flush();
        ob_flush();
        flush();
    }
    

    You can call this function before your long processing.

    0 讨论(0)
  • 2020-11-22 13:22

    There is another approach and its worthwhile considering if you don't want to tamper with the response headers. If you start a thread on another process the called function wont wait for its response and will return to the browser with a finalized http code. You will need to configure pthread.

    class continue_processing_thread extends Thread 
    {
         public function __construct($param1) 
         {
             $this->param1 = $param1
         }
    
         public function run() 
         {
            //Do your long running process here
         }
    }
    
    //This is your function called via an HTTP GET/POST etc
    function rest_endpoint()
    {
      //do whatever stuff needed by the response.
    
      //Create and start your thread. 
      //rest_endpoint wont wait for this to complete.
      $continue_processing = new continue_processing_thread($some_value);
      $continue_processing->start();
    
      echo json_encode($response)
    }
    

    Once we execute $continue_processing->start() PHP wont wait for the return result of this thread and therefore as far as rest_endpoint is considered. It is done.

    Some links to help with pthreads

    • How can one use multi threading in PHP applications
    • http://php.net/manual/kr/pthreads.installation.php

    Good luck.

    0 讨论(0)
  • 2020-11-22 13:23

    I have something that can compressed and send the response and let other php code to execute.

    function sendResponse($response){
        $contentencoding = 'none';
        if(ob_get_contents()){
            ob_end_clean();
            if(ob_get_contents()){
                ob_clean();
            }
        }
        header('Connection: close');
        header("cache-control: must-revalidate");
        header('Vary: Accept-Encoding');
        header('content-type: application/json; charset=utf-8');
        ob_start();
        if(phpversion()>='4.0.4pl1' && extension_loaded('zlib') && GZIP_ENABLED==1 && !empty($_SERVER["HTTP_ACCEPT_ENCODING"]) && (strpos($_SERVER["HTTP_ACCEPT_ENCODING"], 'gzip') !== false) && (strstr($GLOBALS['useragent'],'compatible') || strstr($GLOBALS['useragent'],'Gecko'))){
            $contentencoding = 'gzip';
            ob_start('ob_gzhandler');
        }
        header('Content-Encoding: '.$contentencoding);
        if (!empty($_GET['callback'])){
            echo $_GET['callback'].'('.$response.')';
        } else {
            echo $response;
        }
        if($contentencoding == 'gzip') {
            if(ob_get_contents()){
                ob_end_flush(); // Flush the output from ob_gzhandler
            }
        }
        header('Content-Length: '.ob_get_length());
        // flush all output
        if (ob_get_contents()){
            ob_end_flush(); // Flush the outer ob_start()
            if(ob_get_contents()){
                ob_flush();
            }
            flush();
        }
        if (session_id()) session_write_close();
    }
    
    0 讨论(0)
  • 2020-11-22 13:25

    If you're using FastCGI processing or PHP-FPM, you can:

    session_write_close(); //close the session
    ignore_user_abort(true); //Prevent echo, print, and flush from killing the script
    fastcgi_finish_request(); //this returns 200 to the user, and processing continues
    
    // do desired processing ...
    $expensiveCalulation = 1+1;
    error_log($expensiveCalculation);
    

    Source: https://www.php.net/manual/en/function.fastcgi-finish-request.php

    PHP issue #68722: https://bugs.php.net/bug.php?id=68772

    0 讨论(0)
提交回复
热议问题