s3Service = new S3Service(); } /** * Zips a local folder and uploads it to S3 */ public function zipAndUploadS3(string $localFolderPath, string $s3Folder = '', string $zipName = ''): array { // dd($localFolderPath, $s3Folder, $zipName); if (!is_dir($localFolderPath)) { return ['status' => false, 'message' => 'Local directory does not exist']; } // 1. Prepare naming $folderName = basename($localFolderPath); $zipName = $zipName ?: $folderName . '_' . time() . '.zip'; $tempZipPath = FCPATH . 'tmp/' . $zipName; // 2. Create the Local Zip $zipResult = $this->createLocalZip($localFolderPath, $tempZipPath); if (!$zipResult['status']) { return $zipResult; } try { // 3. Upload to S3 $uploadResult = $this->s3Service->upload($tempZipPath, $s3Folder, $zipName); // dd($uploadResult); // 4. Cleanup if (file_exists($tempZipPath)) { unlink($tempZipPath); } $get_presinged_url = $this->s3Service->getPresignedUrl($uploadResult['key'], 2880); // To delete the original temprory folder after zipping and uploading // $this->deleteDirectory($localFolderPath); return ['status' => true, 'data' => $uploadResult, 'presigned_url' => $get_presinged_url]; } catch (\Exception $e) { log_message('error', 'Zip/Upload Error: ' . $e->getMessage()); return ['status' => false, 'message' => $e->getMessage()]; } } /** * Zips a local folder using native ZipArchive */ public function createLocalZip(string $localFolderPath, string $destinationPath): array { // 1. Validate Source Directory if (!is_dir($localFolderPath)) { return ['status' => false, 'message' => 'Source directory does not exist']; } // 2. Check if folder is empty (ignoring hidden files) $filesInFolder = array_diff(scandir($localFolderPath), array('.', '..')); if (empty($filesInFolder)) { return ['status' => false, 'message' => 'No records found to compress']; } // 3. Ensure the destination directory exists and is writable $destDir = dirname($destinationPath); if (!is_dir($destDir)) { mkdir($destDir, 0777, true); } $zip = new ZipArchive(); // 4. Open the zip file $openZip = $zip->open($destinationPath, ZipArchive::CREATE | ZipArchive::OVERWRITE); if ($openZip !== true) { return ['status' => false, 'message' => "Could not open Zip. Error code: " . $openZip]; } try { $files = new \RecursiveIteratorIterator( new \RecursiveDirectoryIterator($localFolderPath, \RecursiveDirectoryIterator::SKIP_DOTS), \RecursiveIteratorIterator::LEAVES_ONLY ); $fileCount = 0; $sourcePath = realpath($localFolderPath); foreach ($files as $file) { if (!$file->isDir()) { $filePath = $file->getRealPath(); // Calculate relative path correctly $relativePath = ltrim(substr($filePath, strlen($sourcePath)), DIRECTORY_SEPARATOR); // Add to zip if ($zip->addFile($filePath, $relativePath)) { $fileCount++; } } } // 5. Finalize if ($fileCount > 0) { if (!$zip->close()) { return ['status' => false, 'message' => 'Failed to write ZIP file to disk (Check permissions/space)']; } } else { $zip->close(); return ['status' => false, 'message' => 'No files were added to the archive']; } return [ 'status' => true, 'path' => $destinationPath, 'count' => $fileCount, 'message' => 'Zip created successfully' ]; } catch (\Exception $e) { // Only attempt to close if the zip object was successfully opened if (isset($zip->status) && $zip->status !== ZipArchive::ER_OK) { @$zip->close(); } log_message('error', 'Local Zip Error: ' . $e->getMessage()); return ['status' => false, 'message' => 'from catch Exception: ' . $e->getMessage()]; } } private function deleteDirectory($dir) { if (!file_exists($dir)) { return true; } if (!is_dir($dir)) { // Use @ to suppress warnings if the file is already gone or locked // return @unlink($dir); return unlink($dir); } // scandir can return false if the directory isn't readable $items = scandir($dir); if ($items === false) { return false; } foreach ($items as $item) { if ($item == '.' || $item == '..') { continue; } // Recursively call the function if (!$this->deleteDirectory($dir . DIRECTORY_SEPARATOR . $item)) { // If a child cannot be deleted, attempt to change its permissions and try once more @chmod($dir . DIRECTORY_SEPARATOR . $item, 0777); if (!$this->deleteDirectory($dir . DIRECTORY_SEPARATOR . $item)) { return false; } } } // Finally, remove the empty directory return @rmdir($dir); } }