How to make asynchronous HTTP requests in PHP 4種PHP異步執行的經常使用方式

 

【是否等待返回就執行下一步】

How to make asynchronous HTTP requests in PHP - Stack Overflow https://stackoverflow.com/questions/124462/how-to-make-asynchronous-http-requests-in-phpphp

 

【I don't care about the response】html

Is there a way in PHP to make asynchronous HTTP calls? I don't care about the response, I just want to do something like file_get_contents(), but not wait for the request to finish before executing the rest of my code. This would be super useful for setting off "events" of a sort in my application, or triggering long processes.nginx

Any ideas?數據庫

The answer I'd previously accepted didn't work. It still waited for responses. This does work though, taken from How do I make an asynchronous GET request in PHP?apache






http - How do I make an asynchronous GET request in PHP? - Stack Overflow https://stackoverflow.com/questions/962915/how-do-i-make-an-asynchronous-get-request-in-php


function post_without_wait($url, $params) { foreach ($params as $key => &$val) { if (is_array($val)) $val = implode(',', $val); $post_params[] = $key.'='.urlencode($val); } $post_string = implode('&', $post_params); $parts=parse_url($url); $fp = fsockopen($parts['host'], isset($parts['port'])?$parts['port']:80, $errno, $errstr, 30); $out = "POST ".$parts['path']." HTTP/1.1\r\n"; $out.= "Host: ".$parts['host']."\r\n"; $out.= "Content-Type: application/x-www-form-urlencoded\r\n"; $out.= "Content-Length: ".strlen($post_string)."\r\n"; $out.= "Connection: Close\r\n\r\n"; if (isset($post_string)) $out.= $post_string; fwrite($fp, $out); fclose($fp); }

I wish to make a simple GET request to another script on a different server. How do I do this?編程

In one case, I just need to request an external script without the need for any output.瀏覽器

make_request('http://www.externalsite.com/script1.php?variable=45'); //example usage

In the second case, I need to get the text output.服務器

$output = make_request('http://www.externalsite.com/script2.php?variable=45');
echo $output; //string output

To be honest, I do not want to mess around with CURL as this isn't really the job of CURL. I also do not want to make use of http_get as I do not have the PECL extensions.swoole

Would fsockopen work? If so, how do I do this without reading in the contents of the file? Is there no other way?cookie

 

 



file_get_contents will do what you want

$output = file_get_contents('http://www.example.com/');
echo $output;

Edit: One way to fire off a GET request and return immediately.

Quoted from http://petewarden.typepad.com/searchbrowser/2008/06/how-to-post-an.html

function curl_post_async($url, $params)
{
    foreach ($params as $key => &$val) {
      if (is_array($val)) $val = implode(',', $val);
        $post_params[] = $key.'='.urlencode($val);
    }
    $post_string = implode('&', $post_params);

    $parts=parse_url($url);

    $fp = fsockopen($parts['host'],
        isset($parts['port'])?$parts['port']:80,
        $errno, $errstr, 30);

    $out = "POST ".$parts['path']." HTTP/1.1\r\n";
    $out.= "Host: ".$parts['host']."\r\n";
    $out.= "Content-Type: application/x-www-form-urlencoded\r\n";
    $out.= "Content-Length: ".strlen($post_string)."\r\n";
    $out.= "Connection: Close\r\n\r\n";
    if (isset($post_string)) $out.= $post_string;

    fwrite($fp, $out);
    fclose($fp);
}

What this does is open a socket, fire off a get request, and immediately close the socket and return.

 

4種PHP異步執行的經常使用方式_php技巧_腳本之家 https://www.jb51.net/article/76909.htm

4種PHP異步執行的經常使用方式

 更新時間:2015年12月24日 10:32:06   投稿:lijiao   

 
這篇文章主要介紹了4種PHP異步執行的經常使用方式,幫助你們更好地分析php異步調用方法,熟練掌握,感興趣的小夥伴們能夠參考一下
 

