我有一个脚本,向post
发送/usr/bin/php-cgi
请求。处理纯文本时脚本工作正常,但当数据为二进制时失败:
$data = file_get_contents('example.jpg');
$size = filesize('example.jpg') + 5;
$post_data = 'file='.$data;
$response = shell_exec('echo "'.$post_data.'" |
REDIRECT_STATUS=CGI
REQUEST_METHOD=POST
SCRIPT_FILENAME=/example/script.php
SCRIPT_NAME=/script.php
PATH_INFO=/
SERVER_NAME=localhost
SERVER_PROTOCOL=HTTP/1.1
REQUEST_URI=/example/index.html
HTTP_HOST=example.com
CONTENT_TYPE=application/x-www-form-urlencoded
CONTENT_LENGTH='.$size.' php-cgi');
我收到以下错误:
sh:-c:第1行:在寻找匹配的“”时出现意外的EOF sh:-c:第5行:语法错误:意外的文件结束
我想这是因为我试图发送的数据是二进制的,必须以某种方式编码/转义。
就像我说的,如果数据是纯文本,上面的代码是有效的:
$post_data = "data=sample data to php-cgi";
$size = strlen($post_data);
我也尝试使用base64_encode()
对数据进行编码,但后来又面临另一个问题;必须从接收脚本中解码数据。我想也许我可以编码base64
中的数据然后添加一些内容或mime类型标题来强制php-cgi
二进制文件进行对话?
另一个问题是我喜欢将数据作为附件发送,因此我认为我们必须将CONTENT_TYPE
设置为multipart/form-data; boundary=<random_boundary>
并将CONTENT_DISPOSITION
设置为form-data
,但我不确定如何从命令行设置这些标头。
您正尝试通过shell_exe上传二进制文件以发布内容。 shell_exe不接受二进制编码。如果您将图像数据更改为base64,那么您的问题将得到解决。但是你会遇到另一个问题,即如何识别提交的文本/字符串,即文本或图像。目前,我发现无法确定提交的值是图像还是文本。
既然,你想发布图像和数据,我建议你使用CURL并提供通过CURL提交图像和数据的方法,我也使用它:
$local_directory=dirname(__FILE__).'/local_files/';
$ch = curl_init();
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_VERBOSE, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible;)");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_URL, 'http://localhost/curl_image/uploader.php' );
//most importent curl assues @filed as file field
$post_array = array(
"my_file"=>"@".$local_directory.'filename.jpg',
"upload"=>"Upload"
);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_array);
$response = curl_exec($ch);
echo $response;
您还可以将所有发布数据存储在临时文件中,然后将该文件存入php-cgi:
char file[20] = "/tmp/php"; //temp post data location
char name[10];
webserver_alpha_random(name, 10); //create random name
strcat(file, name);
int f = open(file, O_TRUNC | O_WRONLY | O_CREAT);
write(f, conn->content, conn->content_len); //post data from mongoose
close(f);
/* cat temp post data into php-cgi */
/* this function also takes care of all environment variables */
/* but the idea is understandable */
output = webserver_shell("cat %s | php-cgi %s", conn, request, file, request);
unlink(file);
最后,我得到了这个工作,解决方案是发送一个base64
编码的请求,其中还包含一个常量命名字段,如ORIGINAL_QUERY_URI
到一种gateway
文件,反过来将解码请求并将其弹回到它的原始目的地。
基本上,服务器执行此操作:
base64
中的任何接收文件数据ORIGINAL_REQEUST_URI
的表单数据字段,并将原始URL作为值multipart/form-data
的有效http请求体shell_exec
将此数据发送到将解码内容的gateway
文件这是我用来将所有内容发送到php-cgi
的命令:
shell_exec('echo "' . $body . '" |
HOST=localhost
REDIRECT_STATUS=200
REQUEST_METHOD=POST
SCRIPT_FILENAME=/<path>/gate.php
SCRIPT_NAME=/gate.php
PATH_INFO=/
SERVER_NAME=localhost
SERVER_PROTOCOL=HTTP/1.1
REQUEST_URI=/example.php
HTTP_HOST=localhost
CONTENT_TYPE="multipart/form-data; boundary=' . $boundary . '"
CONTENT_LENGTH=' . $size . ' php-cgi');
然后在gate.php
文件中我解码了数据并包含了theORIGINAL_REQUEST_URI
字段指向的文件。
// File: gate.php
if (isset($_FILES)) {
foreach ($_FILES as $key => $value) {
// decode the `base64` encoded file data
$content = file_get_contents($_FILES[$key]['tmp_name']);
$content = base64_decode($content);
file_put_contents($_FILES[$key]['tmp_name'], $content);
}
}
// bounce to original destination
include_once($_POST['ORIGINAL_REQUEST_URI']);