简体   繁体   English

如何从 Bash CGI 脚本中的 POST 数据中获取文件?

[英]How to get file from POST data in Bash CGI script?

I am trying to post a file using cURL and receive it on the other side via a CGI Bash script and store it with the same name.我正在尝试使用 cURL 发布文件并通过 CGI Bash 脚本在另一端接收它并以相同的名称存储它。 After upload is completed, diff between the original file and reconstructed one should return zero.上传完成后,原始文件和重建文件之间的diff应返回零。

The way cURL sends data: cURL 发送数据的方式:

curl --request POST --data-binary "@dummy.dat" 127.0.0.1/cgi-bin/upload-rpm

Receiver script:接收脚本:

#!/bin/bash

echo "Content-type: text/html"
echo ""

echo '<html>'
echo '<head>'
echo '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">'
echo '<title>Foo</title>'
echo '</head>'
echo '<body>'

echo "<p>Start</p>"

if [ "$REQUEST_METHOD" = "POST" ]; then
    echo "<p>Post Method</p>"
    if [ "$CONTENT_LENGTH" -gt 0 ]; then
        echo "<p>Size=$CONTENT_LENGTH</p>"
        while read -n 1 byte -t 3; do echo -n -e "$byte" >> ./foo.dat ; done
    fi
fi
echo '</body>'
echo '</html>'

exit 0

But it's not working.但它不起作用。 File is not created on the server side.文件不是在服务器端创建的。 And how can I get the file name?我怎样才能得到文件名?

as long as you're always uploading exactly 1 file using the multipart/form-data format and the client always put the Content-Type as the last header of the file upload (which curl always seem to do), this seem to work:只要您始终使用multipart/form-data格式准确上传 1 个文件,并且客户端始终将Content-Type作为文件上传的最后一个标头(curl 似乎总是这样做),这似乎有效:

#!/bin/bash

echo "Content-type: text/html"
echo ""

echo '<html>'
echo '<head>'
echo '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">'
echo '<title>Foo</title>'
echo '</head>'
echo '<body>'

echo "<p>Start</p>"

if [ "$REQUEST_METHOD" = "POST" ]; then
    echo "<p>Post Method</p>"
    if [ "$CONTENT_LENGTH" -gt 0 ]; then
    in_raw="$(cat)"
    boundary=$(echo -n "$in_raw" | head -1 | tr -d '\r\n');
    filename=$(echo -n "$in_raw" | grep --text --max-count=1 -oP "(?<=filename=\")[^\"]*");
    file_content=$(echo -n "$in_raw" | sed '1,/Content-Type:/d' | tail -c +3 | head --lines=-1 | head --bytes=-4  );
    echo "boundary: $boundary"
    echo "filename: $filename"
    #echo "file_content: $file_content"
    fi
fi
echo '</body>'
echo '</html>'

exit 0

example upload invocation (which I used to debug the above):示例上传调用(我用来调试上面的):

curl http://localhost:81/cgi-bin/wtf.sh -F "MyFile=@myfile.txt"
  • with all that said, THIS IS INSANITY!话虽如此,这太疯狂了! bash is absolutely not suitable for handling binary data, such as http file uploads, use something else. bash绝对适合处理二进制数据,比如http文件上传,用别的吧。 (PHP? Python? Perl?) (PHP?Python?Perl?)

The ways curl sends data curl 发送数据的方式

With fields:带字段:

curl --data "param1=value1&param2=value2" https://example.com/resource.cgi

With fields specified individually:单独指定字段:

curl --data "param1=value1" --data "param2=value2" https://example.com/resource.cgi

Multipart:多部分:

curl --form "fileupload=@my-file.txt" https://example.com/resource.cgi

Multipart with fields and a filename:带有字段和文件名的多部分:

curl --form "fileupload=@my-file.txt;filename=desired-filename.txt" --form param1=value1 --form param2=value2 https://example.com/resource.cgi

For a RESTful HTTP POST containing XML:对于包含 XML 的 RESTful HTTP POST:

curl -X POST -d @filename.txt http://example.com/path/to/resource --header "Content-Type:text/xml"

or for JSON, use this:或者对于 JSON,使用这个:

curl -X POST -d @filename.txt http://example.com/path/to/resource --header "Content-Type:application/json"

This will read the contents of the file named filename.txt and send it as the post request.这将读取名为 filename.txt 的文件的内容并将其作为 post 请求发送。

For further information see欲了解更多信息,请参阅

Reading HTTP POST data using BASH使用 BASH 读取 HTTP POST 数据

How to get the content length:如何获取内容长度:

if [ "$REQUEST_METHOD" = "POST" ]; then
    if [ "$CONTENT_LENGTH" -gt 0 ]; then
        read -n $CONTENT_LENGTH POST_DATA <&0
        echo "$CONTENT_LENGTH"
    fi
fi

To save a binary or text file:要保存二进制文件或文本文件:

boundary=$(export | \
    sed '/CONTENT_TYPE/!d;s/^.*dary=//;s/.$//')
filename=$(echo "$QUERY_STRING" | \
    sed -n '2!d;s/\(.*filename=\"\)\(.*\)\".*$/\2/;p')
file=$(echo "$QUERY_STRING" | \
    sed -n "1,/$boundary/p" | sed '1,4d;$d')

The uploaded file is now contained in the $file variable, and file name in the $filename variable.上传的文件现在包含在 $file 变量中,文件名包含在 $filename 变量中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM