代码之家  ›  专栏  ›  技术社区  ›  sorush-r

如何从bash cgi脚本中的post数据中获取文件?

  •  12
  • sorush-r  · 技术社区  · 6 年前

    我尝试使用curl发布一个文件,并通过一个cgi bash脚本在另一端接收它,然后用相同的名称存储它。上传完成后, diff 在原始文件和重建文件之间,应该返回零。

    curl发送数据的方式:

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

    接收器脚本:

    #!/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
    

    但它不起作用。文件不是在服务器端创建的。如何获取文件名?

    2 回复  |  直到 6 年前
        1
  •  7
  •   hanshenrik    6 年前

    只要你总是使用 multipart/form-data 格式和客户端总是将 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
    

    上载调用示例(我用于调试上述内容):

    curl http://localhost:81/cgi-bin/wtf.sh -F "MyFile=@myfile.txt"
    
    • 尽管如此,这是疯狂的!巴什绝对是 适用于处理二进制数据,如HTTP文件上载,请使用其他方法。(PHP?蟒蛇?)
        2
  •  6
  •   Bharata colxi    6 年前

    curl发送数据的方式

    随场:

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

    单独指定字段:

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

    Multipart:

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

    包含字段和文件名的多部分:

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

    对于包含XML的RESTful HTTP Post:

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

    或者对于JSON,使用以下命令:

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

    这将读取名为filename.txt的文件的内容,并将其作为post请求发送。

    有关更多信息,请参阅

    使用bash读取HTTP Post数据

    如何获取内容长度:

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

    要保存二进制或文本文件:

    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')
    

    上载的文件现在包含在$file变量中,文件名包含在$file name变量中。