Search code examples
phpcurlgoogle-drive-api

upload CSV file to google drive with curl fails: "Bad content type. Please use multipart."


I'm trying to upload a CSV file to google drive and I'm getting the error described in the subject of this post.

this is my code:

I think my error is in the content generation. I've seen some other posts but I can't resolve it yet.

this is the code

public function uploadFileToDrive($token, $fileContent){
        echo "Iniciando subida de archivo a drive .... \n";
        
        try {
            $apiUrl = 'https://www.googleapis.com/';
            $ch1 = curl_init();

           
            /* MEtODO 1 */
            $mime_type = 'text/csv';
            $data = '
            --section_divider
            Content-Type: application/json; charset=UTF-8
            {
                "name": "test.xlsx",
            }

            --section_divider
            Content-Type: '.$mime_type.',
            '.$fileContent.'
            --section_divider--
            ';

           
            //print_r($body);die();
            curl_setopt($ch1, CURLOPT_URL, $apiUrl . 'upload/drive/v3/files?uploadType=multipart');
            curl_setopt($ch1, CURLOPT_POST, 1);
            curl_setopt($ch1, CURLOPT_POSTFIELDS, $data);
            curl_setopt($ch1, CURLOPT_RETURNTRANSFER, true);

            curl_setopt($ch1, CURLOPT_HTTPHEADER, array('Content-Type: multipart/related;section_divider', 'Authorization: Bearer' . $token) );

            $response = curl_exec($ch1);
            if ($response === false) {
                echo 'Curl error: ' . curl_error($ch1);
            } else {
                echo "Operation completed without any errors \n";
                $output = $response;
            }
            curl_close($ch1);
            var_dump($output);die();
            return $output;

        } catch (Exception $e) {
            print "An error occurred: " . $e->getMessage();
        }

    }

I don't know what I'm doing wrong

I hope you can give some advice
thanks

The expected results. See the CSV file uploaded on google drive.

See in the console a response indicating that all it's done


Solution

  • I thought that in your script, $data and Content-Type are required to be modified. So, how about the following modification?

    From:

    $data = '
    --section_divider
    Content-Type: application/json; charset=UTF-8
    {
        "name": "test.xlsx",
    }
    
    --section_divider
    Content-Type: '.$mime_type.',
    '.$fileContent.'
    --section_divider--
    ';
    
    
    //print_r($body);die();
    curl_setopt($ch1, CURLOPT_URL, $apiUrl . 'upload/drive/v3/files?uploadType=multipart');
    curl_setopt($ch1, CURLOPT_POST, 1);
    curl_setopt($ch1, CURLOPT_POSTFIELDS, $data);
    curl_setopt($ch1, CURLOPT_RETURNTRANSFER, true);
    
    curl_setopt($ch1, CURLOPT_HTTPHEADER, array('Content-Type: multipart/related;section_divider', 'Authorization: Bearer' . $token) );
    

    To:

    $data = '
    --section_divider
    Content-Type: application/json; charset=UTF-8
    
    {"name": "test.csv", "mimeType": "text/csv"}
    
    --section_divider
    Content-Type: '.$mime_type.',
    
    '.$fileContent.'
    
    --section_divider--';
    
    //print_r($body);die();
    curl_setopt($ch1, CURLOPT_URL, $apiUrl . 'upload/drive/v3/files?uploadType=multipart');
    curl_setopt($ch1, CURLOPT_POST, 1);
    curl_setopt($ch1, CURLOPT_POSTFIELDS, $data);
    curl_setopt($ch1, CURLOPT_RETURNTRANSFER, true);
    
    curl_setopt($ch1, CURLOPT_HTTPHEADER, array('Content-Type: multipart/related;boundary=section_divider', 'Authorization: Bearer ' . $token) );
    
    • By this modification, the following file metadata of the uploaded file is returned.

        {
         "kind": "drive#file",
         "id": "###",
         "name": "test.csv",
         "mimeType": "text/csv"
        }
      

    Note:

    • In your script, although you want to upload a CSV file, the filename is test.xlsx. And also, the mimeType is not set. By this, the mimeType of the uploaded file is automatically set as application/vnd.openxmlformats-officedocument.spreadsheetml.sheet. When you want to upload a CSV file as the CSV data, please set the mimeType of text/csv.

    • If you want to upload the CSV data as Google Spreadsheet, please set the mimeType as "mimeType": "application/vnd.google-apps.spreadsheet" instead of "mimeType": "text/csv".

    • In your script, 'Authorization: Bearer' . $token is used. In this case, if $token is ya29.###, it is required to insert a space like 'Authorization: Bearer ' . $token. In my modification, 'Authorization: Bearer ' . $token is used. Please be careful about this.

    Reference:

    Added 1:

    From your following reply,

    I did the changes as you has recommended. the process ends, but file isn't uploaded on the drive. I've put a print_r($output) and I get this message: "Invalid multipart request with 0 mime parts."

    In order to upload the file with multipart/related, the spaces and the line breaks in the request body are important. From your current error message, I'm worried about it. So, in order to avoid this, I would like to propose one more modification. Please modify as follows. "### From:" is the same as the above modification.

    To:

    $data = implode([
        "--section_divider\r\n",
        "Content-Type: application/json; charset=UTF-8\r\n\r\n",
        "{\"name\": \"test.csv\", \"mimeType\": \"text/csv\"}\r\n\r\n",
        "--section_divider\r\n",
        "Content-Type: ".$mime_type."\r\n\r\n",
        $fileContent."\r\n\r\n",
        "--section_divider--",
    ], "");
    
    //print_r($body);die();
    curl_setopt($ch1, CURLOPT_URL, $apiUrl . 'upload/drive/v3/files?uploadType=multipart');
    curl_setopt($ch1, CURLOPT_POST, 1);
    curl_setopt($ch1, CURLOPT_POSTFIELDS, $data);
    curl_setopt($ch1, CURLOPT_RETURNTRANSFER, true);
    
    curl_setopt($ch1, CURLOPT_HTTPHEADER, array('Content-Type: multipart/related;boundary=section_divider', 'Authorization: Bearer ' . $token) );
    
    • When I tested the above 2 modified scripts, I confirmed that no error occurs and the CSV data is uploaded with multipart/related in my Google Drive.

    Added 2:

    From your following reply,

    I try with the new code. now returns { "kind": "drive#file", "id": "1Qorzy6e5Vm_x2PU_lGdF066SI8c76DZy", "name": "test.csv", "mimeType": "text/csv" } BUT the big "but", the file isn't appears on google drive.

    Yes your script works. I get the token through service account.

    It was found that your error of Invalid multipart request with 0 mime parts. was resolved, and your question was resolved.

    About BUT the big "but", the file isn't appears on google drive., I think that this is a new issue. In this case, it is required to know about the access token.

    If your access token is retrieved from OAuth2, I think that the uploaded file can be seen in the root folder of your Google Drive. So, from BUT the big "but", the file isn't appears on google drive., I guessed that your access token might be retrieved from the service account. If your access token is retrieved from the service account, the uploaded file is put into the root folder of the service account. By this, the file cannot be directly seen in your Google Drive. If you want to see the uploaded file in your Google account, please use the access token retrieved with OAuth2 from your account. Or, if you are required to use the service account, for example, how about the following flow?

    1. Create a new folder in your Google drive.

    2. Share the created folder with the email of the service account as the writer. And please copy the folder ID.

    3. Upload the file to your folder. In this case, please modify the above script as follows.

      • From

          "{\"name\": \"test.csv\", \"mimeType\": \"text/csv\"}\r\n\r\n",
        
      • To

          "{\"name\": \"test.csv\", \"mimeType\": \"text/csv\", \"parents\": [\"###folderID###\"]}\r\n\r\n",
        
      • Please replace ###folderID### with your folder ID.

    Of course, you can also see the uploaded file in the Google Drive of the service account by sharing the uploaded file with your Google account. In that case, please use Permissions of Drive API.