【问题标题】:How to use the content of the file instead of filename for `curl_file_create` function?`curl_file_create` 函数如何使用文件的内容而不是文件名?
【发布时间】:2019-06-19 09:28:43
【问题描述】:

curl_file_create 函数的第一个参数是文件名。有没有办法直接使用文件的内容?
我不想在临时文件中写入内容并在函数中使用该文件名。

更多展开:
我从带有$image = file_get_contents('http://example.com/image.jpg'); 函数的URL 获取图像,所以我现在有一个带有二进制图像内容的$image 变量,在得到它之后,我需要立即将此图像作为表单的一部分发布到另一个URL,而不使用临时文件磁盘。

【问题讨论】:

  • 你的意思是你想把它作为一个多部分/表单数据格式的文件上传,而实际上没有一个文件在磁盘上供 curl_file_create() 读取?
  • @hanshenrik 是的,我想以数据形式发布,请参阅More expand 已添加段落。
  • 完全有可能,只是实施起来很痛苦。 (几年前自己做过,但找不到源),它的要点是自己为multipart/form-data-format 制作一个生成器,作为一个字符串,并将生成的字符串插入到 CURLOPT_POSTFIELDS 并设置适当的标题,包括带有 CURLOPT_HTTPHEADER 的边界字符串

标签: php file curl


【解决方案1】:

对于任何考虑这样做的人:几乎可以肯定不值得麻烦。这是可能的,当然,但你几乎肯定想使用 tmpfile() 技巧,例如,如果你有一个名为 $file_content 的变量,你想将其作为文件上传,但你没有文件,做

<?php
$file_content = "the content of the *file* i want to upload, which does not exist on disk";
$file_name = "example.bin";
$tmph = tmpfile(); // will create a file in the appropriate temp folder when an unique filename
fwrite($tmph, $file_content);
$tmpf = stream_get_meta_data($tmph)['uri'];
$ch = curl_init('http://target_url/');
curl_setopt_array($ch, array(
    CURLOPT_POST => 1,
    CURLOPT_POSTFIELDS => array(
        'file' => new CURLFile($tmpf, 'application/octet-stream', $file_name)
    )
));
curl_exec($ch);
fclose($tmph); // thanks to tmpfile() magic, the file is automatically deleted when fclosed()'d
unset($tmph, $tmpf); // unset() is not needed, but this is the end of the tmpfile()-trick.

.. 幸运的是,只要上传速度很快并且我们不调用 fflush($tmph);,文件可能永远不会接触到实际磁盘,它只会在 IO 中创建缓存,计划稍后写入磁盘,然后删除(从 io 缓存中) - 此代码也受 PHP 的垃圾收集器保护,如果代码中有未捕获的异常/错误停止执行,PHP 的垃圾收集器将删除该文件为我们..

但是,以下是如何通过使用用户级 PHP 代码创建 Multipart/form-data-request 来实际上传 Multipart/form-data 格式的文件,而无需创建磁盘文件:

用法示例:

<?php

// normal php-way: 
$ch = curl_init();
curl_setopt_array($ch, array(
    CURLOPT_URL=>'https://example.com/',
    CURLOPT_POST => 1,
    CURLOPT_POSTFIELDS => array(
        'sample_variable' => 'anything',
        'file' => new CURLFile("path/to/file.txt")
    )
));
curl_exec($ch);
curl_close($ch);
// shitty_multipart-way: 
$post_data = array();
$tmp = new shitty_multipart_variable();
$tmp->post_name = 'sample_variable';
$tmp->content = 'anything';
$post_data[] = $tmp;
$tmp = new shitty_multipart_file();
$tmp->post_name = 'file';
$tmp->post_file_name = "file.ext";
$tmp->content = 'contents of file.ext';
$post_data[] = $tmp;
$content_type_header="";
$post_body=shitty_multipart_form_data_generator($post_data,$content_type_header);
$ch = curl_init();
curl_setopt_array($ch, array(
    CURLOPT_URL=>'https://example.com/',
    CURLOPT_POST => 1,
    CURLOPT_POSTFIELDS => $post_body,
    CURLOPT_HTTPHEADER=>array(
        $content_type_header
    )
));
curl_exec($ch);
curl_close($ch);

实施:

class shitty_multipart_file
{
    public $post_name = "";
    public $file_name = "";
    public $content_type = "application/octet-stream";
    public $content = "";
    public $additional_headers = [];
}
class shitty_multipart_variable
{
    public $post_name = "";
    public $content = "";
    public $additional_headers = [];
}
function shitty_multipart_form_data_generator(array $postfields, string &$out_content_type_header): string
{
    // Content-Type: multipart/form-data; boundary=------------------------7b5b9abe8c56fd67
    // same boundary format as used by curl
    $boundary = "------------------------" . strtolower(bin2hex(random_bytes(8)));
    $out_content_type_header = 'Content-Type: multipart/form-data; boundary=' . $boundary;
    $body = "";
    foreach ($postfields as $unused => $post) {
        $body .= $boundary . "\r\n";
        if (is_a($post, 'shitty_multipart_variable')) {
            $body .= "Content-Disposition: form-data; name=\"{$post->post_name}\"\r\n";
            foreach ($post->additional_headers as $header) {
                $body .= $header . "\r\n";
            }
            $body .= "\r\n";
            $body .= $post->content . "\r\n";
        } elseif (is_a($post, 'shitty_multipart_file')) {
            $body .= "Content-Disposition: form-data; name=\"{$post->post_name}\"; filename=\"{$post->file_name}\"\r\n";
            $body .= "Content-Type: " . $post->content_type . "\r\n";
            foreach ($post->additional_headers as $header) {
                $body .= $header . "\r\n";
            }
            $body .= "\r\n";
            $body .= $post->content . "\r\n";
        } else {
            throw new \InvalidArgumentException("postfields key {$unused} is not an instance of shitty_multipart_variable NOR an instance of shitty_multipart_file!");
        }
    }
    $body .= $boundary . "--\r\n";
    return $body;
}

【讨论】:

    猜你喜欢
    • 2012-04-30
    • 2019-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-31
    • 1970-01-01
    • 2012-08-08
    • 1970-01-01
    相关资源
    最近更新 更多