TwitterService.php 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. <?php
  2. namespace App\Services\Smm;
  3. use App\Services\Contracts\SmmPlatformInterface;
  4. use Abraham\TwitterOAuth\TwitterOAuth;
  5. use Carbon\Carbon;
  6. use Illuminate\Http\Request;
  7. class TwitterService implements SmmPlatformInterface
  8. {
  9. protected $configData;
  10. protected $twitterOAuth;
  11. protected $consumerKey;
  12. protected $consumerSecret;
  13. protected $oauthCallbackUrl;
  14. public function __construct($configData)
  15. {
  16. $this->configData = $configData;
  17. $this->consumerKey = env('TWITTER_CONSUMER_KEY');
  18. $this->consumerSecret = env('TWITTER_CONSUMER_SECRET');
  19. $this->oauthCallbackUrl = env('DIST_SITE_URL') . '/dist/callback/twitter';
  20. if (!empty($configData['access_token']) && !empty($configData['access_token_secret'])) {
  21. $this->twitterOAuth = new TwitterOAuth(
  22. $this->consumerKey,
  23. $this->consumerSecret,
  24. $configData['access_token'],
  25. $configData['access_token_secret']
  26. );
  27. }
  28. }
  29. public function login()
  30. {
  31. $connection = new TwitterOAuth($this->consumerKey, $this->consumerSecret);
  32. $requestToken = $connection->oauth('oauth/request_token', ['oauth_callback' => $this->oauthCallbackUrl]);
  33. session(['twitter_oauth_token' => $requestToken['oauth_token']]);
  34. session(['twitter_oauth_token_secret' => $requestToken['oauth_token_secret']]);
  35. $url = $connection->url('oauth/authorize', ['oauth_token' => $requestToken['oauth_token']]);
  36. return [
  37. 'status' => true,
  38. 'data' => ['url' => $url]
  39. ];
  40. }
  41. public function loginCallback(Request $request)
  42. {
  43. $oauthToken = $request->get('oauth_token');
  44. $oauthVerifier = $request->get('oauth_verifier');
  45. $requestToken = session('twitter_oauth_token');
  46. $requestTokenSecret = session('twitter_oauth_token_secret');
  47. $connection = new TwitterOAuth(
  48. $this->consumerKey,
  49. $this->consumerSecret,
  50. $requestToken,
  51. $requestTokenSecret
  52. );
  53. $accessToken = $connection->oauth('oauth/access_token', [
  54. 'oauth_verifier' => $oauthVerifier
  55. ]);
  56. return [
  57. 'status' => true,
  58. 'data' => [
  59. 'accessToken' => $accessToken['oauth_token'],
  60. 'accessTokenSecret' => $accessToken['oauth_token_secret'],
  61. 'userId' => $accessToken['user_id'],
  62. 'userName' => $accessToken['screen_name'],
  63. ]
  64. ];
  65. }
  66. public function postImage($message, $imagePaths, $accessToken = null)
  67. {
  68. try {
  69. $mediaIds = [];
  70. foreach ($imagePaths as $imagePath) {
  71. if (!file_exists($imagePath)) {
  72. throw new \Exception("图片不存在: {$imagePath}");
  73. }
  74. $uploadedMedia = $this->twitterOAuth->upload('media/upload', [
  75. 'media' => $imagePath
  76. ]);
  77. if (isset($uploadedMedia->error)) {
  78. throw new \Exception('媒体上传失败: ' . json_encode($uploadedMedia));
  79. }
  80. $mediaIds[] = $uploadedMedia->media_id_string;
  81. }
  82. $tweet = $this->twitterOAuth->post('statuses/update', [
  83. 'status' => $message,
  84. 'media_ids' => implode(',', $mediaIds)
  85. ]);
  86. if (isset($tweet->errors)) {
  87. throw new \Exception('推文发布失败: ' . json_encode($tweet->errors));
  88. }
  89. return [
  90. 'status' => true,
  91. 'data' => [
  92. 'tweetId' => $tweet->id_str,
  93. 'mediaIds' => $mediaIds
  94. ]
  95. ];
  96. } catch (\Exception $e) {
  97. return ['status' => false, 'data' => $e->getMessage()];
  98. }
  99. }
  100. public function postVideo($message, $videoPath, $accessToken = null)
  101. {
  102. try {
  103. if (!file_exists($videoPath)) {
  104. throw new \Exception("视频文件不存在: {$videoPath}");
  105. }
  106. $uploadedVideo = $this->twitterOAuth->upload('media/upload', [
  107. 'media' => $videoPath,
  108. 'media_type' => 'video/mp4'
  109. ], true); // 注意: chunked upload
  110. if (isset($uploadedVideo->error)) {
  111. throw new \Exception('视频上传失败: ' . json_encode($uploadedVideo));
  112. }
  113. $tweet = $this->twitterOAuth->post('statuses/update', [
  114. 'status' => $message,
  115. 'media_ids' => $uploadedVideo->media_id_string
  116. ]);
  117. if (isset($tweet->errors)) {
  118. throw new \Exception('推文发布失败: ' . json_encode($tweet->errors));
  119. }
  120. return [
  121. 'status' => true,
  122. 'data' => [
  123. 'tweetId' => $tweet->id_str,
  124. 'mediaId' => $uploadedVideo->media_id_string
  125. ]
  126. ];
  127. } catch (\Exception $e) {
  128. return ['status' => false, 'data' => $e->getMessage()];
  129. }
  130. }
  131. // 保持空实现
  132. public function getComments($postId) {}
  133. public function replyToComment($commentId) {}
  134. public function deleteComment($commentId) {}
  135. }