bucketName = $config['bucket_name'] ?? null; } // Load Service Account Path $this->serviceAccountPath = dirname(__DIR__, 2) . '/apikey/google_service_account.json'; } public function getBucketName() { return $this->bucketName; } private function getAccessToken() { if ($this->accessToken) return $this->accessToken; if (!file_exists($this->serviceAccountPath)) { throw new Exception("Service account file not found: " . $this->serviceAccountPath); } $serviceAccount = json_decode(file_get_contents($this->serviceAccountPath), true); if (!$serviceAccount) { throw new Exception("Invalid service account JSON"); } $now = time(); $jwtHeader = base64_encode(json_encode(['alg' => 'RS256', 'typ' => 'JWT'])); $jwtClaim = base64_encode(json_encode([ 'iss' => $serviceAccount['client_email'], 'scope' => 'https://www.googleapis.com/auth/devstorage.full_control', 'aud' => 'https://oauth2.googleapis.com/token', 'exp' => $now + 3600, 'iat' => $now ])); $privateKey = openssl_pkey_get_private($serviceAccount['private_key']); if (!$privateKey) throw new Exception("Failed to load private key"); openssl_sign($jwtHeader . '.' . $jwtClaim, $signature, $privateKey, OPENSSL_ALGO_SHA256); openssl_free_key($privateKey); $jwt = $jwtHeader . '.' . $jwtClaim . '.' . base64_encode($signature); $ch = curl_init('https://oauth2.googleapis.com/token'); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([ 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', 'assertion' => $jwt ])); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($httpCode !== 200) { throw new Exception("Failed to get OAuth token: " . $response); } $data = json_decode($response, true); $this->accessToken = $data['access_token']; return $this->accessToken; } public function upload($filePath, $objectName) { $token = $this->getAccessToken(); $fileContent = file_get_contents($filePath); $mimeType = 'application/json'; $url = 'https://storage.googleapis.com/upload/storage/v1/b/' . urlencode($this->bucketName) . '/o?uploadType=media&name=' . urlencode($objectName); $ch = curl_init($url); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'Authorization: Bearer ' . $token, 'Content-Type: ' . $mimeType, 'Content-Length: ' . strlen($fileContent) ]); curl_setopt($ch, CURLOPT_POSTFIELDS, $fileContent); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($httpCode == 200) { return true; } else { throw new Exception("GCS Upload Failed ($httpCode): " . $response); } } public function download($objectName, $savePath) { $token = $this->getAccessToken(); $url = 'https://storage.googleapis.com/storage/v1/b/' . urlencode($this->bucketName) . '/o/' . urlencode($objectName) . '?alt=media'; $ch = curl_init($url); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'Authorization: Bearer ' . $token ]); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $content = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($httpCode == 200) { file_put_contents($savePath, $content); return true; } else { throw new Exception("GCS Download Failed ($httpCode)"); } } } ?>