7

How do I upload multiple files in an array using CURLFile and curl_setopt?

Using the data array as it would throw an error (can't convert an array to a string) and http_build_query on the data would corrupt the CURLFile objects.

The data I have to upload looks like that:

[
    'mode' => 'combine',
    'input' => 'upload',
    'format' => $outputformat,
    'files' => [
        [0] => CURLFile object,
        [1] => CURLFile object,
        [x] => ...
    ]
]

3 Answers 3

9

PHP 5.5+ has a function to create files without using CURLFile: curl_file_create.

You can upload multiple files like this:

<?php

$files = [
    '/var/file/something.txt',
    '/home/another_file.txt',
];

// Set postdata array
$postData = ['somevar' => 'hello'];

// Create array of files to post
foreach ($files as $index => $file) {
    $postData['file[' . $index . ']'] = curl_file_create(
        realpath($file),
        mime_content_type($file),
        basename($file)
    );
}

$request = curl_init('https://localhost/upload');
curl_setopt($request, CURLOPT_POST, true);
curl_setopt($request, CURLOPT_POSTFIELDS, $postData);
curl_setopt($request, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($request);

if ($result === false) {
    error_log(curl_error($request));
}

curl_close($request);

This will be received on the server as an array under file the same as if there was a posted form, this is $_FILES:

Array
(
    [file] => Array
        (
            [name] => Array
                (
                    [0] => 1.txt
                    [1] => 2.txt
                )

            [type] => Array
                (
                    [0] => text/plain
                    [1] => text/plain
                )

            [tmp_name] => Array
                (
                    [0] => /private/var/folders/cq/7262ntt15mqdmylblg9p1wf80000gn/T/phpp8SsKD
                    [1] => /private/var/folders/cq/7262ntt15mqdmylblg9p1wf80000gn/T/php73ijEP
                )

            [error] => Array
                (
                    [0] => 0
                    [1] => 0
                )

            [size] => Array
                (
                    [0] => 6
                    [1] => 6
                )

        )

)

This is $_POST:

Array
(
    [somevar] => hello
)
Sign up to request clarification or add additional context in comments.

5 Comments

The problem is that the server is an API and the files must be placed in a "files" array.
Are they expecting files to be an array of files like you posted the data or an array of files in some other format such as a base64 encoded string of the file contents?
Either files or base64, but the latter option is discouraged for big files.
It does not work. My array seems well formed (files[0] => CURLFile Object, files[1] => CURLFile Object, ...) but curl_exec run until the timeout...
it does not work. I've tried a lot, but I'm facing exactly the same challenge here, to send multiple files to an API via CURL.
5

The index is part of the key

[
    'mode' => 'combine',
    'input' => 'upload',
    'format' => $outputformat,
    'files[0]' => CURLFile object,
    'files[1]' => CURLFile object,
    'files[x]' => CURLFile object
     ...
    ]
]

Comments

2

I know, this is the old questions but I faced the same problem as well. I haven't found solution for cURL but was able to solve the problem using file_get_contents. Note that I use the same key for all of the files.

Example:

/* Prepare request */
$multipartBoundary = "--------------------------" . microtime(true);
$contentType = "multipart/form-data; boundary={$multipartBoundary}";
$content = "";

// Files
$paramName = "files";
foreach ($files as $file) {
    $fileBaseName = basename($file);
    $fileContent = file_get_contents($file);
    $content .= "--{$multipartBoundary}\r\n";
    $content .= "Content-Disposition: form-data; name=\"{$paramName}\"; filename=\"{$fileBaseName}\"\r\n";
    $content .= "Content-Type: application/zip\r\n\r\n{$fileContent}\r\n";
}

// Regular params
foreach ($params $key=>$value) {
    $content .= "--{$multipartBoundary}\r\n";
    $content .= "Content-Disposition: form-data; name=\"{$key}\"\r\n\r\n{$value}\r\n";
}

// End
$content .= "--{$multipartBoundary}--\r\n";

// Create context
$context = stream_context_create(['http' => [
    'header' => "Content-type: {$contentType}",
    'method'  => "POST",
    'timeout' => 5, // Seconds
    'content' => $content,
    'ignore_errors' => true // Do not report about HTTP errors as PHP Warnings
]]);



/* Send request */
$apiUrl = "https//api.example.com";
$endpoint = "/upload";
$url = $apiUrl . $endpoint;
$body = file_get_contents($url, false, $context);
$headerInfo = explode(" ", $http_response_header[0]);
$code = (int)$headerInfo[1];
$message = implode(" ", array_slice($headerInfo, 2));



/* Return result */
return [$body, $code, $message];

1 Comment

This is the only way I could get it working, thanks for sharing!

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.