本文爲你們講述了php異步調用方法,分享給你們供你們參考,具體內容以下
客戶端與服務器端是經過HTTP協議進行鏈接通信,客戶端發起請求,服務器端接收到請求後執行處理,並返回處理結果。
有時服務器須要執行很耗時的操做,這個操做的結果並不須要返回給客戶端。但由於php是同步執行的,因此客戶端須要等待服務處理完才能夠進行下一步。
所以對於耗時的操做適合異步執行,服務器接收到請求後,處理完客戶端須要的數據就返回,再異步在服務器執行耗時的操做。
1.使用Ajax 與 img 標記
原理,服務器返回的html中插入Ajax 代碼或 img 標記,img的src爲須要執行的程序。
優勢:實現簡單,服務端無需執行任何調用
缺點:在執行期間,瀏覽器會一直處於loading狀態,所以這種方法並不算真正的異步調用。

?
1
2
$.get( "doRequest.php" , { name: "fdipzone" } );
<img src= "doRequest.php?name=fdipzone" >

2.使用popen
使用popen執行命令,語法:

?
1
2
3
// popen — 打開進程文件指針 
resource popen ( string $command , string $mode )
pclose(popen( 'php /home/fdipzone/doRequest.php &' , 'r' ));

優勢:執行速度快
缺點:

  • 1).只能在本機執行
  • 2).不能傳遞大量參數
  • 3).訪問量高時會建立不少進程

3.使用curl
設置curl的超時時間 CURLOPT_TIMEOUT 爲1 (最小爲1),所以客戶端須要等待1秒

?
1
2
3
4
5
6
7
8
9
10
11
<?php
$ch = curl_init();
$curl_opt = array (
   CURLOPT_RETURNTRANSFER,1,
   CURLOPT_TIMEOUT,1
);
curl_setopt_array( $ch , $curl_opt );
curl_exec( $ch );
curl_close( $ch );
?>

4.使用fsockopen
fsockopen是最好的,缺點是須要本身拼接header部分。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<?php
    
$param = array (
   'name' => 'fdipzone' ,
   'gender' => 'male' ,
   'age' =>30
);
    
doRequest( $url , $param );
    
function doRequest( $url , $param = array ()){
    
   $urlinfo = parse_url ( $url );
    
   $host = $urlinfo [ 'host' ];
   $path = $urlinfo [ 'path' ];
   $query = isset( $param )? http_build_query( $param ) : '' ;
    
   $port = 80;
   $errno = 0;
   $errstr = '' ;
   $timeout = 10;
    
   $fp = fsockopen ( $host , $port , $errno , $errstr , $timeout );
    
   $out = "POST " . $path . " HTTP/1.1\r\n" ;
   $out .= "host:" . $host . "\r\n" ;
   $out .= "content-length:" . strlen ( $query ). "\r\n" ;
   $out .= "content-type:application/x-www-form-urlencoded\r\n" ;
   $out .= "connection:close\r\n\r\n" ;
   $out .= $query ;
    
   fputs ( $fp , $out );
   fclose( $fp );
}
    
?>

注意:當執行過程當中,客戶端鏈接斷開或鏈接超時,都會有可能形成執行不完整,所以須要加上

?
1
2
ignore_user_abort(true); // 忽略客戶端斷開
set_time_limit(0);    // 設置執行不超時

以上就是php異步調用方法的詳細介紹,但願對你們的學習有所幫助。

 
 
深刻PHP異步執行的詳解_php實例_腳本之家 https://www.jb51.net/article/37774.htm
 
 更新時間:2013年06月03日 15:00:22
Web服務器執行一個PHP腳本,有時耗時很長才能返回執行結果,後面的腳本須要等待很長一段時間才能繼續執行。若是想實現只簡單觸發耗時腳本的執行而不等待執行結果就直接執行下一步操做,能夠經過fscokopen函數來實現。
PHP支持socket編程,fscokopen函數返回一個到遠程主機鏈接的句柄,能夠像使用fopen返回的句柄同樣,對它進行fwrite、fgets、fread等操做。使用fsockopen鏈接到本地服務器,觸發腳本執行,而後當即返回,不等待腳本執行完成,便可實現異步執行PHP的效果。
示例代碼以下:
複製代碼代碼以下:

