<?php
namespace app\service;
use GuzzleHttp\Client;
use think\facade\Db as ThinkDb;
use app\model\ThirdUserAdvertiser;
use app\model\ThirdUser;
//use Webman\RedisQueue\Redis;
use Webman\RedisQueue\Client as QueueClient;
use app\event\GoogleAdsCustomers;
class GoogleOAuthService
{
public function getAuthUrl($state = '')
{
$clientId = getenv('GOOGLE_CLIENT_ID');
$redirectUri = getenv('GOOGLE_REDIRECT_URI');
$scope = 'https://www.googleapis.com/auth/adwords';
$responseType = 'code';
$accessType = 'offline';
// $state = 'state_parameter_passthrough_value'; // 可选,保护防止CSRF
// 将state保存到会话或数据库中,稍后验证
// $_SESSION['oauth_state'] = $state; // 使用PHP会话来保存state
// $authUrl = "https://accounts.google.com/o/oauth2/v2/auth?client_id=$clientId&redirect_uri=$redirectUri&scope=$scope&response_type=$responseType&state=$state";
if (!empty($state)) {
// 生成随机的state参数,防止CSRF攻击
// $state = bin2hex(random_bytes(16)); // 生成一个随机字符串
// $this->saveThirdUser($state);
$authUrl = "https://accounts.google.com/o/oauth2/v2/auth?client_id=$clientId&redirect_uri=$redirectUri&scope=$scope&response_type=$responseType&access_type=$accessType&state=$state";
} else {
$authUrl = "https://accounts.google.com/o/oauth2/v2/auth?client_id=$clientId&redirect_uri=$redirectUri&scope=$scope&response_type=$responseType&access_type=$accessType";
}
return $authUrl;
}
public function getThirdUserByRandomCode($state)
{
$tableName = 'bps_third_user';
$tableName = getenv('DB_PG_SCHEMA') ? getenv('DB_PG_SCHEMA') . '.' . $tableName : 'bps' . $tableName;
$result = ThinkDb::name($tableName)->where('random_code', $state)->find();
return $result;
}
public function getRefreshToken($authCode)
{
$client = new Client();
$response = $client->post('https://oauth2.googleapis.com/token', [
'form_params' => [
'code' => $authCode,
'client_id' => getenv('GOOGLE_CLIENT_ID'),
'client_secret' => getenv('GOOGLE_CLIENT_SECRET'),
'redirect_uri' => getenv('GOOGLE_REDIRECT_URI'),
'grant_type' => 'authorization_code',
],
]);
return json_decode($response->getBody(), true);
}
public function saveThirdUser($state)
{
//发起授权前,新记录到bps_third_user表
$data = [
'random_code' => $state,
'is_default' => 't',
'third_type' => 'google',
];
$tableName = 'bps_third_user';
$tableName = getenv('DB_PG_SCHEMA') ? getenv('DB_PG_SCHEMA') . '.' . $tableName : 'bps' . $tableName;
$sql = " INSERT INTO {$tableName}
(random_code, is_default, third_type)
VALUES (:random_code, :is_default, :third_type";
ThinkDb::execute($sql, $data);
}
public function getCustomerList($third_user_id = 0)
{
$tableName = 'bps_third_user_advertiser';
$tableName = getenv('DB_PG_SCHEMA') ? getenv('DB_PG_SCHEMA') . '.' . $tableName : 'bps' . $tableName;
$sql = "SELECT * FROM {$tableName} WHERE doc_ = :third_user_id";
$data = ['third_user_id' => $third_user_id];
return ThinkDb::query($sql, $data);
}
//保存或更新某个主体部广告账号
public function saveThirdUserAdvertiser($customer_id, $third_user_id, $login_customer_id, $customer)
{
// 确保 customer_id 和 third_user_id 是字符串
$customer_id = (string)$customer_id;
$tableName = 'bps_third_user_advertiser';
$tableName = getenv('DB_PG_SCHEMA') ? getenv('DB_PG_SCHEMA') . '.' . $tableName : 'bps' . $tableName;
$data = [
'doc_' => $third_user_id,
'advertiser_id' => $customer_id,
'advertiser_name' => $customer['descriptive_name'],
'google_login_customer_id' => $login_customer_id,
];
if ($customer['manager'] === true) {
$data['google_manager'] = 't';
} else {
$data['google_manager'] = 'f';
}
if ($customer['test_account'] === true) {
$data['google_test_account'] = 't';
} else {
$data['google_test_account'] = 'f';
}
// dump($data);
$sql = "
INSERT INTO {$tableName}
(advertiser_id,advertiser_name, doc_,google_login_customer_id,google_manager,google_test_account)
VALUES (:advertiser_id, :advertiser_name,:doc_,:google_login_customer_id,:google_manager,:google_test_account)
ON CONFLICT (advertiser_id,doc_)
DO UPDATE SET
advertiser_name = EXCLUDED.advertiser_name,
google_login_customer_id = EXCLUDED.google_login_customer_id,
google_manager = EXCLUDED.google_manager,
google_test_account = EXCLUDED.google_test_account
";
// dump($sql,$data);
ThinkDb::execute($sql, $data);
}
//绑定某个主体的广告账号
public function bindThirdUserAdvertiser($customer_id, $third_user_id)
{
$tableName = 'bps_third_user';
$tableName = getenv('DB_PG_SCHEMA') ? getenv('DB_PG_SCHEMA') . '.' . $tableName : 'bps' . $tableName;
$data = [
'id' => $third_user_id,
'user_id' => $customer_id,];
$sql = "
UPDATE {$tableName}
SET user_id = :user_id
WHERE id = :id
";
ThinkDb::execute($sql, $data);
}
public function updateThirdUserDefault($third_user_id, $is_default = 't'): void
{
$tableName = 'bps_third_user';
$tableName = getenv('DB_PG_SCHEMA') ? getenv('DB_PG_SCHEMA') . '.' . $tableName : 'bps' . $tableName;
$data = [
'is_default' => $is_default,
'id' => $third_user_id,];
$sql = "
UPDATE {$tableName}
SET is_default = :is_default
WHERE id = :id
";
ThinkDb::execute($sql, $data);
}
public function saveRefreshToken($refreshToken, $state = '')
{
// 使用ThinkORM保存数据到bps_third_user表
// $thirdUser = new \App\Models\ThirdUser();
// $thirdUser->access_token = $accessToken;
// $thirdUser->is_default = true;
// $thirdUser->random_code = bin2hex(random_bytes(16)); // 生成随机码
// $thirdUser->third_type = 'google';
// $thirdUser->user_id = $userId;
// $thirdUser->save();
$data = [
'access_token' => $refreshToken,
'is_default' => 'f',
'third_type' => 'google',
];
$tableName = 'bps_third_user';
$tableName = getenv('DB_PG_SCHEMA') ? getenv('DB_PG_SCHEMA') . '.' . $tableName : 'bps' . $tableName;
if (!empty($state)) {
$thirdUser = ThirdUser::where('user_id', $state)->where('third_type', 'google')->find(); // 获取第一个结果
// dump($thirdUser); return ($uid);
if ($thirdUser) {
$data['id'] = $thirdUser->id;
$sql = "
UPDATE {$tableName}
SET
access_token = :access_token,
is_default = :is_default,
third_type = :third_type
WHERE id = :id
";
} else {
$data['user_id'] = $state;
$sql = "
INSERT INTO {$tableName}
(access_token, is_default, third_type, user_id)
VALUES (:access_token, :is_default, :third_type, :user_id)
";
}
} else {
$sql = "
INSERT INTO {$tableName}
(access_token, is_default, third_type)
VALUES (:access_token, :is_default, :third_type)
";
}
ThinkDb::execute($sql, $data);
$options = [];
$options['refresh_token'] = $refreshToken;
$this->queue($options);
}
public function updateRefreshToken($refreshToken)
{
$customer_id = getenv('GOOGLE_ADS_CUSTOMER_ID');
//暂时update进行绑定
$tableName = "bps.bps_third_user";
// $sql = "UPDATE {$tableName} SET access_token = :access_token WHERE random_code = :random_code";
$sql = "UPDATE {$tableName} SET access_token = :access_token WHERE user_id = :user_id";
$data = [
'access_token' => $refreshToken, // 这里的 $accessToken 是您想要匹配的值
'user_id' => $customer_id, // 这里的 $accessToken 是您想要匹配的值
];
// 执行 SQL 语句
$result = ThinkDb::execute($sql, $data);
}
public function revokeToken($accessToken, $third_user_id)
{
$client = new Client();
$client->post('https://oauth2.googleapis.com/revoke', [
'form_params' => [
'token' => $accessToken,
],
]);
// 在数据库中删除或标记该`access_token(其实是refresh_token)`为无效
ThirdUserAdvertiser::where('doc_', $third_user_id)->delete();
$tableName = 'bps_third_user';
$tableName = getenv('DB_PG_SCHEMA') ? getenv('DB_PG_SCHEMA') . '.' . $tableName : 'bps' . $tableName;
$sql = "UPDATE {$tableName} SET access_token = :access_token WHERE id = :id";
$data = [
'access_token' => '', // 这里的 $accessToken 是您想要匹配的值
'id' => $third_user_id, // 这里的 $accessToken 是您想要匹配的值
];
// 执行 SQL 语句
$result = ThinkDb::execute($sql, $data);
// ThirdUser::where('access_token', $accessToken)->delete();
}
public function useRefreshToken($refreshToken)
{
$client = new Client();
$response = $client->post('https://oauth2.googleapis.com/token', [
'form_params' => [
'refresh_token' => $refreshToken,
'client_id' => getenv('GOOGLE_CLIENT_ID'),
'client_secret' => getenv('GOOGLE_CLIENT_SECRET'),
'grant_type' => 'refresh_token',
],
]);
$data = json_decode($response->getBody(), true);
return $data['access_token'];
}
/**
* 批量获取全部Google广告账号数据
*
*/
public function getGoogleAdCustomers($options = [])
{
if (!empty($options['refresh_token'])) {
$refreshToken = $options['refresh_token'];
// 获取符合条件的客户ID数组
$customers = ThirdUserAdvertiser::alias('tua')
->join('bps.bps_third_user tu', 'tua.doc_ = tu.id') // 连接 bps_third_user 表
->where('tu.third_type', 'google') // 筛选 third_type 为 google 的记录
->where('tu.access_token', $refreshToken) // 筛选 third_type 为 google 的记录
->field('CAST(tua.advertiser_id AS BIGINT) as customer_id,tua.google_login_customer_id as login_customer_id,tua.google_test_account as test_account,tua.google_manager as manager, tu.access_token as refresh_token') // 获取 advertiser_id 字段
->select(); // 执行查询
} else {
// 获取符合条件的客户ID数组
$customers = ThirdUserAdvertiser::alias('tua')
->join('bps.bps_third_user tu', 'tua.doc_ = tu.id') // 连接 bps_third_user 表
->where('tu.third_type', 'google') // 筛选 third_type 为 google 的记录
->field('CAST(tua.advertiser_id AS BIGINT) as customer_id,tua.google_login_customer_id as login_customer_id,tua.google_test_account as test_account,tua.google_manager as manager, tu.access_token as refresh_token') // 获取 advertiser_id 字段
->select(); // 执行查询
}
// 如果没有找到符合条件的广告主,抛出异常
if ($customers->isEmpty()) {
return [];
// throw new ApiException('No customers found for google third type');
}
// 转换为简单的数组(提取 advertiser_id)
return $customers->toArray();
}
public function queue($options = []): string
{
// 队列名
$queue = GoogleAdsCustomers::add_queue;
// 数据,可以直接传数组,无需序列化
// $options = ['to' => 'tom@gmail.com', 'content' => 'hello'];
// 投递消息
// Redis::send($queue, $options['data']);
QueueClient::send($queue, $options,10); //异步投递 延后15秒
// 投递延迟消息,消息会在60秒后处理
// Redis::send($queue, $options['data'], 60);
return $queue.' redis queue ok';
}
}