post_id = $post_id; $this->title = $title; $this->message = $message; $this->images = $images; $this->videos = $videos; $this->publish_date = $publish_date; $this->public_id = config('services.vk.public_id'); $this->primary_attachments_mode = $primary_attachments_mode; } public function handle() { Log::channel('vk')->info('Processing VK post', ['post_id' => $this->post_id, 'images' => count($this->images)]); $vk = new VKApiClient(); $wallService = new VkWallService($vk); $from_group = 1; // Документы больше не загружаются — они добавляются как ссылки в тексте поста // Считаем только видео и изображения $video_attachments = !empty($this->videos) ? $this->prepareVideos($this->videos) : ''; $video_list = $video_attachments ? explode(',', $video_attachments) : []; // Все 10 слотов доступны для видео и изображений $available_slots = 10 - count($video_list); $attached_videos = array_slice($video_list, 0, count($video_list)); $remaining_slots = $available_slots; Log::channel('vk')->debug('Attachment slots calculated', [ 'post_id' => $this->post_id, 'videos' => count($attached_videos), 'remaining_photo_slots' => $remaining_slots, ]); $image_list = []; if ($remaining_slots > 0 && !empty($this->images)) { $images_to_attach = array_slice($this->images, 0, $remaining_slots); Log::channel('vk')->debug('Preparing wall photos', ['files' => $images_to_attach]); $image_attachments = $this->prepareWallPhotos($images_to_attach); Log::channel('vk')->debug('Photo preparation result', ['attachments' => $image_attachments]); $image_list = $image_attachments ? explode(',', $image_attachments) : []; } else { Log::channel('vk')->debug('No photos to attach — no slots or no images', ['post_id' => $this->post_id]); } $selected_attachments = array_merge($attached_videos, $image_list); if (count($this->images) > count($image_list)) { Log::channel('vk')->debug('Not all photos fit in post — creating album', ['post_id' => $this->post_id]); $album = $this->createAlbum($this->title, $this->images); if (isset($album['id'])) { $albumLink = "https://vk.ru/album-{$this->public_id}_{$album['id']}"; $this->message .= "\n\n[{$albumLink}|Ссылка на все фотографии]"; } else { Log::channel('vk')->error('Failed to create VK album', ['post_id' => $this->post_id]); } } $attachmentString = implode(',', $selected_attachments); Log::channel('vk')->debug('Final attachment string', ['post_id' => $this->post_id, 'attachments' => $attachmentString]); $vk_post = $wallService->createPost($this->message, $from_group, $attachmentString, $this->publish_date, $this->primary_attachments_mode); if (isset($vk_post['post_id'])) { Log::channel('vk')->info('VK post created successfully', ['post_id' => $this->post_id, 'vk_post_id' => $vk_post['post_id']]); DB::table('posts_vk_posts')->insert( [ 'post_id' => $this->post_id, 'vk_post_id' => $vk_post['post_id'], 'unchange_time_after' => Carbon::now()->addWeek(), ] ); } else { Log::channel('vk')->error('Failed to create VK post', ['post_id' => $this->post_id, 'response' => $vk_post]); } } private function prepareWallPhotos(array $images): string { try { $imagePaths = []; foreach ($images as $img) { $relativePath = ltrim($img, '/'); $fullPath = public_path($relativePath); if (!file_exists($fullPath)) { $fullPath = storage_path('app/public/' . $relativePath); } if (file_exists($fullPath)) { $imagePaths[] = $fullPath; } else { Log::channel('vk')->warning('Image file not found on disk', ['image' => $img, 'expected_path' => $fullPath]); } } if (empty($imagePaths)) { Log::channel('vk')->debug('No valid local image paths found', ['post_id' => $this->post_id]); return ''; } Log::channel('vk')->debug('Local image paths for upload', ['paths' => $imagePaths]); $photos = $this->uploadWallPhotos($imagePaths, $this->public_id); $result = implode(',', array_map(function($photo) { return "photo{$photo['owner_id']}_{$photo['id']}"; }, $photos)); return $result; } catch (\Exception $e) { Log::channel('vk')->error('Failed to prepare wall photos', ['error' => $e->getMessage()]); return ''; } } private function uploadWallPhotos(array $imagePaths, ?int $groupId = null): array { $uploadedPhotos = []; foreach ($imagePaths as $imagePath) { try { Log::channel('vk')->debug('Uploading photo', ['path' => $imagePath]); // 1. Проверка доступности файла $fileContent = @file_get_contents($imagePath); if ($fileContent === false) { throw new \Exception("Не удалось прочитать файл по ссылке: {$imagePath}. Проверьте доступность URL."); } Log::channel('vk')->debug('File read successfully', ['path' => $imagePath, 'size_bytes' => strlen($fileContent)]); // 2. Получение сервера $uploadServerResponse = Http::get('https://api.vk.ru/method/photos.getWallUploadServer', [ 'group_id' => $groupId, 'access_token' => (new VkAuthService())->getToken()->access_token, 'v' => '5.131', ]); $uploadServerData = $uploadServerResponse->json(); if (isset($uploadServerData['error'])) { Log::channel('vk')->error('VK API getWallUploadServer error', ['error' => $uploadServerData['error']]); continue; } if (!isset($uploadServerData['response']['upload_url'])) { Log::channel('vk')->error('getWallUploadServer response missing upload_url', ['response' => $uploadServerData]); throw new \Exception('Не удалось получить сервер для загрузки: ' . $imagePath); } $uploadUrl = $uploadServerData['response']['upload_url']; Log::channel('vk')->debug('Upload URL obtained', ['url' => $uploadUrl]); // 3. Отправка файла $uploadResponse = Http::attach( 'photo', $fileContent, basename($imagePath) )->post($uploadUrl); $uploadData = $uploadResponse->json(); // Логируем сырой ответ от сервера загрузки, часто ошибка тут Log::channel('vk')->debug('Upload POST response', ['response' => $uploadData ?? []]); if (!isset($uploadData['photo']) || !isset($uploadData['server']) || !isset($uploadData['hash'])) { // Иногда VK возвращает пустой photo: "[]" или error внутри JSON throw new \Exception('Некорректный ответ от сервера загрузки: ' . json_encode($uploadData)); } // 4. Сохранение фото $saveResponse = Http::get('https://api.vk.ru/method/photos.saveWallPhoto', [ 'group_id' => $groupId, 'photo' => $uploadData['photo'], // Это должна быть JSON строка, а не массив, если пришло строкой 'server' => $uploadData['server'], 'hash' => $uploadData['hash'], 'access_token' => (new VkAuthService())->getToken()->access_token, 'v' => '5.131', ]); $saveData = $saveResponse->json(); if (isset($saveData['error'])) { Log::channel('vk')->error('VK API saveWallPhoto error', ['error' => $saveData['error']]); continue; } if (!isset($saveData['response'][0])) { Log::channel('vk')->error('saveWallPhoto missing response[0]', ['response' => $saveData]); throw new \Exception('Не удалось сохранить фотографию: ' . $imagePath); } $uploadedPhotos[] = $saveData['response'][0]; Log::channel('vk')->debug('Photo saved successfully', ['photo_id' => $saveData['response'][0]['id']]); } catch (\Exception $e) { Log::channel('vk')->error('Critical error uploading photo', ['path' => $imagePath, 'error' => $e->getMessage()]); } } return $uploadedPhotos; } // ... (остальные методы prepareVideos, uploadVideos и т.д. остаются как были, // но можно добавить аналогичное логирование и туда при желании) private function prepareVideos(array $videos): string { $baseUrl = config('app.url'); $videoPaths = array_map(function($vid) use ($baseUrl) { return $baseUrl . $vid; }, $videos); $uploadedVideos = $this->uploadVideos($videoPaths, $this->public_id); return implode(',', $uploadedVideos); } private function uploadVideos(array $videoPaths, ?int $groupId = null): array { $uploadedVideos = []; // ... (Ваш старый код uploadVideos) foreach ($videoPaths as $videoPath) { // Для краткости оставил как есть, но лучше тоже обернуть в try-catch с логами try { $saveResponse = Http::timeout(360)->get('https://api.vk.ru/method/video.save', [ 'group_id' => $groupId, 'access_token' => (new VkAuthService())->getToken()->access_token, 'v' => '5.131', ]); $saveData = $saveResponse->json(); if (!isset($saveData['response']['upload_url'])) { throw new \Exception('Не удалось получить сервер для загрузки видео: ' . $videoPath); } $uploadUrl = $saveData['response']['upload_url']; $uploadResponse = Http::timeout(360)->attach( 'video_file', file_get_contents($videoPath), basename($videoPath) )->post($uploadUrl); $uploadData = $uploadResponse->json(); if (!isset($uploadData['video_id']) || !isset($uploadData['owner_id'])) { throw new \Exception('Не удалось загрузить видео: ' . $videoPath); } $attachment = "video{$uploadData['owner_id']}_{$uploadData['video_id']}"; $uploadedVideos[] = $attachment; } catch (\Exception $e) { Log::channel('vk')->error('Failed to upload video', ['path' => $videoPath, 'error' => $e->getMessage()]); } } return $uploadedVideos; } public function createAlbum(string $title, $images) { // Ваш код $vk = new VKApiClient(); $album = (new VkAlbumService($vk))->createAlbum($title); // Добавим проверку if(!isset($album['id'])) return []; $uploadServer = (new VkAlbumService($vk))->getServerForUploadImages($album['id'], config('PUBLIC_ID')); foreach (array_chunk($images, 4) as $images_slice) { $images_data = (new VkAlbumService($vk))->uploadImagesToUploadServer($uploadServer['upload_url'], $images_slice); (new VkAlbumService($vk))->saveImagesToUploadServer( $images_data['aid'], $images_data['server'], $images_data['photos_list'], $images_data['hash'] ); } return $album; } }