我正在编写Java CGI客户端以与PHP-CGI进行通信,但遇到了麻烦,我的php $_POST
肯定发送了一些数据,但没有填充任何数据。我不知道为什么要这么做,而且在任何地方都找不到这个问题。
我直接从windows.php.net使用干净的PHP二进制文件,没有任何编辑。
这是我现在要测试的代码:
public static void main(String[] args)
{
HashMap<String, String> map = new HashMap<String, String>();
String body = "data=Foo+Bar";
String queryString = "yes=no&a=b";
String requestMethod = "POST";
String contentType = "application/x-www-form-urlencoded";
String contentLength = Integer.toString( body.length() );
String docRoot = "D:/http test";
String scriptName = "/index.php";
String scriptFileName = docRoot + scriptName;
String pathInfo = "";
String pathTranslated = docRoot + pathInfo;
String requestUri = scriptName + pathInfo + ("?" + queryString);
String documentUri = scriptName + pathInfo;
String serverProtocol = "HTTP/1.1";
String gatewayInterface = "CGI/1.1";
map.put( "QUERY_STRING" , queryString);
map.put( "REQUEST_METHOD" , requestMethod);
map.put( "CONTENT_TYPE" , contentType);
map.put( "CONTENT_LENGTH" , contentLength);
map.put( "SCRIPT_FILENAME" , scriptFileName);
map.put( "SCRIPT_NAME" , scriptName);
map.put( "PATH_INFO" , pathInfo);
map.put( "PATH_TRANSLATED" , pathTranslated);
map.put( "REQUEST_URI" , requestUri);
map.put( "DOCUMENT_URI" , documentUri);
map.put( "DOCUMENT_ROOT" , docRoot);
map.put( "SERVER_NAME" , "localhost" );
map.put( "SERVER_PROTOCOL" , serverProtocol);
map.put( "GATEWAY_INTERFACE" , gatewayInterface);
Client c = new Client( "127.0.0.1" , 8090 );
System.out.println("\n" + c.doRequest( map , body ));
}
Client.java:
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Map;
import java.util.Map.Entry;
public class Client
{
private Socket socket;
public Client( String host, int port ) throws UnknownHostException, IOException
{
socket = new Socket( host, port );
}
public String doRequest( Map<String, String> params, String content ) throws IOException
{
ByteArrayOutputStream paramBytes = new ByteArrayOutputStream();
for ( Entry<String, String> param: params.entrySet() )
paramBytes.write( nvpair( param.getKey() , param.getValue() ) );
Packet beginRequest = new Packet( FCGI.BEGIN_REQUEST, FCGI.NULL_REQUEST_ID, new byte[] { 0, FCGI.RESPONDER, FCGI.KEEP_CONN, 0, 0, 0, 0, 0 } );
Packet requestParams = new Packet( FCGI.PARAMS, FCGI.NULL_REQUEST_ID, paramBytes.toByteArray() );
Packet requestContent = new Packet( FCGI.STDIN, FCGI.NULL_REQUEST_ID, content.getBytes( "UTF-8" ) );
OutputStream stream = socket.getOutputStream();
stream.write( beginRequest.getBytes() );
stream.write( requestParams.getBytes() );
stream.write( requestContent.getBytes() );
return readResponse();
}
private String readResponse() throws IOException
{
InputStream stream = socket.getInputStream();
// TODO buffering
String out = null;
for ( Packet p = new Packet( stream ); p.getType() != FCGI.END_REQUEST; p = new Packet( stream ) )
{
System.out.print( p.getType() + ", " );
if ( p.getType() == FCGI.STDOUT )
out = new String( p.getContent() );
}
return out;
}
public byte[] nvpair( String name, String value )
{
try
{
int nl = name.length();
int vl = value.length();
ByteArrayOutputStream bytes = new ByteArrayOutputStream( nl + vl + 10 );
if ( nl < 128 )
bytes.write( b( nl ) );
else
bytes.write( new byte[] { b( nl >> 24 ), b( nl >> 16 ), b( nl >> 8 ), b( nl ) } );
if ( vl < 128 )
bytes.write( b( vl ) );
else
bytes.write( new byte[] { b( vl >> 24 ), b( vl >> 16 ), b( vl >> 8 ), b( vl ) } );
bytes.write( name.getBytes( "UTF-8" ) );
bytes.write( value.getBytes( "UTF-8" ) );
return bytes.toByteArray();
}
catch( IOException e )
{
e.printStackTrace();
}
return null;
}
public byte b( int i )
{
return (byte) i;
}
}
index.php:
<pre><?php
echo "Hello World\n";
echo "REQUEST = "; print_r($_REQUEST);
echo "GET = "; print_r($_GET);
echo "POST = "; print_r($_POST);
echo php_ini_loaded_file(), "\n";
echo file_get_contents("php://input"), "\n";
echo php_sapi_name();
?></pre>
而他就是我得到的结果:
6,
X-Powered-By: PHP/5.6.3
Content-type: text/html; charset=UTF-8
<pre>Hello World
REQUEST = Array
(
[yes] => no
[a] => b
)
GET = Array
(
[yes] => no
[a] => b
)
POST = Array
(
)
D:\Programs\PHP 5.6.3 x64 TS\php.ini
cgi-fcgi</pre>
我想要的是$_POST
包含Array( [data] => Foo Bar )
(这是我要发送的内容)。
有谁知道我可以解决这个问题,以便$_POST
也可以填充数据?
参考方案
好吧,如果您查看FastCGI-spec chapter 3.3 under the subtitle "Types of Record Types",它会说:
流记录是流的一部分,即流类型的一系列零个或多个非空记录(长度!= 0),后跟该流类型的空记录(长度== 0)。
这意味着适当的流由至少一个非空数据包组成,这些数据包以相同流类型的空数据包终止。
您也可以查看Appendix B (Typical Protocol Message Flow)外观。
那和你的问题有什么关系?
PHP希望对FCGI_PARAMS
流进行一次或多次非空的“写入”,然后标记一个空的FCGI_PARAMS
数据包以标记params-stream的结尾。
如果查看您的doRequest
方法,您将写入一个非空的FCGI_PARAMS
数据包,然后紧接着写入您的FCGI_STDIN
数据包。
PHP的作用是读取您的第一个FCGI_PARAMS
记录,然后如果您的FCGI_STDIN
数据包到达,它将仅读取标头并停止。因此,下一个fcgi_read
读取无效数据并静默失败-但是PHP继续使用空的STDIN流处理请求。或者,如果您的请求正文太小(例如body =“ a”),PHP将永远阻塞。
如果您修改doRequest
方法并以空写操作终止流(我将它们称为EOF数据包),则它应该可以工作:
public String doRequest( Map<String, String> params, String content ) throws IOException
{
ByteArrayOutputStream paramBytes = new ByteArrayOutputStream();
for ( Entry<String, String> param: params.entrySet() )
paramBytes.write( nvpair( param.getKey() , param.getValue() ) );
Packet beginRequest = new Packet( FCGI.BEGIN_REQUEST, FCGI.NULL_REQUEST_ID, new byte[] { 0, FCGI.RESPONDER, FCGI.KEEP_CONN, 0, 0, 0, 0, 0 } );
Packet requestParams = new Packet( FCGI.PARAMS, FCGI.NULL_REQUEST_ID, paramBytes.toByteArray() );
Packet requestParamsEOF = new Packet( FCGI.PARAMS, FCGI.NULL_REQUEST_ID, new byte[] {} );
Packet requestContent = new Packet( FCGI.STDIN, FCGI.NULL_REQUEST_ID, content.getBytes( "UTF-8" ) );
Packet requestContentEOF = new Packet( FCGI.STDIN, FCGI.NULL_REQUEST_ID, new byte[] {} );
OutputStream stream = socket.getOutputStream();
stream.write( beginRequest.getBytes() );
stream.write( requestParams.getBytes() );
stream.write( requestParamsEOF.getBytes() );
stream.write( requestContent.getBytes() );
stream.write( requestContentEOF.getBytes() );
return readResponse();
}
这样做的原因是,您可以将大型流拆分为多个数据包(因为每个数据包只能容纳64 KiB的有效负载)。从理论上讲,您必须检查请求正文的长度,并将其拆分为64 KiB(2 ^ 16字节)的块。因此,甚至可以改进此版本的doRequest
。
我正在寻找一种简单的方法,供用户将多个图像上传到网站。我想到的想法就像旧的Facebook服务一样,我认为他们使用Java。您单击以添加带有系统文件和文件夹的图像和弹出窗口,您可以在其中使用复选框选择多个图像,仅一个图像等。我从来没有使用过类似的东西,也没有接触过Java,但是我认为这是唯一的方法。谢谢!PS:我不是在说多个<input type=…
PHP和Java的互操作性 - java我正在使用tomcat 6和PHP / Java Bridge在Windows上工作。我知道如何从PHP访问Java文件,但我们如何做另一种方式,即从Java访问PHP<?php require_once("java\Java.inc"); $systemInfo = new Java("java.lang.System&…
PHP:为什么将日期设置为数组? - php为什么将此字符串组成一个数组,如何停止它?摘要:(获取日期)public function setDate(){ $this->date = date("Y-m-d"); return $date; } public function getDate(){ return $this->date; } $date = getDa…
PHP-复选框组 - php我有一个需要发布的表单复选框组。<input type="checkbox" value="true" checked name="chk0[]"> <input type="checkbox" value="false" name=…
从PHP数组中获取价值? - php当我使用var_dump()函数检查数组的值时。var_dump($data['content']); 我有结果array(1) { [0]=> array(10) { ["IDUser"]=> string(1) "1" ["Name"]=> string(5…