2010-06-21 27 views
34

我想知道当文件只是一个字符串时,是否可以发布文件以及其他表单数据?在PHP中使用cURL发布文件字符串?

我知道您可以通过在文件路径前加“@”来发布已经在文件系统上的文件。

但是我想绕过创建一个临时文件并只发送文件作为字符串,但我不确定如何使用PHP中的cURL构造请求。

干杯

$postFields = array(
     'otherFields' => 'Yes' 
     ,'filename'  => 'my_file.csv' 
     ,'data'   => 'comma seperated content' 
    ); 

    $options = array(
     CURLOPT_RETURNTRANSFER => true 
     ,CURLOPT_SSL_VERIFYPEER => false 
     ,CURLOPT_SSL_VERIFYHOST => 1 
     ,CURLOPT_POSTFIELDS  => $postFields 
     ,CURLOPT_HTTPHEADER  => array(
      'Content-type: multipart/form-data' 
     ) 
    ); 
+1

@Vin绝对不是重复的。这是一个很好的问题。我不知道有什么方法可以添加部分头文件,因为这里需要手动制作所有POST数据。 – Artefacto 2010-06-21 15:37:17

+0

@Artefacto:对,我没有正确的理解这个问题 – 2010-06-21 15:59:24

+1

原始数据你的意思是file_get_contents($ path_to_file); ? – Walter 2011-02-18 04:20:28

回答

25

应该是可能的:这里的一种形式,通过浏览器发布(不相关的领域略):

POST http://host.example.com/somewhere HTTP/1.1 
Content-Type: multipart/form-data; boundary=---------------------------7da16b2e4026c 
Content-Length: 105732 

-----------------------------7da16b2e4026c 
Content-Disposition: form-data; name="NewFile"; filename="test.jpg" 
Content-Type: image/jpeg 

(...raw JPEG data here...) 
-----------------------------7da16b2e4026c 
Content-Disposition: form-data; name="otherformfield" 

content of otherformfield is this text 
-----------------------------7da16b2e4026c-- 

所以,如果我们建立了POST正文自己和设置额外的头部或两个,我们应该能够模拟这个:

// form field separator 
$delimiter = '-------------' . uniqid(); 
// file upload fields: name => array(type=>'mime/type',content=>'raw data') 
$fileFields = array(
    'file1' => array(
     'type' => 'text/plain', 
     'content' => '...your raw file content goes here...' 
    ), /* ... */ 
); 
// all other fields (not file upload): name => value 
$postFields = array(
    'otherformfield' => 'content of otherformfield is this text', 
    /* ... */ 
); 

$data = ''; 

// populate normal fields first (simpler) 
foreach ($postFields as $name => $content) { 
    $data .= "--" . $delimiter . "\r\n"; 
    $data .= 'Content-Disposition: form-data; name="' . $name . '"'; 
    // note: double endline 
    $data .= "\r\n\r\n"; 
} 
// populate file fields 
foreach ($fileFields as $name => $file) { 
    $data .= "--" . $delimiter . "\r\n"; 
    // "filename" attribute is not essential; server-side scripts may use it 
    $data .= 'Content-Disposition: form-data; name="' . $name . '";' . 
      ' filename="' . $name . '"' . "\r\n"; 
    // this is, again, informative only; good practice to include though 
    $data .= 'Content-Type: ' . $file['type'] . "\r\n"; 
    // this endline must be here to indicate end of headers 
    $data .= "\r\n"; 
    // the file itself (note: there's no encoding of any kind) 
    $data .= $file['content'] . "\r\n"; 
} 
// last delimiter 
$data .= "--" . $delimiter . "--\r\n"; 

$handle = curl_init($url); 
curl_setopt($handle, CURLOPT_POST, true); 
curl_setopt($handle, CURLOPT_HTTPHEADER , array(
    'Content-Type: multipart/form-data; boundary=' . $delimiter, 
    'Content-Length: ' . strlen($data))); 
curl_setopt($handle, CURLOPT_POSTFIELDS, $data); 
curl_exec($handle); 

这样,我们正在做他所有的他狂热自己,相信cURL不会破坏它。

+1

最初误解了这个问题,并正确地对它进行了低估。改写成可以工作的东西。 – Piskvor 2010-06-21 16:12:27

+2

我已经构建了Piskvor建议的请求,是的,你可以自己构建身体,它会工作。虽然你必须100%准确的EOL。 在“Content-Length”和“Content-Disposition”结尾处需要双重返回。对于“Content-Type:text/plain”后面的文件,还需要双重返回。 对于body值,分隔符也稍微不同于“Boundary”中的decleared。每条边界线在开始时都有两个额外的连字符。 最后一个分隔符在开头和结尾处有两个额外的超级链接。 – gawpertron 2010-06-22 12:00:26

+0

您知道,您还可以通过在文件的完整路径前加@符号来发布文件。 http://www.php.net/manual/en/function.curl-setopt.php检查'CURLOPT_POSTFIELDS'部分。 – 2011-02-18 05:43:24

15

php有权访问一个临时位置“php:// memory”,这实际上使得你想要做的事情变得相当容易。

$fh = fopen('php://memory','rw'); 
fwrite($fh, $content); 
rewind($fh); 

$options = array(
    CURLOPT_RETURNTRANSFER => true 
    ,CURLOPT_SSL_VERIFYPEER => false 
    ,CURLOPT_SSL_VERIFYHOST => 1 
    ,CURLOPT_HTTPHEADER  => array(
     'Content-type: multipart/form-data' 
    ) 
    ,CURLOPT_INFILE   => $fh 
    ,CURLOPT_INFILESIZE  => strlen($content) 
); 
+0

这是否允许与文件一起发送的其他帖子? – 2010-06-21 16:16:36

+4

它绝对创建一个文件处理程序,我试了一下,但我认为CURLOPT_INFILE和CURLOPT_INFILESIZE用于PUT文件,没有文件出现在$ _FILES数组中。 – gawpertron 2010-06-21 18:32:25

+0

问题中的代码可以一次上传多个文件。 'INFILE'可以'PUT'上传多个文件吗? – DanFromGermany 2013-07-10 13:31:02