httpClient = new Client([ 'timeout' => 30, 'headers' => [ 'User-Agent' => 'MediaCollector/1.0' ] ]); $this->basePath = rtrim($basePath, '/'); } /** * Download an image from URL and save it locally */ public function downloadImage(string $url, string $filename, string $subfolder = ''): ?string { if (empty($url) || !filter_var($url, FILTER_VALIDATE_URL)) { return null; } try { $folderPath = $this->basePath; if (!empty($subfolder)) { $folderPath .= '/' . trim($subfolder, '/'); } // Create folder if it doesn't exist if (!is_dir($folderPath)) { mkdir($folderPath, 0755, true); } $filePath = $folderPath . '/' . $filename; // Check if file already exists if (file_exists($filePath)) { return $filePath; } $response = $this->httpClient->get($url, ['sink' => $filePath]); if ($response->getStatusCode() === 200) { return $filePath; } return null; } catch (Exception $e) { // Log error but don't throw - images are not critical error_log("Failed to download image {$url}: " . $e->getMessage()); return null; } } /** * Generate a unique filename for an image */ public function generateFilename(string $url, string $prefix = ''): string { $extension = pathinfo(parse_url($url, PHP_URL_PATH), PATHINFO_EXTENSION); if (empty($extension)) { $extension = 'jpg'; // Default fallback } $hash = substr(md5($url . time()), 0, 8); return ($prefix ? $prefix . '_' : '') . $hash . '.' . $extension; } /** * Get the public URL for a local image */ public function getPublicUrl(string $localPath): ?string { if (empty($localPath) || !file_exists($localPath)) { return null; } // Remove the public/ prefix to get the web-accessible path $relativePath = str_replace($this->basePath . '/', '', $localPath); return '/' . $relativePath; } }