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);    }}
相关文章
相关标签/搜索