PHP Curl实现Google Drive多部分上传遇badContent错误求助
Google Drive Multipart上传报错:Unsupported content with type: application/octet-stream
能完成两步式媒体上传,但尝试实现Google Drive的multipart上传(不想手动处理边界逻辑)时,始终返回badContent错误,错误信息如下:
[message] => Unsupported content with type: application/octet-stream
推测问题可能是MIME类型错误,或是POST请求中未识别到文件,求解决。
现有代码
public function uploadFileToGoogleDriveMulti($accessToken, $filePath, $fileType, $fileName, $folderID) { /* trigger_error("DEBUG: ".print_r($accessToken, true)); trigger_error("DEBUG: ".print_r($filePath, true)); trigger_error("DEBUG: ".print_r($fileType, true)); trigger_error("DEBUG: ".print_r($fileName, true)); trigger_error("DEBUG: ".print_r($folderID, true)); */ $cFile = curl_file_create($filePath, $fileType, $fileName); //trigger_error("DEBUG: ".print_r($cFile, true)); $curl = curl_init(); $postdata = array ( 'metadata' => json_encode (array ( 'name' => $fileName, //'parents' => array($folderID), //'Content-Type' => 'application/json; charset=UTF-8' ) ), //'file' => new CURLFILE($filePath, $fileType), //'file_contents'=>$cFile 'file' => $cFile, //'Content-Type' => $fileType . '\n\n' . file_get_contents($filePath) ); $headers = array ( 'Authorization: Bearer ' . $accessToken, //'Content-Type: multipart/form-data', 'Content-Type: multipart/related', //'Content-Length: ' . mb_strlen(serialize($postdata), '8bit') ); $post_string = json_encode($data); curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($curl, CURLOPT_URL, Config::GOOGLE_DRIVE_FILE_UPLOAD_URI . '?uploadType=multipart'); //curl_setopt($curl, CURLOPT_BINARYTRANSFER, 1); curl_setopt($curl, CURLOPT_POST, 1); curl_setopt($curl, CURLOPT_POSTFIELDS, $postdata); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); $curlResponse = json_decode(curl_exec($curl), true); $responseCode = curl_getinfo($curl, CURLINFO_HTTP_CODE); trigger_error("DEBUG: ".print_r($curlResponse, true)); if ($responseCode != 200) { $errorMessage = 'Failed to upload file to drive'; if(curl_errno($curl)) { $errorMessage = curl_error($curl); } throw new Exception('Error ' . $responseCode . ': ' . $errorMessage); } curl_close($curl); return $curlResponse['id']; }
问题分析与解决方案
核心问题:Google Drive的multipart/related上传要求每个请求部分必须明确指定Content-Type,而用curl数组传递CURLOPT_POSTFIELDS时,curl会默认按multipart/form-data处理,且无法为metadata部分指定application/json类型,导致Drive无法识别元数据,进而触发错误。
以下是修正后的代码,手动构造符合要求的multipart/related请求体:
public function uploadFileToGoogleDriveMulti($accessToken, $filePath, $fileType, $fileName, $folderID) { // 构造元数据JSON $metadata = json_encode([ 'name' => $fileName, 'parents' => [$folderID] // 取消注释可指定上传目录 ]); // 读取文件内容 $fileContent = file_get_contents($filePath); if ($fileContent === false) { throw new Exception('Failed to read file: ' . $filePath); } // 生成随机边界字符串 $boundary = '----GoogleDriveBoundary' . uniqid(); // 构造multipart/related请求体 $body = "--{$boundary}\r\n"; $body .= "Content-Type: application/json; charset=UTF-8\r\n\r\n"; $body .= $metadata . "\r\n"; $body .= "--{$boundary}\r\n"; $body .= "Content-Type: {$fileType}\r\n\r\n"; $body .= $fileContent . "\r\n"; $body .= "--{$boundary}--\r\n"; $curl = curl_init(); $headers = [ 'Authorization: Bearer ' . $accessToken, 'Content-Type: multipart/related; boundary=' . $boundary, 'Content-Length: ' . strlen($body) ]; curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true); // 生产环境建议开启SSL验证 curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2); curl_setopt($curl, CURLOPT_URL, Config::GOOGLE_DRIVE_FILE_UPLOAD_URI . '?uploadType=multipart'); curl_setopt($curl, CURLOPT_POST, true); curl_setopt($curl, CURLOPT_POSTFIELDS, $body); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); curl_setopt($curl, CURLOPT_BINARYTRANSFER, true); // 确保二进制文件正确传输 $curlResponse = json_decode(curl_exec($curl), true); $responseCode = curl_getinfo($curl, CURLINFO_HTTP_CODE); trigger_error("DEBUG: ".print_r($curlResponse, true)); if ($responseCode != 200) { $errorMessage = 'Failed to upload file to drive'; if(curl_errno($curl)) { $errorMessage = curl_error($curl); } throw new Exception('Error ' . $responseCode . ': ' . $errorMessage); } curl_close($curl); return $curlResponse['id']; }
关键修正点
- 手动构造
multipart/related请求体,明确为元数据部分指定application/json的Content-Type - 生成唯一边界字符串,确保请求体格式符合标准
- 修复了不安全的SSL验证设置(生产环境建议保持开启)
- 增加文件读取失败的异常处理
- 启用
CURLOPT_BINARYTRANSFER确保二进制文件正确传输
内容的提问来源于stack exchange,提问作者Beast
相关产品推荐
相关产品推荐

