【问题标题】:Send file via cURL from form POST in PHP通过 cURL 从 PHP 中的表单 POST 发送文件
【发布时间】:2011-05-12 13:24:51
【问题描述】:

我正在编写一个 API,我想处理来自 POST 表单的文件上传。表单的标记并不复杂:

<form action="" method="post" enctype="multipart/form-data">
  <fieldset>
    <input type="file" name="image" id="image" />
    <input type="submit" name="upload" value="Upload" />
  </fieldset>
</form>

但是,我很难理解如何处理此服务器端并与 cURL 请求一起发送。

我熟悉使用带有数据数组的 cURL 发送 POST 请求,并且我在上传文件时阅读的资源告诉我在文件名前加上 @ 符号。但是这些相同的资源有一个硬编码的文件名,例如

$post = array(
    'image' => '@/path/to/myfile.jpg',
    ...
);

那么这是哪个文件路径?我在哪里可以找到它?是不是类似于$_FILES['image']['tmp_name'],在这种情况下我的$post 数组应该是这样的:

$post = array(
    'image' => '@' . $_FILES['image']['tmp_name'],
    ...
);

或者我是不是走错了路?任何建议将不胜感激。

编辑:如果有人能给我一个代码 sn-p,我将使用以下代码 sn-ps 去哪里,那么我将不胜感激。我主要关注我将作为 cURL 参数发送的内容,以及如何将这些参数与接收脚本一起使用的示例(为了参数,我们将其称为 curl_receiver.php)。

我有这个网络表单:

<form action="script.php" method="post" enctype="multipart/form-data">
  <fieldset>
    <input type="file" name="image />
    <input type="submit" name="upload" value="Upload" />
  </fieldset>
</form>

这将是script.php:

if (isset($_POST['upload'])) {
    // cURL call would go here
    // my tmp. file would be $_FILES['image']['tmp_name'], and
    // the filename would be $_FILES['image']['name']
}

【问题讨论】:

  • http extension 会成为话题吗?与 cURL(多协议)不同,它更适合 HTTP。

标签: php curl image-uploading


【解决方案1】:

我们可以通过curl请求上传图片文件,将其转换为base64字符串。所以在后期我们将发送文件字符串,然后将其转换为图片。

function covertImageInBase64()
{
    var imageFile = document.getElementById("imageFile").files;
    if (imageFile.length > 0)
    {
        var imageFileUpload = imageFile[0];
        var readFile = new FileReader();
        readFile.onload = function(fileLoadedEvent) 
        {
            var base64image = document.getElementById("image");
            base64image.value = fileLoadedEvent.target.result;
        };
        readFile.readAsDataURL(imageFileUpload);
    }
}

然后在 curl 请求中发送它

if(isset($_POST['image'])){
    $curlUrl='localhost/curlfile.php';  
    $ch = curl_init();
    curl_setopt($ch,CURLOPT_URL, $curlUrl);
    curl_setopt($ch,CURLOPT_POST, 1);
    curl_setopt($ch,CURLOPT_POSTFIELDS, 'image='.$_POST['image']);
    $result = curl_exec($ch);
    curl_close($ch);
}

看这里http://technoblogs.co.in/blog/How-to-upload-an-image-by-using-php-curl-request/118

