nhance/app/Libraries/ZipService.php
2026-07-15 15:49:13 +05:30

179 lines
5.8 KiB
PHP

<?php
namespace App\Libraries;
use ZipArchive;
class ZipService
{
protected $s3Service;
public function __construct()
{
$this->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);
}
}