2

Welcome everyone.

Here is a problem I have: I'm trying to send data with files to server using PHP and CURL. Server accepts data with 6 photos. And if there are less than 6 items in $_FILES array - it`s an error.

So if I send all 6 photos, everything goes perfectly. But if there are less photos, than value with empty photo goes to $_POST array.

I read Curl documentation but couldn`t find such possibility. How can it be done with CURL to send an empty value of File type?

2
  • 1
    You can try sending /dev/zero. Reading from that "file" will just give you an 'EOF', in essence a zero-byte file. Commented Feb 28, 2011 at 1:42
  • Tryed to send it, but server still don`t find it in $_FILES array. Anyway, thank you a lot, Marc. It seems to me, that there is no such function in Curl - as Pekka said. Commented Feb 28, 2011 at 20:07

4 Answers 4

2

I had the same problem and this works:

curl  -F "[email protected]" -F "file_2=@/dev/null;filename=" -F "file_3=@/dev/null;filename="
Sign up to request clarification or add additional context in comments.

1 Comment

On Windows, replacing /dev/null with NUL does the trick.
1

I don't think this is possible: In a browser, an unused file input will simply not be attached to the request at all, so there is no "empty file field" value to parse.

$_FILES will be constructed by PHP when it receives the request carrying the uploaded files.

Not sure what you are trying to do here though - don't you already know the request will fail if you don't have six images to send in the first place?

1 Comment

I just trying to create a script for automate every day work - loading data to server. Server is not mine, so I can only guess how its working. Yes, it fails if there are less than 6 images, and also fails if images are empty. I just could add an image 1*1px instead of empty images, but its not the solution that I need - because it shows all 6 photos and some of them just 1*1px. So I think you`re right - there is no such feature in Curl.
0

I had the same problem. My PHP solution is to send data like browser does. Just try to use example 1:

Example 1

$postData = '------WebKitFormBoundarywPZdrW1CWvlHZ7xB
Content-Disposition: form-data; name="image[3]"; filename=""
Content-Type: application/octet-stream


------WebKitFormBoundarywPZdrW1CWvlHZ7xB--';
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);


Works fine? Now we need some function to build this data automatically. Example 2 is simple illustration how to do it using CurlHelper::prepareMultiPartData() function. You need to create class CurlHelper before (code listed below).

Example 2

$data=array( //array can be multidimensional like this
  'image' => array( 
    3 => curl_file_create('', '', ''),
  ),
);
$boundary = 'webkit';
$postData = CurlHelper::prepareMultiPartData($data, $boundary);

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'url');//TODO set your own url
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
curl_setopt($ch, CURLOPT_HTTPHEADER, array("Content-Type: multipart/form-data; boundary=$boundary"));
$response = curl_exec($ch);

class CurlHelper

class CurlHelper {
  /**
   * @param array $data POST data. could be multidimensional array
   * @param string $boundary if $boundary == '' it will be generated automatically
   * @return string formatted POST data separeted with boundary like in browser.
   */
  static function prepareMultiPartData($data, &$boundary){
    $boundary = self::_createBoundary($boundary);
    $boundaryMiddle = "--$boundary\r\n";
    $boundaryLast = "--$boundary--\r\n";

    $res = self::_prepareMultipartData($data, ["\r\n"]);
    $res = join($boundaryMiddle, $res) . $boundaryLast;
    return $res;
  }

  static private function _createBoundary($boundaryCustom = '') {
    switch ($boundaryCustom) {
      case '':
        return uniqid('----').uniqid();
      case 'chrome':
      case 'webkit':
        return uniqid('----WebKitFormBoundary').'FxB';
      default:
        return $boundaryCustom;
    }
  }

  static private function _prepareMultipartData($data, $body, $keyTpl = ''){
    $ph = '{key}';
    if ( !$keyTpl ) {
      $keyTpl = $ph;
    }
    foreach ($data as $k => $v) {
      $paramName = str_replace($ph, $k, $keyTpl);
      if ( (class_exists('CURLFile') && $v instanceof \CURLFile) || strpos($v, '@') === 0 ) {
        if (is_string($v)) {
          $buf = strstr($v,'filename=');
          $buf = explode(';', $buf);
          $filename = str_replace('filename=', '', $buf[0]);
          $mimeType = (isset($buf[1])) ? str_replace('type=', '', $buf[1]) : 'application/octet-stream';
        } else {
          $filename = $v->name;
          $mimeType = $v->mime;
        }
        $str = 'Content-Disposition: form-data; name="' . $paramName . '"; filename="' . $filename . "\"\r\n";
        $str .= 'Content-Type: ' . $mimeType . "\r\n\r\n\r\n";
        $body[] = $str;
      } elseif ( is_array($v) ) {
        $body = self::_prepareMultipartData($v, $body, $paramName.'['.$ph.']');
      } else {
        $body[] = 'Content-Disposition: form-data; name="' . $paramName . "\"\r\n\r\n" . $v . "\r\n";
      }
    }
    return $body;
  }

} 

2 Comments

This is a massive code dump, explain what's going on!
@SterlingArcher Thx for your remark! I have edited my answer. I hope now my solution is clear.
0

This is how you can always send a file input field even if it is empty:

<input type="text" name="team_logo" hidden>
<input type="file" name="team_logo">

I'm not familiar with curl, but this works in php laravel.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.