configData = $configData; $this->consumerKey = 'ahCsl1rD6ml2Ofma5UKUaMveJ'; $this->consumerSecret = 'CsS5AHR1vIVuuhWHrbV8RR9DrF6JvZjjMOIt7oA9YubpxllDWD'; $this->oauthCallbackUrl = env('DIST_SITE_URL') . '/dist/callback/twitter'; if (isset($configData['accountInfo'])) { //初始化1.1版本的配置信息 $access_token = $configData['accountInfo']['access_token']; $backup_field1 = json_decode($configData['accountInfo']['backup_field1'],true); $access_token_secret = $backup_field1['accessTokenSecret']; if (!empty($access_token) && !empty($access_token_secret)) { $this->twitterOAuth = new TwitterOAuth( $this->consumerKey, $this->consumerSecret, $access_token, $access_token_secret ); } } } public function login() { $connection = new TwitterOAuth($this->consumerKey, $this->consumerSecret); $requestToken = $connection->oauth('oauth/request_token', ['oauth_callback' => $this->oauthCallbackUrl]); session(['twitter_oauth_token' => $requestToken['oauth_token']]); session(['twitter_oauth_token_secret' => $requestToken['oauth_token_secret']]); $url = $connection->url('oauth/authorize', ['oauth_token' => $requestToken['oauth_token']]); return [ 'status' => true, 'data' => ['url' => $url] ]; } public function loginCallback(Request $request) { $oauthToken = $request->get('oauth_token'); $oauthVerifier = $request->get('oauth_verifier'); $requestToken = session('twitter_oauth_token'); $requestTokenSecret = session('twitter_oauth_token_secret'); $connection = new TwitterOAuth( $this->consumerKey, $this->consumerSecret, $requestToken, $requestTokenSecret ); $accessToken = $connection->oauth('oauth/access_token', [ 'oauth_verifier' => $oauthVerifier ]); $expiresAt = Carbon::now()->addDays(90)->format('Y-m-d H:i:s'); return [ 'status' => true, 'data' => [ 'accessToken' => $accessToken['oauth_token'], 'backupField1' => json_encode(['accessTokenSecret'=>$accessToken['oauth_token_secret']]), 'userId' => $accessToken['user_id'], 'userName' => $accessToken['screen_name'], 'accessToken_expiresAt' => $expiresAt, ] ]; } public function postImage($message, $imagePaths, $accessToken = null) { try { $this->twitterOAuth->setApiVersion('1.1'); // 强制使用 v1.1 API $this->twitterOAuth->setTimeouts(10, 30); $mediaIds = []; foreach ($imagePaths as $imagePath) { $imagePath = toStoragePath($imagePath); if (!file_exists($imagePath)) { throw new \Exception("图片不存在: {$imagePath}"); } //1.1版本上传媒体文件 $uploadedMedia = $this->twitterOAuth->upload('media/upload', [ 'media' => $imagePath ]); if (isset($uploadedMedia->error)) { throw new \Exception('媒体上传失败: ' . json_encode($uploadedMedia)); } $mediaIds[] = $uploadedMedia->media_id_string; } // 2.0版本发布推文 $this->twitterOAuth->setApiVersion('2'); $tweet = $this->twitterOAuth->post('tweets', [ 'text' => $message, 'media' => !empty($mediaIds) ? ['media_ids' => $mediaIds] : null ]); if (isset($tweet->errors)) { throw new \Exception('推文发布失败: ' . json_encode($tweet->errors)); } return ['status' => true, 'data' => [ 'responseIds' => [$tweet->data->id], ]]; } catch (\Exception $e) { return ['status' => false, 'data' => $e->getMessage()]; } } public function postVideo($message, $videoPath, $accessToken = null) { try { $this->twitterOAuth->setTimeouts(10, 120); $this->twitterOAuth->setApiVersion('1.1'); $videoPath = toStoragePath($videoPath); // Verify file exists and is readable if (!file_exists($videoPath) || !is_readable($videoPath)) { throw new Exception("Video file does not exist or is not readable: $videoPath"); } // Upload video with chunked upload $uploadedMedia = $this->twitterOAuth->upload('media/upload', [ 'media' => $videoPath, 'media_category' => 'tweet_video' ],['chunkedUpload'=>true]); $code = $this->twitterOAuth->getLastHttpCode(); if (isset($uploadedMedia->error) || $code != 200) { throw new \Exception('媒体上传失败: ' . json_encode($uploadedMedia)); } $mediaId = $uploadedMedia->media_id_string; // 检查媒体处理状态 $processingInfo = $uploadedMedia->processing_info ?? null; if ($processingInfo && $processingInfo->state === 'pending') { $checkAfter = $processingInfo->check_after_secs; sleep($checkAfter); do { $status = $this->twitterOAuth->get("media/upload", [ 'command' => 'STATUS', 'media_id' => $mediaId ]); dd($status); if (isset($status->error)) { throw new \Exception("媒体状态检查失败: " . json_encode($status)); } $processingInfo = $status->processing_info ?? null; if (!$processingInfo || $processingInfo->state === 'failed') { throw new \Exception("媒体处理失败: " . json_encode($status)); } if ($processingInfo->state !== 'succeeded') { sleep($processingInfo->check_after_secs ?? 5); } } while ($processingInfo->state !== 'succeeded'); } // 2.0版本发布推文 $this->twitterOAuth->setApiVersion('2'); $tweet = $this->twitterOAuth->post('tweets', [ 'text' => $message, 'media' => ['media_ids' => [$mediaId]] ]); dd($tweet); } catch (\Exception $e) { return ['status' => false, 'data' => $e->getMessage()]; } } // 保持空实现 public function getComments($postId) {} public function replyToComment($commentId) {} public function deleteComment($commentId) {} }