diff --git a/app/Services/Social/BlueskyPublisher.php b/app/Services/Social/BlueskyPublisher.php index ef8e7f3f..46c3f341 100644 --- a/app/Services/Social/BlueskyPublisher.php +++ b/app/Services/Social/BlueskyPublisher.php @@ -105,7 +105,11 @@ private function uploadBlob(SocialAccount $account, string $service, string $url $tempFile = tempnam(sys_get_temp_dir(), 'bsky_blob_'); try { - Http::withOptions(['sink' => $tempFile])->timeout(600)->get($url); + $downloadResponse = Http::withOptions(['sink' => $tempFile])->timeout(600)->get($url); + + if ($downloadResponse->failed()) { + throw new \Exception('Failed to download media: HTTP '.$downloadResponse->status()); + } $fileSize = filesize($tempFile); diff --git a/app/Services/Social/FacebookPublisher.php b/app/Services/Social/FacebookPublisher.php index f651e868..be649e8c 100644 --- a/app/Services/Social/FacebookPublisher.php +++ b/app/Services/Social/FacebookPublisher.php @@ -221,15 +221,25 @@ private function publishReel(string $pageId, string $accessToken, ?string $conte // Upload the video file $tempFile = tempnam(sys_get_temp_dir(), 'fb_reel_'); try { - Http::withOptions(['sink' => $tempFile])->timeout(600)->get($media->url); + $downloadResponse = Http::withOptions(['sink' => $tempFile])->timeout(600)->get($media->url); + + if ($downloadResponse->failed()) { + throw new \Exception('Failed to download media: HTTP '.$downloadResponse->status()); + } + + $stream = fopen($tempFile, 'r'); $uploadResponse = Http::withToken($accessToken) - ->attach('video_file_chunk', fopen($tempFile, 'r'), 'video.mp4') + ->attach('video_file_chunk', $stream, 'video.mp4') ->post("{$this->baseUrl}/{$videoId}", [ 'upload_phase' => 'transfer', 'access_token' => $accessToken, ]); + if (is_resource($stream)) { + fclose($stream); + } + if ($uploadResponse->failed()) { Log::error('Facebook reel upload transfer failed', ['body' => $uploadResponse->body()]); $this->handleApiError($uploadResponse); @@ -283,15 +293,25 @@ private function publishStory(string $pageId, string $accessToken, $media): arra // Transfer the video $tempFile = tempnam(sys_get_temp_dir(), 'fb_story_'); try { - Http::withOptions(['sink' => $tempFile])->timeout(600)->get($media->url); + $downloadResponse = Http::withOptions(['sink' => $tempFile])->timeout(600)->get($media->url); + + if ($downloadResponse->failed()) { + throw new \Exception('Failed to download media: HTTP '.$downloadResponse->status()); + } + + $stream = fopen($tempFile, 'r'); $transferResponse = Http::withToken($accessToken) - ->attach('video_file_chunk', fopen($tempFile, 'r'), 'video.mp4') + ->attach('video_file_chunk', $stream, 'video.mp4') ->post("{$this->baseUrl}/{$videoId}", [ 'upload_phase' => 'transfer', 'access_token' => $accessToken, ]); + if (is_resource($stream)) { + fclose($stream); + } + if ($transferResponse->failed()) { Log::error('Facebook video story transfer failed', ['body' => $transferResponse->body()]); $this->handleApiError($transferResponse); diff --git a/app/Services/Social/LinkedInPagePublisher.php b/app/Services/Social/LinkedInPagePublisher.php index 08b73ae2..1c09c417 100644 --- a/app/Services/Social/LinkedInPagePublisher.php +++ b/app/Services/Social/LinkedInPagePublisher.php @@ -264,7 +264,11 @@ private function uploadImage($mediaItem, string $ownerUrn): ?string $tempFile = tempnam(sys_get_temp_dir(), 'lip_image_'); try { - Http::withOptions(['sink' => $tempFile])->timeout(600)->get($mediaItem->url); + $downloadResponse = Http::withOptions(['sink' => $tempFile])->timeout(600)->get($mediaItem->url); + + if ($downloadResponse->failed()) { + throw new \Exception('Failed to download media: HTTP '.$downloadResponse->status()); + } $detectedMime = mime_content_type($tempFile) ?: ''; if (str_starts_with($detectedMime, 'image/') && ! str_starts_with($detectedMime, 'image/gif')) { @@ -311,7 +315,11 @@ private function uploadVideo($mediaItem, string $ownerUrn): ?string private function doUploadVideo(string $tempFile, $mediaItem, string $ownerUrn): ?string { - Http::withOptions(['sink' => $tempFile])->timeout(600)->get($mediaItem->url); + $downloadResponse = Http::withOptions(['sink' => $tempFile])->timeout(600)->get($mediaItem->url); + + if ($downloadResponse->failed()) { + throw new \Exception('Failed to download media: HTTP '.$downloadResponse->status()); + } $fileSize = (int) filesize($tempFile); diff --git a/app/Services/Social/LinkedInPublisher.php b/app/Services/Social/LinkedInPublisher.php index 1a9a3791..0fad60d6 100644 --- a/app/Services/Social/LinkedInPublisher.php +++ b/app/Services/Social/LinkedInPublisher.php @@ -245,7 +245,11 @@ private function uploadImage($mediaItem, string $ownerUrn): ?string $tempFile = tempnam(sys_get_temp_dir(), 'li_image_'); try { - Http::withOptions(['sink' => $tempFile])->timeout(600)->get($mediaItem->url); + $downloadResponse = Http::withOptions(['sink' => $tempFile])->timeout(600)->get($mediaItem->url); + + if ($downloadResponse->failed()) { + throw new \Exception('Failed to download media: HTTP '.$downloadResponse->status()); + } $detectedMime = mime_content_type($tempFile) ?: ''; if (str_starts_with($detectedMime, 'image/') && ! str_starts_with($detectedMime, 'image/gif')) { @@ -292,7 +296,11 @@ private function uploadVideo($mediaItem, string $ownerUrn): ?string private function doUploadVideo(string $tempFile, $mediaItem, string $ownerUrn): ?string { - Http::withOptions(['sink' => $tempFile])->timeout(600)->get($mediaItem->url); + $downloadResponse = Http::withOptions(['sink' => $tempFile])->timeout(600)->get($mediaItem->url); + + if ($downloadResponse->failed()) { + throw new \Exception('Failed to download media: HTTP '.$downloadResponse->status()); + } $fileSize = (int) filesize($tempFile); diff --git a/app/Services/Social/MastodonPublisher.php b/app/Services/Social/MastodonPublisher.php index bc78fd3f..5857c730 100644 --- a/app/Services/Social/MastodonPublisher.php +++ b/app/Services/Social/MastodonPublisher.php @@ -65,7 +65,11 @@ private function uploadMedia(SocialAccount $account, string $instance, string $u $tempFile = tempnam(sys_get_temp_dir(), 'masto_media_'); try { - Http::withOptions(['sink' => $tempFile])->timeout(600)->get($url); + $downloadResponse = Http::withOptions(['sink' => $tempFile])->timeout(600)->get($url); + + if ($downloadResponse->failed()) { + throw new \Exception('Failed to download media: HTTP '.$downloadResponse->status()); + } if (filesize($tempFile) === 0) { Log::error('Mastodon failed to download media', ['url' => $url]); diff --git a/app/Services/Social/PinterestPublisher.php b/app/Services/Social/PinterestPublisher.php index c7cd9d29..8229ad8c 100644 --- a/app/Services/Social/PinterestPublisher.php +++ b/app/Services/Social/PinterestPublisher.php @@ -54,7 +54,11 @@ private function publishImagePin(PostPlatform $postPlatform): array $tempFile = tempnam(sys_get_temp_dir(), 'pin_image_'); try { - Http::withOptions(['sink' => $tempFile])->timeout(600)->get($media->url); + $downloadResponse = Http::withOptions(['sink' => $tempFile])->timeout(600)->get($media->url); + + if ($downloadResponse->failed()) { + throw new \Exception('Failed to download media: HTTP '.$downloadResponse->status()); + } $detectedMime = mime_content_type($tempFile) ?: ''; if (str_starts_with($detectedMime, 'image/') && ! str_starts_with($detectedMime, 'image/gif')) { @@ -164,7 +168,11 @@ private function publishVideoPin(PostPlatform $postPlatform): array $videoStream = null; try { - Http::withOptions(['sink' => $tempFile])->timeout(600)->get($media->url); + $downloadResponse = Http::withOptions(['sink' => $tempFile])->timeout(600)->get($media->url); + + if ($downloadResponse->failed()) { + throw new \Exception('Failed to download media: HTTP '.$downloadResponse->status()); + } $videoStream = fopen($tempFile, 'r'); diff --git a/app/Services/Social/XPublisher.php b/app/Services/Social/XPublisher.php index 947f9e18..8616a233 100644 --- a/app/Services/Social/XPublisher.php +++ b/app/Services/Social/XPublisher.php @@ -102,7 +102,11 @@ private function uploadMedia($mediaItem): ?array $tempFile = tempnam(sys_get_temp_dir(), 'x_media_'); try { - Http::withOptions(['sink' => $tempFile])->timeout(600)->get($mediaItem->url); + $downloadResponse = Http::withOptions(['sink' => $tempFile])->timeout(600)->get($mediaItem->url); + + if ($downloadResponse->failed()) { + throw new \Exception('Failed to download media: HTTP '.$downloadResponse->status()); + } // Optimize images (skip GIFs — they need special handling) if (str_starts_with($mimeType, 'image/') && ! str_starts_with($mimeType, 'image/gif')) { @@ -130,7 +134,7 @@ private function uploadMedia($mediaItem): ?array ->timeout(360) ->attach( 'media', - file_get_contents($tempFile), + fopen($tempFile, 'r'), basename($tempFile), ['Content-Type' => $mimeType] );