
本文详解使用 google Ads php 客户端库调用 searchStream() 获取广告系列列表时返回空结果的核心原因——误用经理账号(Manager Account)的 Customer ID,而非子账号(Client Account)ID,并提供可立即运行的修复代码与关键配置说明。
本文详解使用 google ads php 客户端库调用 `searchstream()` 获取广告系列列表时返回空结果的核心原因——误用经理账号(manager account)的 customer id,而非子账号(client account)id,并提供可立即运行的修复代码与关键配置说明。
在 google Ads API 中,广告系列(Campaign)资源始终归属于具体的客户账号(Client Account),而非上级经理账号(Manager Account)。当你使用经理账号的 Customer ID(如 123456789)发起查询时,API 会严格按该 ID 所代表的账户上下文执行检索——而经理账号本身不直接拥有 Campaign 资源,因此 searchStream() 返回的流为空,导致 foreach ($stream->iterateAllElements() as …) 循环根本不会执行,var_dump() 也无输出。
✅ 正确做法是:
- 传入目标广告系列实际所属的子账号 Customer ID(例如 1138211281)作为 searchStream() 的第一个参数;
- 同时通过 withLoginCustomerId() 显式指定经理账号 ID(仅用于身份授权与访问权限校验),确保 OAuth2 凭据具备对该子账号的操作权限。
以下是修正后的完整示例(适配 symfony 控制器):
use GoogleAdsGoogleAdsLibV15GoogleAdsClient; use GoogleAdsGoogleAdsLibV15GoogleAdsClientBuilder; use GoogleAdsGoogleAdsLibV15OAuth2TokenBuilder; use GoogleAdsGoogleAdsV15ServicesGoogleAdsServiceClient; use GoogleAdsGoogleAdsV15ServicesSearchGoogleAdsStreamRequest; use GoogleAdsGoogleAdsV15ResourcesCampaign; // ... 在你的控制器方法中: $configPath = $this->getParameter('kernel.project_dir') . '/google_ads_php.ini'; if (!is_file($configPath)) { return $this->json(['error' => 'Config file not found: ' . $configPath]); } $oAuth2Credential = (new OAuth2TokenBuilder()) ->fromFile($configPath) ->build(); // ✅ 关键修复:设置 login_customer_id(经理账号ID)用于授权 // 注意:此处填入你的经理账号(MCC)ID,不含连字符,如 "1234567890" $googleAdsClient = (new GoogleAdsClientBuilder()) ->fromFile($configPath) ->withOAuth2Credential($oAuth2Credential) ->withLoginCustomerId('1234567890') // ← 必须设置!否则可能因权限不足静默失败 ->build(); $customerId = '1138211281'; // ← 此处必须为实际拥有Campaign的子账号ID try { $stream = $this->fetchCampaigns($googleAdsClient, $customerId); $campaigns = []; foreach ($stream->iterateAllElements() as $row) { $campaign = $row->getCampaign(); $campaigns[] = [ 'id' => $campaign->getId(), 'name' => $campaign->getName(), 'status' => $campaign->getStatus()->value() ]; } return $this->json([ 'total' => count($campaigns), 'campaigns' => $campaigns ]); } catch (GoogleAdsGoogleAdsUtilV15GoogleAdsException $e) { return $this->json([ 'error' => 'Google Ads API error', 'request_id' => $e->getRequestId(), 'errors' => array_map(fn($err) => [ 'code' => $err->getErrorCode()->getErrorCode(), 'message' => $err->getMessage() ], $e->getGoogleAdsFailure()->getErrors()) ], 400); } catch (GoogleApiCoreApiException $e) { return $this->json([ 'error' => 'gRPC API exception', 'message' => $e->getMessage() ], 500); } // —— 提取为独立方法便于复用 —— private function fetchCampaigns(GoogleAdsClient $client, string $customerId): GoogleAdsGoogleAdsLibV15GoogleAdsServerStreamDecorator { $serviceClient = $client->getGoogleAdsServiceClient(); $query = 'SELECT campaign.id, campaign.name, campaign.status FROM campaign ORDER BY campaign.id'; return $serviceClient->searchStream($customerId, $query); }
⚠️ 重要注意事项:
立即学习“PHP免费学习笔记(深入)”;
- Customer ID 格式:必须为纯数字(10 位),不可带连字符或空格(如 123-456-7890 → 应传 1234567890);
- 权限验证:确保 OAuth2 凭据已获该子账号的「标准访问」或「管理员访问」权限(可通过 Google Ads 界面 > 工具与设置 > 共享 > 访问权限确认);
- 错误静默风险:若遗漏 withLoginCustomerId(),某些场景下 API 可能返回空流而不抛异常,务必主动校验 $stream->iterateAllElements() 是否有元素;
- 分页与性能:searchStream() 默认单次响应最多 10,000 行,超量数据需结合 pageToken 分页处理(本例未涉及,但生产环境应考虑)。
总结:Google Ads PHP SDK 中“查不到 Campaign”问题,90% 源于 Customer ID 使用错误。牢记口诀:查询用子号,授权靠经理号。正确配置 withLoginCustomerId() 并传入真实子账号 ID,即可稳定获取广告系列列表。