179 lines
5.8 KiB
PHP
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);
|
|
}
|
|
} |