【讨论】:

    【解决方案2】:

    通过 Mercadolibre 的消息系统向 Mercadolibre 发送附件时,它适用于我。

    答案https://stackoverflow.com/a/35227055/7656744

    $target_url = "http://server:port/xxxxx.php";           
    $fname = 'file.txt';   
    $cfile = new CURLFile(realpath($fname));
    
        $post = array (
                  'file' => $cfile
                  );    
    
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $target_url);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_HEADER, 0);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 
    curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible;)");   
    curl_setopt($ch, CURLOPT_HTTPHEADER,array('Content-Type: multipart/form-data'));
    curl_setopt($ch, CURLOPT_FRESH_CONNECT, 1);   
    curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);  
    curl_setopt($ch, CURLOPT_TIMEOUT, 100);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
    
    $result = curl_exec ($ch);
    
    if ($result === FALSE) {
        echo "Error sending" . $fname .  " " . curl_error($ch);
        curl_close ($ch);
    }else{
        curl_close ($ch);
        echo  "Result: " . $result;
    }   
    

    【讨论】:

      【解决方案3】:

      过程方法中的cURL文件对象:

      $file = curl_file_create('full path/filename','extension','filename');
      

      Oop 方法中的 cURL 文件对象:

      $file = new CURLFile('full path/filename','extension','filename');
      
      $post= array('file' => $file);
      
      $curl = curl_init();  
      //curl_setopt ... 
      curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
      $response = curl_exec($curl);
      curl_close($curl);
      

      【讨论】:

        【解决方案4】:

        对于发现这篇文章并使用 PHP5.5+ 的人来说,这可能会有所帮助。

        我发现 netcoder 建议的方法不起作用。即这不起作用:

        $tmpfile = $_FILES['image']['tmp_name'];
        $filename = basename($_FILES['image']['name']);
        $data = array(
            'uploaded_file' => '@'.$tmpfile.';filename='.$filename,
        );
        $ch = curl_init();   
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        

        我会在 $_POST var 中收到 'uploaded_file' 字段 - 而在 $_FILES var 中什么也没有。

        事实证明,对于 php5.5+,您需要使用一个新的 curl_file_create() 函数。所以上面会变成:

        $data = array(
            'uploaded_file' => curl_file_create($tmpfile, $_FILES['image']['type'], $filename)
        );
        

        由于 @ 格式现已弃用。

        【讨论】:

        • 我在过去 5 小时内一直在寻找这个命令!!没有人提到 curl_file_create() 函数,非常感谢
        • 现在是 2019 年,我为此寻找了 6 小时...谢谢!
        • curl_file_create()
        • 你的答案太离谱了。
        • curl_file_create 的最佳示例。你救了我的命。 ^^
        【解决方案5】:

        因为我的@符号不起作用,所以我做了一些研究,发现这种方式对我有用,希望对你有所帮助。

            $target_url = "http://server:port/xxxxx.php";           
            $fname = 'file.txt';   
            $cfile = new CURLFile(realpath($fname));
        
                $post = array (
                          'file' => $cfile
                          );    
        
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, $target_url);
            curl_setopt($ch, CURLOPT_POST, 1);
            curl_setopt($ch, CURLOPT_HEADER, 0);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 
            curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible;)");   
            curl_setopt($ch, CURLOPT_HTTPHEADER,array('Content-Type: multipart/form-data'));
            curl_setopt($ch, CURLOPT_FRESH_CONNECT, 1);   
            curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);  
            curl_setopt($ch, CURLOPT_TIMEOUT, 100);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
        
            $result = curl_exec ($ch);
        
            if ($result === FALSE) {
                echo "Error sending" . $fname .  " " . curl_error($ch);
                curl_close ($ch);
            }else{
                curl_close ($ch);
                echo  "Result: " . $result;
            }   
        

        【讨论】:

        • 谢谢,我已经尝试了几天,最后尝试了你的答案,它是有效的(PHP 5.6),最重要的是使用 CURLFile() 来包含 realpath($file)。
        • 很高兴能帮到你
        【解决方案6】:

        这是一些将文件发送到 ftp 的生产代码(对您来说可能是一个很好的解决方案):

        // This is the entire file that was uploaded to a temp location.
        $localFile = $_FILES[$fileKey]['tmp_name']; 
        
        $fp = fopen($localFile, 'r');
        
        // Connecting to website.
        $ch = curl_init();
        
        curl_setopt($ch, CURLOPT_USERPWD, "email@email.org:password");
        curl_setopt($ch, CURLOPT_URL, 'ftp://@ftp.website.net/audio/' . $strFileName);
        curl_setopt($ch, CURLOPT_UPLOAD, 1);
        curl_setopt($ch, CURLOPT_TIMEOUT, 86400); // 1 Day Timeout
        curl_setopt($ch, CURLOPT_INFILE, $fp);
        curl_setopt($ch, CURLOPT_NOPROGRESS, false);
        curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, 'CURL_callback');
        curl_setopt($ch, CURLOPT_BUFFERSIZE, 128);
        curl_setopt($ch, CURLOPT_INFILESIZE, filesize($localFile));
        curl_exec ($ch);
        
        if (curl_errno($ch)) {
        
            $msg = curl_error($ch);
        }
        else {
        
            $msg = 'File uploaded successfully.';
        }
        
        curl_close ($ch);
        
        $return = array('msg' => $msg);
        
        echo json_encode($return);
        

        【讨论】:

        • FTP 有多快?会不会比 HTTP 上传慢很多?
        • @think123 FTP 有时可能更快或更慢。这取决于您的 ftp 服务器。如果他们限制了 ftp 上传,可能会减慢它的速度,但否则 ftp 和 http 应该差不多。
        • 啊,谢谢。我发现这个解决方案非常有用。
        • ftp 应该比 http 更快,因为 http 编码所有内容的方式。
        • @Toby 这并不像我们想的那么简单,有时 http 更快。在这里查看答案stackoverflow.com/questions/717200/…
        【解决方案7】:

        这是我的解决方案,我已经阅读了很多帖子,它们真的很有帮助,最后我用 cUrl 和 Php 为小文件构建了一个代码,我认为它真的很有用。

        public function postFile()
        {
        
        
                $file_url = "test.txt";  //here is the file route, in this case is on same directory but you can set URL too like "http://examplewebsite.com/test.txt"
                $eol = "\r\n"; //default line-break for mime type
                $BOUNDARY = md5(time()); //random boundaryid, is a separator for each param on my post curl function
                $BODY=""; //init my curl body
                $BODY.= '--'.$BOUNDARY. $eol; //start param header
                $BODY .= 'Content-Disposition: form-data; name="sometext"' . $eol . $eol; // last Content with 2 $eol, in this case is only 1 content.
                $BODY .= "Some Data" . $eol;//param data in this case is a simple post data and 1 $eol for the end of the data
                $BODY.= '--'.$BOUNDARY. $eol; // start 2nd param,
                $BODY.= 'Content-Disposition: form-data; name="somefile"; filename="test.txt"'. $eol ; //first Content data for post file, remember you only put 1 when you are going to add more Contents, and 2 on the last, to close the Content Instance
                $BODY.= 'Content-Type: application/octet-stream' . $eol; //Same before row
                $BODY.= 'Content-Transfer-Encoding: base64' . $eol . $eol; // we put the last Content and 2 $eol,
                $BODY.= chunk_split(base64_encode(file_get_contents($file_url))) . $eol; // we write the Base64 File Content and the $eol to finish the data,
                $BODY.= '--'.$BOUNDARY .'--' . $eol. $eol; // we close the param and the post width "--" and 2 $eol at the end of our boundary header.
        
        
        
                $ch = curl_init(); //init curl
                curl_setopt($ch, CURLOPT_HTTPHEADER, array(
                                 'X_PARAM_TOKEN : 71e2cb8b-42b7-4bf0-b2e8-53fbd2f578f9' //custom header for my api validation you can get it from $_SERVER["HTTP_X_PARAM_TOKEN"] variable
                                 ,"Content-Type: multipart/form-data; boundary=".$BOUNDARY) //setting our mime type for make it work on $_FILE variable
                            );
                curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/1.0 (Windows NT 6.1; WOW64; rv:28.0) Gecko/20100101 Firefox/28.0'); //setting our user agent
                curl_setopt($ch, CURLOPT_URL, "api.endpoint.post"); //setting our api post url
                curl_setopt($ch, CURLOPT_COOKIEJAR, $BOUNDARY.'.txt'); //saving cookies just in case we want
                curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1); // call return content
                curl_setopt ($ch, CURLOPT_FOLLOWLOCATION, 1); navigate the endpoint
                curl_setopt($ch, CURLOPT_POST, true); //set as post
                curl_setopt($ch, CURLOPT_POSTFIELDS, $BODY); // set our $BODY 
        
        
                $response = curl_exec($ch); // start curl navigation
        
             print_r($response); //print response
        
        }
        

        有了这个,我们应该在“api.endpoint.post”上发布以下变量 您可以使用此脚本轻松测试,并且您应该在最后一行的函数 postFile() 上收到此调试

        print_r($response); //打印响应

        public function getPostFile()
        {
        
            echo "\n\n_SERVER\n";
            echo "<pre>";
            print_r($_SERVER['HTTP_X_PARAM_TOKEN']);
            echo "/<pre>";
            echo "_POST\n";
            echo "<pre>";
            print_r($_POST['sometext']);
            echo "/<pre>";
            echo "_FILES\n";
            echo "<pre>";
            print_r($_FILEST['somefile']);
            echo "/<pre>";
        }
        

        在这里,它应该工作得很好,可能是更好的解决方案,但这确实有助于理解边界和 multipart/from-data mime 如何在 php 和 curl 库上工作,

        我最诚挚的问候,

        抱歉,我的英语不是我的母语。

        【讨论】:

        • 试图在不理解的情况下对 HTTP 进行逆向工程?
        【解决方案8】:

        这应该可行:

        $tmpfile = $_FILES['image']['tmp_name'];
        $filename = basename($_FILES['image']['name']);
        
        $data = array(
            'uploaded_file' => '@'.$tmpfile.';filename='.$filename,
        );
        
        $ch = curl_init();   
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        // set your other cURL options here (url, etc.)
        
        curl_exec($ch);
        

        在接收脚本中,您将:

        print_r($_FILES);
        /* which would output something like
             Array (
                [uploaded_file] => Array (
                    [tmp_name] => /tmp/f87453hf
                    [name] => myimage.jpg
                    [error] => 0
                    [size] => 12345
                    [type] => image/jpeg
                )
             )
        */
        

        然后,如果你想正确处理文件上传,你会做这样的事情:

        if (move_uploaded_file($_FILES['uploaded_file'], '/path/to/destination/file.zip')) {
           // do stuff
        }
        

        【讨论】:

        • 谢谢。我得到了这个解决方案的派生,但是当我将请求方法更改为PUT 时,它会失败($_FILES 数组是空的,但在设置为POST 时会按预期填充)。知道为什么会这样吗?
        • PHP $_FILES 数组永远不会在 PUT 请求中填充,因为 PHP 期望 $_FILES 通过 POST 上传。如果您想在 PUT 请求上接受文件上传,您必须手动解析 php://input 流以获取 multipart 格式(这不是太难,但无法在评论中解释...)。
        • @netcoder,如果服务位于不同的服务并且tmp 文件需要通过PUT 请求作为数据传递,那会是什么方法呢?
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-01-29
        • 1970-01-01
        • 2011-10-24
        • 1970-01-01
        相关资源
        最近更新 更多