<?
function triggerRequest($url, $post_data = array(), $cookie = array()){
        $method = "GET";  //經過POST或者GET傳遞一些參數給要觸發的腳本
        $url_array = parse_url($url); //獲取URL信息
        $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'];
        if(!empty($post_data)){
                $method = "POST";
        }
        $header = $method . " " . $getPath;
        $header .= " HTTP/1.1\r\n";
        $header .= "Host: ". $url_array['host'] . "\r\n "; //HTTP 1.1 Host域不能省略
        /*如下頭信息域能夠省略
        $header .= "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13 \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";
        if(!empty($cookie)){
                $_cookie = strval(NULL);
                foreach($cookie as $k => $v){
                        $_cookie .= $k."=".$v."; ";
                }
                $cookie_str =  "Cookie: " . base64_encode($_cookie) ." \r\n"; //傳遞Cookie
                $header .= $cookie_str;
        }
        if(!empty($post_data)){
                $_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數據的長度
                $post_str .= $_post."\r\n\r\n "; //傳遞POST數據
                $header .= $post_str;
        }
        fwrite($fp, $header);
        //echo fread($fp, 1024); //服務器返回
        fclose($fp);
        return true;
}   

這樣就能夠經過fsockopen()函數來觸發一個PHP腳本的執行,而後函數就會返回。 接着執行下一步操做了。
如今存在一個問題:當客戶端斷開鏈接後,也就是triggerRequest發送請求後,當即關閉了鏈接,那麼可能會引發服務器端正在執行的腳本退出。
在 PHP 內部,系統維護着鏈接狀態,其狀態有三種可能的狀況:
* 0 – NORMAL(正常)
* 1 – ABORTED(異常退出)
* 2 – TIMEOUT(超時)
當 PHP 腳本正常地運行 NORMAL 狀態時,鏈接爲有效。當客戶端中斷鏈接時,ABORTED 狀態的標記將會被打開。遠程客戶端鏈接的中斷一般是由用戶點擊 STOP 按鈕致使的。當鏈接時間超過 PHP 的時限(參閱 set_time_limit() 函數)時,TIMEOUT 狀態的標記將被打開。

能夠決定腳本是否須要在客戶端中斷鏈接時退出。有時候讓腳本完整地運行會帶來不少方便,即便沒有遠程瀏覽器接受腳本的輸出。默認的狀況是當遠程客戶端鏈接 中斷時腳本將會退出。該處理過程可由 php.ini 的 ignore_user_abort 或由 Apache .conf 設置中對應的"php_value ignore_user_abort"以及 ignore_user_abort() 函數來控制。若是沒有告訴 PHP 忽略用戶的中斷,腳本將會被中斷,除非經過 register_shutdown_function() 設置了關閉觸發函數。經過該關閉觸發函數,當遠程用戶點擊 STOP 按鈕後,腳本再次嘗試輸出數據時,PHP 將會檢測到鏈接已被中斷,並調用關閉觸發函數。

腳本也有可能被內置的腳本計時器中斷。默認的超時限制爲 30 秒。這個值能夠經過設置 php.ini 的 max_execution_time 或 Apache .conf 設置中對應的"php_value max_execution_time"參數或者 set_time_limit() 函數來更改。當計數器超時的時候,腳本將會相似於以上鍊接中斷的狀況退出,先前被註冊過的關閉觸發函數也將在這時被執行。在該關閉觸發函數中,能夠經過調用 connection_status() 函數來檢查超時是否致使關閉觸發函數被調用。若是超時致使了關閉觸發函數的調用,該函數將返回 2。

須要注意的一點是 ABORTED 和 TIMEOUT 狀態能夠同時有效。這在告訴 PHP 忽略用戶的退出操做時是可能的。PHP 將仍然注意用戶已經中斷了鏈接但腳本仍然在運行的狀況。若是到了運行的時間限制,腳本將被退出,設置過的關閉觸發函數也將被執行。在這時會發現函數 connection_status() 返回 3。
因此還在要觸發的腳本中指明:
複製代碼代碼以下:

<?
    ignore_user_abort(TRUE);//若是客戶端斷開鏈接,不會引發腳本abort
   set_time_limit(0);//取消腳本執行延時上限
  或使用:
<?
    register_shutdown_function(callback fuction[, parameters]);//註冊腳本退出時執行的函數

 

 

http://php.net/manual/en/class.swoole-async.php

 

The Swoole\Async class

(PHP 5 >= 5.2.0, PHP 7, PECL swoole >= 1.9.0)

Introduction

 

Class synopsis

 
Swoole\Async {
/* Methods */
public static void dnsLookup ( string $hostname , callable $callback )
public static bool read ( string $filename , callable $callback [, integer $chunk_size [, integer $offset ]] )
public static void readFile ( string $filename , callable $callback )
public static void set ( array $settings )
public static void write ( string $filename , string $content [, integer $offset [, callable $callback ]] )
public static void writeFile ( string $filename , string $content [, callable $callback [, string $flags ]] )
}

