fast cgi client
PHP fast cgi client使用FASTCGI协议同步向PHP-FPM发送请求(a)。
该库基于Pierrick Charron的PHP-Fastcgi-Client的工作,并已将其移植和现代化为最新的PHP版本,并具有一些用于处理多个请求(以循环)和单位和集成测试的功能。
这是最新版本的文档。
请查看ChangElog中不兼容的更改(BC断裂)。
请参阅以下链接以获取早期版本:
- php> = 7.0(eol)v1.0.0,v1.0.1,v1.1.0,v1.2.0,v1.3.0,v1.4.0,v1.4.0,v1.4.1,v1.4.4.2
- PHP >= 7.1 v2.0.0, v2.0.1, v2.1.0, v2.2.0, v2.3.0, v2.4.0, v2.4.1, v2.4.2, v2.4.3, v2.5.0, v2.6.0, v2.7.0, v2.7.1, v2.7.2, v3.0.0-alpha, v3.0.0-beta, v3.0.0, v3.0.1, v3.1.0,v3.1.1,v3.1.2,v3.1.3,v3.1.4,v3.1.5
在此博客文章中阅读有关v2.6.0的旅程和变化的更多信息。
您可以在我相关的博客文章中找到一个实验用例:
- 实验异步PHP卷。 1
- 实验异步PHP卷。 2
您还可以在SpeakerDeck.com上找到有关此项目的谈话的幻灯片。
安装
composer require hollodotme/fast-cgi-client用法 - 连接
该库支持两种连接到FastCGI服务器的类型:
- 通过网络插座
- 通过Unix域插座
创建网络插座连接
declare (strict_types= 1 );
namespace YourVendor YourProject ;
use hollodotme FastCGI SocketConnections NetworkSocket ;
$ connection = new NetworkSocket (
' 127.0.0.1 ' , # Hostname
9000 , # Port
5000 , # Connect timeout in milliseconds (default: 5000)
5000 # Read/write timeout in milliseconds (default: 5000)
);创建一个UNIX域插座连接
declare (strict_types= 1 );
namespace YourVendor YourProject ;
use hollodotme FastCGI SocketConnections UnixDomainSocket ;
$ connection = new UnixDomainSocket (
' /var/run/php/php7.3-fpm.sock ' , # Socket path
5000 , # Connect timeout in milliseconds (default: 5000)
5000 # Read/write timeout in milliseconds (default: 5000)
);用法 - 单个请求
以下示例假设/path/to/target/script.php的内容看起来像这样:
declare (strict_types= 1 );
sleep (( int )( $ _REQUEST [ ' sleep ' ] ?? 0 ));
echo $ _REQUEST [ ' key ' ] ?? '' ;同步发送请求
declare (strict_types= 1 );
namespace YourVendor YourProject ;
use hollodotme FastCGI Client ;
use hollodotme FastCGI Requests PostRequest ;
use hollodotme FastCGI SocketConnections NetworkSocket ;
$ client = new Client ();
$ connection = new NetworkSocket ( ' 127.0.0.1 ' , 9000 );
$ content = http_build_query ([ ' key ' => ' value ' ]);
$ request = new PostRequest ( ' /path/to/target/script.php ' , $ content );
$ response = $ client -> sendRequest ( $ connection , $ request );
echo $ response -> getBody (); # prints
value
异步发送请求(开火和忘记)
declare (strict_types= 1 );
namespace YourVendor YourProject ;
use hollodotme FastCGI Client ;
use hollodotme FastCGI Requests PostRequest ;
use hollodotme FastCGI SocketConnections NetworkSocket ;
$ client = new Client ();
$ connection = new NetworkSocket ( ' 127.0.0.1 ' , 9000 );
$ content = http_build_query ([ ' key ' => ' value ' ]);
$ request = new PostRequest ( ' /path/to/target/script.php ' , $ content );
$ socketId = $ client -> sendAsyncRequest ( $ connection , $ request );
echo " Request sent, got ID: { $ socketId }" ;在发送异步请求后阅读响应
declare (strict_types= 1 );
namespace YourVendor YourProject ;
use hollodotme FastCGI Client ;
use hollodotme FastCGI Requests PostRequest ;
use hollodotme FastCGI SocketConnections NetworkSocket ;
$ client = new Client ();
$ connection = new NetworkSocket ( ' 127.0.0.1 ' , 9000 );
$ content = http_build_query ([ ' key ' => ' value ' ]);
$ request = new PostRequest ( ' /path/to/target/script.php ' , $ content );
$ socketId = $ client -> sendAsyncRequest ( $ connection , $ request );
echo " Request sent, got ID: { $ socketId }" ;
# Do something else here in the meanwhile
# Blocking call until response is received or read timed out
$ response = $ client -> readResponse (
$ socketId , # The socket ID
3000 # Optional timeout to wait for response,
# defaults to read/write timeout in milliseconds set in connection
);
echo $ response -> getBody (); # prints
value
在异步请求回复时通知回调
您可以为每个请求注册响应和故障回调。为了在收到响应而不是返回响应时通知回调,您需要使用waitForResponse(int $socketId, ?int $timeoutMs = null)方法。
declare (strict_types= 1 );
namespace YourVendor YourProject ;
use hollodotme FastCGI Client ;
use hollodotme FastCGI Requests PostRequest ;
use hollodotme FastCGI Interfaces ProvidesResponseData ;
use hollodotme FastCGI SocketConnections NetworkSocket ;
use Throwable ;
$ client = new Client ();
$ connection = new NetworkSocket ( ' 127.0.0.1 ' , 9000 );
$ content = http_build_query ([ ' key ' => ' value ' ]);
$ request = new PostRequest ( ' /path/to/target/script.php ' , $ content );
# Register a response callback, expects a `ProvidesResponseData` instance as the only parameter
$ request -> addResponseCallbacks (
static function ( ProvidesResponseData $ response )
{
echo $ response -> getBody ();
}
);
# Register a failure callback, expects a `Throwable` instance as the only parameter
$ request -> addFailureCallbacks (
static function ( Throwable $ throwable )
{
echo $ throwable -> getMessage ();
}
);
$ socketId = $ client -> sendAsyncRequest ( $ connection , $ request );
echo " Request sent, got ID: { $ socketId }" ;
# Do something else here in the meanwhile
# Blocking call until response is received or read timed out
# If response was received all registered response callbacks will be notified
$ client -> waitForResponse (
$ socketId , # The socket ID
3000 # Optional timeout to wait for response,
# defaults to read/write timeout in milliseconds set in connection
);
# ... is the same as
while ( true )
{
if ( $ client -> hasResponse ( $ socketId ))
{
$ client -> handleResponse ( $ socketId , 3000 );
break ;
}
} # prints
value
用法 - 多个请求
发送多个请求并阅读其答复(保留订单)
declare (strict_types= 1 );
namespace YourVendor YourProject ;
use hollodotme FastCGI Client ;
use hollodotme FastCGI Requests PostRequest ;
use hollodotme FastCGI SocketConnections NetworkSocket ;
$ client = new Client ();
$ connection = new NetworkSocket ( ' 127.0.0.1 ' , 9000 );
$ request1 = new PostRequest ( ' /path/to/target/script.php ' , http_build_query ([ ' key ' => ' 1 ' ]));
$ request2 = new PostRequest ( ' /path/to/target/script.php ' , http_build_query ([ ' key ' => ' 2 ' ]));
$ request3 = new PostRequest ( ' /path/to/target/script.php ' , http_build_query ([ ' key ' => ' 3 ' ]));
$ socketIds = [];
$ socketIds [] = $ client -> sendAsyncRequest ( $ connection , $ request1 );
$ socketIds [] = $ client -> sendAsyncRequest ( $ connection , $ request2 );
$ socketIds [] = $ client -> sendAsyncRequest ( $ connection , $ request3 );
echo ' Sent requests with IDs: ' . implode ( ' , ' , $ socketIds ) . "n" ;
# Do something else here in the meanwhile
# Blocking call until all responses are received or read timed out
# Responses are read in same order the requests were sent
foreach ( $ client -> readResponses ( 3000 , ... $ socketIds ) as $ response )
{
echo $ response -> getBody () . "n" ;
} # prints
1
2
3
发送多个请求并阅读他们的答复(反应性)
declare (strict_types= 1 );
namespace YourVendor YourProject ;
use hollodotme FastCGI Client ;
use hollodotme FastCGI Requests PostRequest ;
use hollodotme FastCGI SocketConnections NetworkSocket ;
$ client = new Client ();
$ connection = new NetworkSocket ( ' 127.0.0.1 ' , 9000 );
$ request1 = new PostRequest ( ' /path/to/target/script.php ' , http_build_query ([ ' key ' => ' 1 ' , ' sleep ' => 3 ]));
$ request2 = new PostRequest ( ' /path/to/target/script.php ' , http_build_query ([ ' key ' => ' 2 ' , ' sleep ' => 2 ]));
$ request3 = new PostRequest ( ' /path/to/target/script.php ' , http_build_query ([ ' key ' => ' 3 ' , ' sleep ' => 1 ]));
$ socketIds = [];
$ socketIds [] = $ client -> sendAsyncRequest ( $ connection , $ request1 );
$ socketIds [] = $ client -> sendAsyncRequest ( $ connection , $ request2 );
$ socketIds [] = $ client -> sendAsyncRequest ( $ connection , $ request3 );
echo ' Sent requests with IDs: ' . implode ( ' , ' , $ socketIds ) . "n" ;
# Do something else here in the meanwhile
# Loop until all responses were received
while ( $ client -> hasUnhandledResponses () )
{
# read all ready responses
foreach ( $ client -> readReadyResponses ( 3000 ) as $ response )
{
echo $ response -> getBody () . "n" ;
}
echo ' . ' ;
}
# ... is the same as
while ( $ client -> hasUnhandledResponses () )
{
$ readySocketIds = $ client -> getSocketIdsHavingResponse ();
# read all ready responses
foreach ( $ client -> readResponses ( 3000 , ... $ readySocketIds ) as $ response )
{
echo $ response -> getBody () . "n" ;
}
echo ' . ' ;
}
# ... is the same as
while ( $ client -> hasUnhandledResponses () )
{
$ readySocketIds = $ client -> getSocketIdsHavingResponse ();
# read all ready responses
foreach ( $ readySocketIds as $ socketId )
{
$ response = $ client -> readResponse ( $ socketId , 3000 );
echo $ response -> getBody () . "n" ;
}
echo ' . ' ;
} # prints
...............................................3
...............................................2
...............................................1
发送多个请求并通知回调(反应性)
declare (strict_types= 1 );
namespace YourVendor YourProject ;
use hollodotme FastCGI Client ;
use hollodotme FastCGI Requests PostRequest ;
use hollodotme FastCGI Interfaces ProvidesResponseData ;
use hollodotme FastCGI SocketConnections NetworkSocket ;
use Throwable ;
$ client = new Client ();
$ connection = new NetworkSocket ( ' 127.0.0.1 ' , 9000 );
$ responseCallback = static function ( ProvidesResponseData $ response )
{
echo $ response -> getBody ();
};
$ failureCallback = static function ( Throwable $ throwable )
{
echo $ throwable -> getMessage ();
};
$ request1 = new PostRequest ( ' /path/to/target/script.php ' , http_build_query ([ ' key ' => ' 1 ' , ' sleep ' => 3 ]));
$ request2 = new PostRequest ( ' /path/to/target/script.php ' , http_build_query ([ ' key ' => ' 2 ' , ' sleep ' => 2 ]));
$ request3 = new PostRequest ( ' /path/to/target/script.php ' , http_build_query ([ ' key ' => ' 3 ' , ' sleep ' => 1 ]));
$ request1 -> addResponseCallbacks ( $ responseCallback );
$ request1 -> addFailureCallbacks ( $ failureCallback );
$ request2 -> addResponseCallbacks ( $ responseCallback );
$ request2 -> addFailureCallbacks ( $ failureCallback );
$ request3 -> addResponseCallbacks ( $ responseCallback );
$ request3 -> addFailureCallbacks ( $ failureCallback );
$ socketIds = [];
$ socketIds [] = $ client -> sendAsyncRequest ( $ connection , $ request1 );
$ socketIds [] = $ client -> sendAsyncRequest ( $ connection , $ request2 );
$ socketIds [] = $ client -> sendAsyncRequest ( $ connection , $ request3 );
echo ' Sent requests with IDs: ' . implode ( ' , ' , $ socketIds ) . "n" ;
# Do something else here in the meanwhile
# Blocking call until all responses were received and all callbacks notified
$ client -> waitForResponses ( 3000 );
# ... is the same as
while ( $ client -> hasUnhandledResponses () )
{
$ client -> handleReadyResponses ( 3000 );
}
# ... is the same as
while ( $ client -> hasUnhandledResponses () )
{
$ readySocketIds = $ client -> getSocketIdsHavingResponse ();
# read all ready responses
foreach ( $ readySocketIds as $ socketId )
{
$ client -> handleResponse ( $ socketId , 3000 );
}
} # prints
3
2
1
使用通过回调从Worker脚本读取输出缓冲区
通过访问该脚本的冲洗输出,可以看到请求脚本的进度可能很有用。 PHP-FPM的php.ini默认输出缓冲为4096字节,并且(硬编码)用于CLI模式。 (请参阅文档)呼叫ob_implicit_flush()会导致每个呼叫echo或print立即被冲洗。
Callee脚本看起来像这样:
declare (strict_types= 1 );
ob_implicit_flush ();
function show ( string $ string )
{
echo $ string . str_repeat ( "r" , 4096 - strlen ( $ string ) ) . "n" ;
sleep ( 1 );
}
show ( ' One ' );
show ( ' Two ' );
show ( ' Three ' );
error_log ( " Oh oh! n" );
echo ' End ' ;呼叫者看起来像这样:
declare (strict_types= 1 );
namespace YourVendor YourProject ;
use hollodotme FastCGI Client ;
use hollodotme FastCGI Requests GetRequest ;
use hollodotme FastCGI SocketConnections NetworkSocket ;
$ client = new Client ();
$ connection = new NetworkSocket ( ' 127.0.0.1 ' , 9000 );
$ passThroughCallback = static function ( string $ outputBuffer , string $ errorBuffer )
{
echo ' Output: ' . $ outputBuffer ;
echo ' Error: ' . $ errorBuffer ;
};
$ request = new GetRequest ( ' /path/to/target/script.php ' , '' );
$ request -> addPassThroughCallbacks ( $ passThroughCallback );
$ client -> sendAsyncRequest ( $ connection , $ request );
$ client -> waitForResponses (); # prints immediately
Buffer: Content-type: text/html; charset=UTF-8
Output: One
# sleeps 1 sec
Output: Two
# sleeps 1 sec
Output: Three
# sleeps 1 sec
Error: Oh oh!
Output: End
请求
请求由以下接口定义:
declare (strict_types= 1 );
namespace hollodotme FastCGI Interfaces ;
interface ProvidesRequestData
{
public function getGatewayInterface () : string ;
public function getRequestMethod () : string ;
public function getScriptFilename () : string ;
public function getServerSoftware () : string ;
public function getRemoteAddress () : string ;
public function getRemotePort () : int ;
public function getServerAddress () : string ;
public function getServerPort () : int ;
public function getServerName () : string ;
public function getServerProtocol () : string ;
public function getContentType () : string ;
public function getContentLength () : int ;
public function getContent () : string ;
public function getCustomVars () : array ;
public function getParams () : array ;
public function getRequestUri () : string ;
}除此界面外,此软件包还提供了一个抽象请求类,其中包含默认值,使您对您更方便,并且该摘要类的5请求方法实现:
-
hollodotmeFastCGIRequestsGetRequest -
hollodotmeFastCGIRequestsPostRequest -
hollodotmeFastCGIRequestsPutRequest -
hollodotmeFastCGIRequestsPatchRequest -
hollodotmeFastCGIRequestsDeleteRequest
因此,您可以实现从抽象类继承的接口,也可以简单地使用5个实现之一。
默认值
抽象请求类定义了几个默认值,您可以选择覆盖这些值:
| 钥匙 | 默认值 | 评论 |
|---|---|---|
| Gateway_interface | fastcgi/1.0 | 不能被覆盖,因为这是客户端的唯一支持版本。 |
| server_software | hollodotme/fast-cgi-client | |
| 远程_ADDR | 192.168.0.1 | |
| 远程_PORT | 9985 | |
| server_addr | 127.0.0.1 | |
| server_port | 80 | |
| server_name | Localhost | |
| server_protocol | http/1.1 | 您可以在hollodotmeFastCGIConstantsServerProtocol中使用公共类常数 |
| content_type | 应用/X-WWW-Form-urlenCoded | |
| request_uri | ||
| custom_vars | 空数组 | 您可以使用setCustomVar , addCustomVars添加自己的键值对 |
请求内容
为了使不同请求内容类型的组成更容易,有涵盖典型内容类型的类:
- urlencodedefformdata
- MultipartFormData
- jsondata
您可以通过实现以下接口来创建自己的请求内容类型的作曲家:
构图requestContent
interface ComposesRequestContent
{
public function getContentType () : string ;
public function getContent () : string ;
}请求内容示例:URL编码的表单数据(Application/X-WWW-Form-urlCoded)
declare (strict_types= 1 );
use hollodotme FastCGI RequestContents UrlEncodedFormData ;
use hollodotme FastCGI SocketConnections NetworkSocket ;
use hollodotme FastCGI Requests PostRequest ;
use hollodotme FastCGI Client ;
$ client = new Client ();
下载源码
通过命令行克隆项目:
git clone https://github.com/hollodotme/fast-cgi-client.git