1

我有一个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_TYPEtomultipart/form-data; boundary=<random_boundary>CONTENT_DISPOSITIONto form-data,但我不确定如何从命令行设置这些标头。

4

3 回答 3

2

您正在尝试通过 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;
于 2013-07-26T07:07:48.600 回答
2

您还可以将所有发布数据存储在一个临时文件中,然后将该文件放入 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);
于 2014-02-14T13:16:11.150 回答
1

最后我得到了这个工作,解决方案是发送一个base64编码的请求,该请求还包含一个常量命名字段ORIGINAL_QUERY_URI,例如一种gateway文件,该文件反过来会解码请求并将其反弹到它的原始目的地。

基本上,服务器会这样做:

  1. 将任何接收到的文件数据编码为base64
  2. ORIGINAL_REQEUST_URI添加一个以原始 url命名的表单数据字段作为值
  3. multipart/form-data组装基于上述编码的有效http请求正文
  4. 将此数据发送shell_execgateway将解码内容的文件

这是我用来将所有内容发送到的命令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指向的文件。ORIGINAL_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']);  
于 2013-08-05T19:31:21.603 回答