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域插座
创建网络插座连接
<?php 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域插座连接
<?php 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的内容看起来像这样:
<?php declare (strict_types= 1 ); sleep (( int )( $ _REQUEST [ \' sleep \' ] ?? 0 )); echo $ _REQUEST [ \' key \' ] ?? \'\' ;
同步发送请求
<?php 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
异步发送请求(开火和忘记)
<?php 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 }\" ;
在发送异步请求后阅读响应
<?php 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)方法。
<?php 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
用法 – 多个请求
发送多个请求并阅读其答复(保留订单)
<?php 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
发送多个请求并阅读他们的答复(反应性)
<?php 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
发送多个请求并通知回调(反应性)
<?php 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脚本看起来像这样:
<?php 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 \' ;
呼叫者看起来像这样:
<?php 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
请求
请求由以下接口定义:
<?php 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请求方法实现:
-
hollodotme\\FastCGI\\Requests\\GetRequest -
hollodotme\\FastCGI\\Requests\\PostRequest -
hollodotme\\FastCGI\\Requests\\PutRequest -
hollodotme\\FastCGI\\Requests\\PatchRequest -
hollodotme\\FastCGI\\Requests\\DeleteRequest
因此,您可以实现从抽象类继承的接口,也可以简单地使用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 | 您可以在hollodotme\\FastCGI\\Constants\\ServerProtocol中使用公共类常数 |
| 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)
<?php 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 ();
<s
