PHP实现Azure文件上传至Google Drive 解决Untitled文件名问题
解决Google Drive API上传文件命名异常及Azure URL上传需求问题
先给你拆解核心问题:你遇到的Untitled.pdf命名问题,本质是因为用了uploadType=media的上传方式——这种方式只传文件二进制内容,不带任何元数据(比如文件名),所以Drive会自动分配默认名称。要解决这个,得改用multipart类型上传,同时传递文件内容和元数据。另外针对你要从Azure URL直接上传、设置文件公开权限的需求,我给你整理了完整的修正方案:
一、修复文件命名为Untitled的问题 + 支持Azure URL上传
下面是重构后的uploadFile函数,既解决命名问题,又能直接从Azure URL拉取文件上传:
function uploadFile($credentials, $azureFileUrl, $fileName) { global $GAPIS; // 1. 从Azure URL获取文件内容(如果Azure文件带SAS权限,直接传带SAS的完整URL即可) $fileContent = file_get_contents($azureFileUrl); if ($fileContent === false) { throw new Exception("无法从Azure地址获取文件,请检查URL有效性"); } // 2. 构造文件元数据(指定文件名、类型等) $metadata = json_encode([ 'title' => $fileName, 'mimeType' => 'application/pdf' // 可根据实际文件类型调整,或自动检测MIME ]); // 3. 构造多部分请求的边界标识 $boundary = uniqid(); $delimiter = "--" . $boundary; $closeDelimiter = "--" . $boundary . "--"; // 4. 拼接多部分请求体:元数据块 + 文件内容块 $body = $delimiter . "\r\n" . "Content-Type: application/json\r\n\r\n" . $metadata . "\r\n" . $delimiter . "\r\n" . "Content-Type: application/pdf\r\n\r\n" . $fileContent . "\r\n" . $closeDelimiter; // 5. 初始化cURL请求 $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $GAPIS . 'upload/drive/v2/files?uploadType=multipart'); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $body); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'Authorization: Bearer ' . getAccessToken($credentials), 'Content-Type: multipart/related; boundary=' . $boundary, 'Content-Length: ' . strlen($body) ]); $postResult = curl_exec($ch); if (curl_errno($ch)) { throw new Exception("上传请求出错:" . curl_error($ch)); } curl_close($ch); $response = json_decode($postResult, true); if (isset($response['error'])) { throw new Exception("Drive API返回错误:" . $response['error']['message']); } // 6. 上传完成后自动设置文件为公开可读 setFilePublic($credentials, $response['id']); // 返回可存入数据库的Drive文件信息 return [ 'fileId' => $response['id'], 'publicUrl' => $response['alternateLink'], 'fileName' => $response['title'] ]; }
二、添加设置文件公开权限的函数
上面的函数里调用了setFilePublic,专门用来实现你的“公开访问权限”需求:
function setFilePublic($credentials, $fileId) { global $GAPIS; $permissionData = json_encode([ 'type' => 'anyone', // 允许任何人访问 'role' => 'reader' // 只读权限,避免被修改 ]); $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $GAPIS . 'drive/v2/files/' . $fileId . '/permissions'); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $permissionData); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'Authorization: Bearer ' . getAccessToken($credentials), 'Content-Type: application/json' ]); $result = curl_exec($ch); if (curl_errno($ch)) { throw new Exception("设置权限出错:" . curl_error($ch)); } curl_close($ch); $response = json_decode($result, true); if (isset($response['error'])) { throw new Exception("权限设置API返回错误:" . $response['error']['message']); } return true; }
三、额外优化建议
- Azure文件获取的备选方案:如果服务器禁用了
file_get_contents,可以改用cURL拉取Azure文件:
function getAzureFileContent($azureUrl) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $azureUrl); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $content = curl_exec($ch); curl_close($ch); return $content; }
然后在uploadFile里替换$fileContent = getAzureFileContent($azureFileUrl);即可。
- 回到Google Client库的简化方案:其实你最初用的Google官方Client库更易维护,也能直接实现Azure URL上传,代码更简洁:
$client->setAccessToken($_SESSION['accessToken']); $service = new Google_DriveService($client); // 示例:循环处理多个Azure文件 $azureFiles = [ "Invoice-2024-05.pdf" => "https://your-azure-storage.blob.core.windows.net/container/invoice.pdf", "Report-Q2.pdf" => "https://your-azure-storage.blob.core.windows.net/container/report.pdf" ]; foreach ($azureFiles as $fileName => $azureUrl) { $fileContent = file_get_contents($azureUrl); $file = new Google_DriveFile(); $file->setTitle($fileName); $file->setMimeType('application/pdf'); // 上传文件 $createdFile = $service->files->insert( $file, ['data' => $fileContent, 'mimeType' => 'application/pdf'] ); // 设置公开权限 $permission = new Google_Permission(); $permission->setType('anyone'); $permission->setRole('reader'); $service->permissions->insert($createdFile->getId(), $permission); // 把公开URL存入数据库 $publicUrl = $createdFile->getAlternateLink(); // 这里执行你的数据库插入逻辑 }
四、调用示例
$credentials = getStoredCredentials($STORE_PATH); if (!$credentials) { requestAuthCode(); } try { $azureUrl = "https://your-azure-storage.blob.core.windows.net/container/your-file.pdf"; $fileName = "客户合同-2024.pdf"; $driveFileInfo = uploadFile($credentials, $azureUrl, $fileName); // 将$driveFileInfo['publicUrl']存入数据库 echo "文件上传成功,公开访问地址:" . $driveFileInfo['publicUrl']; } catch (Exception $e) { echo "操作失败:" . $e->getMessage(); }
内容的提问来源于stack exchange,提问作者Vasim Shaikh
相关产品推荐
相关产品推荐