Table of Contents

 

php 不等待返回的實現方法(異步調用) - 與f - 博客園 https://www.cnblogs.com/fps2tao/p/7900677.html

PHP異步執行的經常使用方式常見的有如下幾種,能夠根據各自優缺點進行選擇:

1.客戶端頁面採用AJAX技術請求服務器
優勢
:最簡單,也最快,就是在返回給客戶端的HTML代碼中,嵌入AJAX調用,或者,嵌入一個img標籤,src指向要執行的耗時腳本。
缺點:通常來講Ajax都應該在onLoad之後觸發,也就是說,用戶點開頁面後,就關閉,那就不會觸發咱們的後臺腳本了。
而使用img標籤的話,這種方式不能稱爲嚴格意義上的異步執行。用戶瀏覽器會長時間等待php腳本的執行完成,也就是用戶瀏覽器的狀態欄一直顯示還在load。
固然,還可使用其餘的相似原理的方法,好比script標籤等等。

2.popen()函數
該函數打開一個指向進程的管道,該進程由派生給定的 command 命令執行而產生。打開一個指向進程的管道,該進程由派生給定的 command 命令執行而產生。
因此能夠經過調用它,但忽略它的輸出。使用代碼以下:

pclose(popen("/home/xinchen/backend.php &", 'r'));

優勢:避免了第一個方法的缺點,而且也很快。
缺點:這種方法不能經過HTTP協議請求另外的一個WebService,只能執行本地的腳本文件。而且只能單向打開,沒法穿大量參數給被調用腳本。而且若是,訪問量很高的時候,會產生大量的進程。若是使用到了外部資源,還要本身考慮競爭。

3.CURL擴展
CURL是一個強大的HTTP命令行工具,能夠模擬POST/GET等HTTP請求,而後獲得和提取數據,顯示在"標準輸出"(stdout)上面。代碼以下:

複製代碼
$ch = curl_init();
 
$curl_opt = array(CURLOPT_URL, 'http://www.example.com/backend.php',
                            CURLOPT_RETURNTRANSFER, 1,
                            CURLOPT_TIMEOUT, 1,);
curl_setopt_array($ch, $curl_opt); 
curl_exec($ch);
curl_close($ch);
複製代碼

缺點如你問題中描述的同樣,因爲使用CURL須要設置CUROPT_TIMEOUT爲1(最小爲1,鬱悶)。也就是說,客戶端至少必須等待1秒鐘。(等不等帶1秒沒有驗證,我感受不用吧)

4.fscokopen()函數
fsockopen支持socket編程,可使用fsockopen實現郵件發送等socket程序等等,使用fcockopen須要本身手動拼接出header部分
能夠參考: http://cn.php.net/fsockopen/
使用示例以下:

複製代碼
$fp = fsockopen("www.34ways.com", 80, $errno, $errstr, 30);
if (!$fp) {
    echo "$errstr ($errno)<br />\n";
} else {
    $out = "GET /index.php  / HTTP/1.1\r\n";
    $out .= "Host: www.34ways.com\r\n";
    $out .= "Connection: Close\r\n\r\n";
  
    fwrite($fp, $out);
    /*忽略執行結果
    while (!feof($fp)) {
        echo fgets($fp, 128);
    }*/
    fclose($fp);
}
複製代碼

因此總結來講,fscokopen()函數應該能夠知足您的要求。能夠嘗試一下。

1
fscokopen的問題和popen 同樣,併發很是多時會產生不少子進程,當達到apache的鏈接限制數時,就會掛掉,我問題已經說了這種狀況。

  

PHP 自己沒有多線程的東西,但能夠曲線的辦法來造就出一樣的效果,好比多進程的方式來達到異步調用,只限於命令模式。還有一種更簡單的方式,可用於 Web 程序中,那就是用fsockopen()、fputs() 來請求一個 URL 而無需等待返回,若是你在那個被請求的頁面中作些事情就至關於異步了。

關鍵代碼以下:

