Dive into the details of PHP asynchronous execution

  • 2020-06-03 06:02:45
  • OfStack

The Web server executes one PHP script, sometimes taking a long time to return the execution results, and later scripts wait a long time to continue. If you want to simply trigger the execution of a time-consuming script and simply execute the next step without waiting for the result, you can do so through the fscokopen function.
PHP supports socket programming. The fscokopen function returns a handle to a remote host connection and can be operated on like the handle returned by fopen, fwrite, fgets, fread, etc. Use fsockopen to connect to the local server, trigger the script execution, and then return immediately to execute PHP asynchronously without waiting for the script execution to complete.
The sample code is as follows:

function triggerRequest($url, $post_data = array(), $cookie = array()){
        $method = "GET";  // through POST or GET pass 1 Some parameters to the script to be triggered 
        $url_array = parse_url($url); // To obtain URL information 
        $port = isset($url_array['port'])? $url_array['port'] : 80;  
        $fp = fsockopen($url_array['host'], $port, $errno, $errstr, 30);
        if (!$fp) {
                return FALSE;
        $getPath = $url_array['path'] ."?". $url_array['query'];
                $method = "POST";
        $header = $method . " " . $getPath;
        $header .= " HTTP/1.1\r\n";
        $header .= "Host: ". $url_array['host'] . "\r\n "; //HTTP 1.1 Host Domain cannot be omitted 
        /* The following header fields can be omitted 
        $header .= "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv: Gecko/20080311 Firefox/ \r\n";
        $header .= "Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,q=0.5 \r\n";
        $header .= "Accept-Language: en-us,en;q=0.5 ";
        $header .= "Accept-Encoding: gzip,deflate\r\n";
        $header .= "Connection:Close\r\n";
                $_cookie = strval(NULL);
                foreach($cookie as $k => $v){
                        $_cookie .= $k."=".$v."; ";
                $cookie_str =  "Cookie: " . base64_encode($_cookie) ." \r\n"; // pass Cookie
                $header .= $cookie_str;
                $_post = strval(NULL);
                foreach($post_data as $k => $v){
                        $_post .= $k."=".$v."&";
                $post_str  = "Content-Type: application/x-www-form-urlencoded\r\n"; 
                $post_str .= "Content-Length: ". strlen($_post) ." \r\n"; //POST Length of data 
                $post_str .= $_post."\r\n\r\n "; // pass POST data 
                $header .= $post_str;
        fwrite($fp, $header);
        //echo fread($fp, 1024); // Server return 
        return true;

This will trigger the execution of an PHP script via the fsockopen() function and the function will return. The next step is performed.
There is a problem: when the client disconnects, triggerRequest immediately closes the connection after sending the request, it may cause the script that the server is executing to exit.
Within PHP, the system maintains the connection state, which has three possible states:
* 0 by NORMAL (normal)
* 1 ABORTED (exception exit)
* 2 WUNDER TIMEOUT (timeout)
The connection is valid when the PHP script is running NORMAL normally. When the client disconnects, the flag for the ABORTED status will be opened. A remote client connection break is usually caused by the user clicking the STOP button. When the connection time exceeds the PHP time limit (see the set_time_limit() function), the flag for the TIMEOUT state is turned on.

You can decide whether the script needs to exit when the client breaks the connection. Sometimes it is convenient to have the script run in its entirety, even if no remote browser accepts the output of the script. By default, the script will exit when the remote client connection is broken. This process can be controlled by ignore_user_abort of php.ini or by the corresponding "php_value ignore_user_abort" and ignore_user_abort() function in the Apache.conf setting. If PHP is not told to ignore the user's interrupt, the script will be interrupted unless the close trigger function is set through register_shutdown_function(). With this close trigger function, when the remote user clicks the STOP button and the script tries to output data again, PHP will detect that the connection has been interrupted and call the close trigger function.

Scripts can also be interrupted by built-in script timers. The default timeout limit is 30 seconds. This value can be changed by setting the max_execution_time or Apache.conf setting to the corresponding "php_value max_execution_time" parameter or the set_time_limit() function. When the counter times out, the script exits similar to the connection break above, and the previously registered close trigger function is executed. In this close trigger function, you can check whether the timeout caused the close trigger function to be called by calling the connection_status() function. If the timeout resulted in the closing of the call to the triggering function, the function returns 2.

One thing to note is that the ABORTED and TIMEOUT states can work together. This is possible when telling PHP to ignore the user's exit operation. PHP will still notice if the user has broken the connection but the script is still running. If the run time limit is reached, the script is exited and the set close trigger function is executed. At this point you see that the function connection_status() returns 3.
Therefore, in the script to be triggered, specify:

    ignore_user_abort(TRUE);// If the client is disconnected, the script will not be caused abort
   set_time_limit(0);// Remove the upper limit of script execution latency 
 Or use :
    register_shutdown_function(callback fuction[, parameters]);// Register the function that executes when the script exits 

Related articles: