FacebookService.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. <?php
  2. namespace App\Services\Smm;
  3. use App\Services\Contracts\SmmPlatformInterface;
  4. use Carbon\Carbon;
  5. use Illuminate\Http\Request;
  6. use \Facebook\Facebook;
  7. use Illuminate\Support\Facades\Session;
  8. use \Facebook\Exceptions\FacebookResponseException;
  9. use \Facebook\Exceptions\FacebookSDKException;
  10. class FacebookService implements SmmPlatformInterface
  11. {
  12. public $fb = null;
  13. public $pageAccessToken = null;
  14. // 构造函数,传入配置信息
  15. public $configData = [];
  16. public function __construct($configData) {
  17. $this->configData = $configData;
  18. $this->fb = new Facebook([
  19. 'app_id' => env('SSM_FACEBOOK_APP_ID'), // 替换为您的App ID
  20. 'app_secret' => env('SSM_FACEBOOK_APP_SECRET'), // 替换为您的App Secret
  21. 'default_graph_version' => 'v19.0', // 使用当前版本
  22. ]);
  23. //$this->pageAccessToken = $pageAccessToken;
  24. }
  25. /*
  26. * OAuth 2.0 授权登录
  27. * 返回授权地址:https://example.com/fb-callback.php
  28. */
  29. public function login()
  30. {
  31. session_start();
  32. // 实现Facebook登录逻辑
  33. $helper = $this->fb->getRedirectLoginHelper();
  34. $permissions = [
  35. 'publish_video',
  36. 'pages_manage_cta',
  37. 'pages_show_list',
  38. 'business_management',
  39. 'pages_read_engagement',
  40. 'pages_manage_metadata',
  41. 'pages_read_user_content',
  42. 'pages_manage_ads',
  43. 'pages_manage_posts',
  44. 'pages_manage_engagement',
  45. ];
  46. $loginUrl = $helper->getLoginUrl(env('DIST_SITE_URL').'/dist/callback/facebook', $permissions);
  47. return ['status'=>true, 'data' => ['url'=>$loginUrl]];
  48. }
  49. /*
  50. * OAuth 2.0 授权回调
  51. * 授权成功后,得到access_token,refresh_token等信息, 保存到数据库中
  52. * 授权成功后,返回回调需要的数据
  53. */
  54. public function loginCallback(Request $request)
  55. {
  56. $helper = $this->fb->getRedirectLoginHelper();
  57. if (isset($_GET['state'])) {
  58. // 由于session的原因,这里需要重新设置state
  59. $helper->getPersistentDataHandler()->set('state', $_GET['state']);
  60. }
  61. try {
  62. $accessToken = $helper->getAccessToken();
  63. } catch (Facebook\Exceptions\FacebookResponseException $e) {
  64. return ['status' => false, 'data' => 'Graph API错误:' . $e->getMessage()];
  65. } catch (Facebook\Exceptions\FacebookSDKException $e) {
  66. return ['status' => false, 'data' => 'SDK错误:' . $e->getMessage()];
  67. }
  68. if (isset($accessToken)) {
  69. // 可选:将短期令牌转换为长期令牌(有效期约60天)
  70. $oAuth2Client = $this->fb->getOAuth2Client();
  71. $longLivedAccessToken = $oAuth2Client->getLongLivedAccessToken($accessToken);
  72. $useriInfo = $this->getFacebookUser($longLivedAccessToken->getValue());
  73. if ($useriInfo['status'] == false) {
  74. return ['status' => false, 'data' => $useriInfo['data']];
  75. }
  76. $expiresAt = $longLivedAccessToken->getExpiresAt();
  77. //DateTime转 carbon
  78. if ($expiresAt != null) {
  79. $expiresAt = $expiresAt->format('Y-m-d H:i:s');
  80. } else {
  81. $expiresAt = Carbon::now()->addDays(60)->format('Y-m-d H:i:s');
  82. }
  83. //$expiresAt = $expiresAt->format('Y-m-d H:i:s');
  84. //保存到数据库中
  85. return ['status' => true, 'data' => ['accessToken' => $longLivedAccessToken->getValue(),'accessToken_expiresAt'=>$expiresAt,'userName'=>$useriInfo['data']['name'],'userId'=>$useriInfo['data']['id']]];
  86. } else {
  87. return ['status' => false, 'data' => '无法获取访问令牌'];
  88. }
  89. }
  90. /*
  91. * 发布图片,可以发多个图片
  92. * $imagePath = ['/path/to/image1.jpg','/path/to/image2.jpg'];
  93. */
  94. public function postImage($message,$imagePaths,$accessToken) {
  95. // 获取pageAccessToken
  96. $info = $this->getAccountsInfo($accessToken);
  97. if ($info['status'] == false) {
  98. return ['status' => false, 'data' => $info['data']];
  99. }
  100. try {
  101. $requestContent = [];
  102. $responseContent = [];
  103. $postIds = [];
  104. foreach ($info['data'] as $value) {
  105. $mediaIds = [];
  106. $pageId = $value['id'];
  107. // 第一步:上传每张图片,获取 media_id
  108. foreach ($imagePaths as $imagePath){
  109. //dd($imagePath);
  110. $pageAccessToken = $value['pageAccessToken'];
  111. $postData = [
  112. 'source' => $this->fb->fileToUpload($imagePath), // 上传图片文件
  113. // 'source' => $imagePath, // 上传图片文件
  114. 'published' => false, // 添加描述
  115. ];
  116. $postUrl = '/'.$pageId.'/photos';
  117. $response = $this->fb->post(
  118. $postUrl,
  119. $postData,
  120. $pageAccessToken
  121. );
  122. $requestContent[] = ['postUrl'=>$postUrl,'data'=>$postData,'pageAccessToken'=>$pageAccessToken];
  123. $responseContent[] = $response->getDecodedBody();
  124. $mediaIds[] = $response->getDecodedBody()['id'];
  125. }
  126. // 第二步:发布帖子,附加多个 media_id
  127. $attachedMedia = array_map(function($id) {
  128. return ['media_fbid' => $id];
  129. }, $mediaIds);
  130. $feedParams = [
  131. 'message' => $message,
  132. 'attached_media' => json_encode($attachedMedia)
  133. ];
  134. $postUrl = '/'.$pageId.'/feed';
  135. $response = $this->fb->post(
  136. $postUrl,
  137. $feedParams, $pageAccessToken
  138. );
  139. $requestContent[] = ['postUrl'=>$postUrl,'data'=>$feedParams,'pageAccessToken'=>$pageAccessToken];
  140. $responseContent[] = $response->getDecodedBody();
  141. $postIds[] = $response->getDecodedBody()['id'];
  142. }
  143. return ['status' => true, 'data' => ['responseIds' => $postIds,'requestContent'=>$requestContent,'responseContent'=>$responseContent]];
  144. } catch (Facebook\Exceptions\FacebookResponseException $e) {
  145. $errorMsg = 'Graph API错误:' . $e->getMessage();
  146. } catch (Facebook\Exceptions\FacebookSDKException $e) {
  147. $errorMsg = 'SDK错误:' . $e->getMessage();
  148. }
  149. return ['status'=>false,'data' => $errorMsg];
  150. }
  151. /*
  152. * 发布视频,只能发一个视频
  153. */
  154. public function postVideo($message,$videoPath,$accessToken) {
  155. $info = $this->getAccountsInfo($accessToken);
  156. if ($info['status'] == false) {
  157. return ['status' => false, 'data' => $info['data']];
  158. }
  159. try {
  160. $postIds = [];
  161. $requestContent = [];
  162. $responseContent = [];
  163. foreach ($info['data'] as $value) {
  164. $pageId = $value['id'];
  165. $pageAccessToken = $value['pageAccessToken'];
  166. $data = [
  167. 'source' => $this->fb->fileToUpload($videoPath), // 上传图片文件
  168. 'description' => $message, // 添加描述
  169. ];
  170. $response = $this->fb->post(
  171. '/'.$pageId.'/videos',
  172. $data,
  173. $pageAccessToken
  174. );
  175. $requestContent[] = ['url'=>'/'.$pageId.'/videos','data'=>$data,'pageAccessToken'=>$pageAccessToken];
  176. $responseContent[] = $response->getDecodedBody();
  177. $postIds[] = $response->getDecodedBody()['id'];
  178. //第二步:发布帖子,附加 media_id
  179. }
  180. return ['status' => true, 'data' => ['responseIds' => $postIds,'requestContent'=>$requestContent,'responseContent'=>$responseContent]];
  181. } catch (Facebook\Exceptions\FacebookResponseException $e) {
  182. $errorMsg = 'Graph API错误:' . $e->getMessage();
  183. } catch (Facebook\Exceptions\FacebookSDKException $e) {
  184. $errorMsg = 'SDK错误:' . $e->getMessage();
  185. }
  186. return ['status'=>false,'data' => $errorMsg];
  187. }
  188. public function getComments($postId) {
  189. }
  190. public function replyToComment($commentId) {
  191. }
  192. public function deleteComment($commentId) {
  193. }
  194. /**
  195. * 获取Facebook用户信息
  196. * @param string $accessToken
  197. * @return array [
  198. * 'name' => string,
  199. * 'id' => string,
  200. * 'error' => string|null
  201. * ]
  202. */
  203. public function getFacebookUser($accessToken)
  204. {
  205. try {
  206. // 验证并设置访问令牌
  207. $this->fb->setDefaultAccessToken($accessToken);
  208. // 发送请求获取用户信息
  209. $response = $this->fb->get('/me?fields=name,id');
  210. $userNode = $response->getGraphUser();
  211. return [
  212. 'status' => true,
  213. 'data' => [
  214. 'name' => $userNode->getName(),
  215. 'id' => $userNode->getId(),
  216. ]
  217. ];
  218. } catch (FacebookResponseException $e) {
  219. // API 响应错误处理
  220. $errorMsg = 'Graph API Error: ' . $e->getMessage();
  221. } catch (FacebookSDKException $e) {
  222. // SDK 错误处理
  223. $errorMsg = 'SDK Error: ' . $e->getMessage();
  224. } catch (Exception $e) {
  225. // 其他错误处理
  226. $errorMsg = 'General Error: ' . $e->getMessage();
  227. }
  228. return [
  229. 'status' => false,
  230. 'data' => $errorMsg
  231. ];
  232. }
  233. public function getAccountsInfo($accessToken) {
  234. try {
  235. // 验证并设置访问令牌
  236. $this->fb->setDefaultAccessToken($accessToken);
  237. // 发送请求获取用户信息
  238. $response = $this->fb->get('/me/accounts');
  239. $userNode = $response->getDecodedBody();
  240. if ($userNode['data'] == [] || $userNode['data'] == null || $userNode['data'] == '') {
  241. return [
  242. 'status' => false,
  243. 'data' => '没有获取到任何账号信息'
  244. ];
  245. }
  246. $data = [];
  247. foreach ($userNode['data'] as $value) {
  248. $data[] = [
  249. 'id' => $value['id'],
  250. 'name' => $value['name'],
  251. 'pageAccessToken' => $value['access_token'],
  252. ];
  253. }
  254. return [
  255. 'status'=>true,
  256. 'data' => $data
  257. ];
  258. } catch (FacebookResponseException $e) {
  259. // API 响应错误处理
  260. $errorMsg = 'Graph API Error: ' . $e->getMessage();
  261. } catch (FacebookSDKException $e) {
  262. // SDK 错误处理
  263. $errorMsg = 'SDK Error: ' . $e->getMessage();
  264. } catch (Exception $e) {
  265. // 其他错误处理
  266. $errorMsg = 'General Error: ' . $e->getMessage();
  267. }
  268. return [
  269. 'status'=>false,
  270. 'data' => $errorMsg
  271. ];
  272. }
  273. }