$fp=fsockopen('localhost',80,&$errno,&$errstr,5);
if(!$fp){
    echo "$errstr ($errno)<br />\n";
}
fputs($fp,"GET another_page.php?flag=1\r\n");
fclose($fp);

上面的代碼向頁面 another_page.php 發送完請求就無論了,用不着等待請求頁面的響應數據,利用這一點就能夠在被請求的頁面 another_page.php 中異步的作些事情了。

好比,一個很切實的應用,某個 Blog 在每 Post 了一篇新日誌後須要給全部它的訂閱者發個郵件通知。若是按照一般的方式就是:

1
2
日誌寫完 -> 點提交按鈕 -> 日誌插入到數據庫 -> 發送郵件通知 ->
告知撰寫者發佈成功

  

那麼做者在點提交按鈕到看到成功提示之間可能會等待很常時間,基本是在等郵件發送的過程,好比鏈接郵件服務異常、或器緩慢或是訂閱者太多。而其實是無論郵件發送成功與否,保證日誌保存成功基本可接受的,因此等待郵件發送的過程是很不經濟的,這個過程可異步來執行,而且郵件發送的結果不太關心或以日誌形式記錄備查。

改進後的流程就是:

1
2
3
日誌寫完 -> 點提交按鈕 -> 日誌插入到數據庫 --->
告知撰寫者發佈成功
└ 發送郵件通知 -> [記下日誌]

  

用個實際的程序來測試一下,有兩個 php,分別是 write.php 和 sendmail.php,在 sendmail.php 用 sleep(seconds) 來模擬程序執行使用時間。

write.php,執行耗時 1 秒

複製代碼
<?php 
 
function asyn_sendmail() {
    $fp=fsockopen('localhost',80,&$errno,&$errstr,5);
    if(!$fp){
        echo "$errstr ($errno)<br />\n";
    }
    sleep(1);
    fputs($fp,"GET /sendmail.php?param=1\r\n"); #請求的資源 URL 必定要寫對
    fclose($fp);
} 
 
echo time().'<br>';
echo 'call asyn_sendmail<br>';
asyn_sendmail();
echo time().'<br>';
?>
sendmail.php,執行耗時 10 秒

<?php
//sendmail();
//sleep 10 seconds
sleep(10);
fopen('C:\'.time(),'w');
?>
複製代碼

經過頁面訪問 write.php,頁面輸出:

1272472697 call asyn_sendmail
1272472698

而且在 C:\ 生成文件:

1272472708

從上面的結果可知 sendmail.php 花費至少 10 秒,但不會阻塞到 write.php 的繼續往下執行,代表這一過程是異步的。

 

 

 

 php fsockopen()方法,簡化,異步非阻塞調用 - CSDN博客 https://blog.csdn.net/qq_22823581/article/details/77712987

 

在項目中遇到一個問題,就是php是同步的讀取下來的,若是一個方法請求的時間長了一點, 那麼整個程序走下去將會遇到阻塞,如今我想觸發這個方法,可是又不影響我下下面的程序正常的走下去。查了一上午的方法, 就這個函數比較靠譜,可是會比較low 一點, 由於直接是經過url尋找咱們要觸發的方法。

<?phpfunction _sock($url) {    $host = parse_url($url,PHP_URL_HOST);    $port = parse_url($url,PHP_URL_PORT);    $port = $port ? $port : 80;    $scheme = parse_url($url,PHP_URL_SCHEME);    $path = parse_url($url,PHP_URL_PATH);    $query = parse_url($url,PHP_URL_QUERY);    if($query) $path .= '?'.$query;    if($scheme == 'https') {        $host = 'ssl://'.$host;    }    $fp = fsockopen($host,$port,$error_code,$error_msg,1);    if(!$fp) {        return array('error_code' => $error_code,'error_msg' => $error_msg);    }    else {        stream_set_blocking($fp,true);//開啓了手冊上說的非阻塞模式        stream_set_timeout($fp,1);//設置超時        $header = "GET $path HTTP/1.1\r\n";        $header.="Host: $host\r\n";        $header.="Connection: close\r\n\r\n";//長鏈接關閉        fwrite($fp, $header);        usleep(1000); // 這一句也是關鍵,若是沒有這延時,可能在nginx服務器上就沒法執行成功        fclose($fp);        return array('error_code' => 0);    }}
相關文章
相關標籤/搜索