What i would like to do, is to zip my fileadmin and my extension folder with a zipAction on my controller. So i took a piece of code from here
and i have this:
$fileAdminPath = 'fileadmin';
$archiveName = $importerSettings['fileadminArchiveName'];
$zip = new \ZipArchive;
$zip->open($archiveName, \ZipArchive::CREATE | \ZipArchive::OVERWRITE);
$files = new \RecursiveIteratorIterator (new \RecursiveDirectoryIterator($fileAdminPath), \RecursiveIteratorIterator::LEAVES_ONLY);
if (!$file->isDir()) {
// Get real and relative path for current file
$filePath = $file->getRealPath();
$relativePath = substr($filePath, strlen($fileAdminPath) + 1);
// Add current file to archive
$zip->addFile($filePath, $relativePath);
}
// Zip archive will be created only after closing object
$zip->close();
Now, when the code reaches the isDir() part, i get the following error:
Call to a member function isDir() on null
If i remove it and let the code run again, the getRealPath() gets the same error. So i am guessing i missing a namespace or something like that, that stores these functions.
On a local php file (index.php) and MAMPP it works. On TYPO3, not.
By the way, i am not sure if the controller really reads the fileadmin path. If i got it wrong, please feel free to correct me.
Best regards
If you run your script inside an extension, this script is searching fileadmin within your extension directory.
Try to use the following script:
$fileAdminPath = \TYPO3\CMS\Core\Utility\GeneralUtility::getFileAbsFileName('fileadmin');
Edit:
You should also walk the files in an foreach because you scan an directory recursiv:
foreach ($files as $file) {
if (!$file->isDir()) {
// Get real and relative path for current file
$filePath = $file->getRealPath();
$relativePath = substr($filePath, strlen($fileAdminPath) + 1);
// Add current file to archive
$zip->addFile($filePath, $relativePath);
}
}
Related
So our code creates a zip file and inside it are PDF's from a specific folder. Everything works fine, except that when this zip file is downloaded to a computer and the files are extracted - the modification time for each PDF file follows the server's time zone. (Our site is on a GoDaddy shared server, and they're located in Arizona. We are located in Singapore.)
Is there a way to modify this? I have tried to set the default time zone or use touch() but no luck.
// Initialize archive object
$zip = new ZipArchive();
$res = $zip->open(plugin_dir_path( __FILE__ ).'MortgageWise-All-Reports.zip', ZipArchive::CREATE | ZipArchive::OVERWRITE);
if ($res === TRUE) {
// Create recursive directory iterator
/** #var SplFileInfo[] $files */
$files = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($rootPath)
);
foreach ($files as $name => $file) {
// Skip directories (they would be added automatically)
if (!$file->isDir()) {
// Get real and relative path for current file
$filePath = $file->getRealPath();
$relativePath = substr($filePath, strlen($rootPath));
date_default_timezone_set("Asia/Singapore");
//touch($filePath, );
// Add current file to archive
$zip->addFile($filePath, $relativePath);
}
}
// Zip archive will be created only after closing object
$zip->close();
}
else {
echo "File not created.";
}
I would start by trying to set the timezone at the start of the script, before you create the ZIP, rather than in the foreach loop.
But with that being said I don't believe it will make much difference as the PDF files already exist? And therefore will already have those properties assigned to them!
Do you have access to Web Host Manager or similar? If you have a VPS or Dedicated server, you can change the time zone of the server yourself.
EDIT: sorry, you already stated you are on a shared server, would highly recommend a VPS to give you full control over these settings, should only be $50 a month
Got a bit of a weird problem.
I have a folder with PowerPoint data that I need to zip and then rename to pptx.
If I manually create a .zip and copy the files into it, then rename, it works like expected, but when I use ZipArchive to archive the data and then rename the created file, it doesn't work.
The programmatically created archive is also a few kB smaller than the manually created one.
Archive comparison tools tell me that I've got the exact same files in both zips, including hidden files.
But here is where it gets really weird: if I make another, empty archive, then copy-paste the files from the programmatically created archive with a simple select, drag and drop, that new archive will work when renamed to a .pptx and has the same size as the first manually created file.
$dir = 'pptx/test/compiled';
$zip_file = 'pptx/test/file.zip';
// Get real path for our folder
$rootPath = realpath($dir);
// Initialize archive object
$zip = new \ZipArchive();
$zip->open($zip_file, \ZipArchive::CREATE | \ZipArchive::OVERWRITE);
// Create recursive directory iterator
/** #var SplFileInfo[] $files */
$files = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($rootPath),
\RecursiveIteratorIterator::LEAVES_ONLY
);
foreach ($files as $name => $file)
{
// Skip directories (they would be added automatically)
if (!$file->isDir())
{
// Get real and relative path for current file
$filePath = $file->getRealPath();
$relativePath = substr($filePath, strlen($rootPath) + 1);
// Add current file to archive
$zip->addFile($filePath, $relativePath);
}
}
// Zip archive will be created only after closing object
$zip->close();
update
This only seems to be a problem on Windows, when tested on a Mac, it works without issues.
I ran into this problem again, and after asking help on a LibreOffice forum (the problem was specific for Impress), I've discovered that in windows the filepaths used when archiving had backslashes, that caused the issues.
I've added two lines in my archiving function to clean up the paths:
// Get real and relative path for current file
$filePath = $file->getRealPath();
$relativePath = substr($filePath, strlen($rootPath) + 1);
// Replace backward with forward slashes, for compatibility issues
$filePath = str_replace('\\', '/', $filePath);
$relativePath = str_replace('\\', '/', $relativePath);
// Add current file to archive
$zip->addFile($filePath, $relativePath);
Now my code runs without problems. (I use the LibreOffice headless as an exec() to convert to pdf, which wouldn't work previously)
When I make ZIP archive using PHP ZipArchive object, all files inside the archive have permissions set to 666, although original files have permissions set to 644.
My script makes the zip archives properly, just the permissions are messed up.
////// Make Template archive object
$templateArchive = new ZipArchive();
$templateArchive->open(PATH_TO_TEMPLATES.'_files/'.$templateName.'/_pack/'.$templateName.'.zip', ZipArchive::CREATE | ZipArchive::OVERWRITE);
$files = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($templateDir."/templates/".$template_archive_name),
RecursiveIteratorIterator::LEAVES_ONLY
);
foreach ($files as $name => $file)
{
// Skip directories (they would be added automatically)
if (!$file->isDir())
{
// Get real and relative path for current file
$filePath = $file->getRealPath();
// relative path is full path, reduced with length of templateDir string and 11 more chars for /templates/
$relativePath = substr($filePath, strlen($templateDir) + 11);
// Add current file to archive
$templateArchive->addFile($filePath, $relativePath);
}
}
// Template Zip archive will be created only after closing object
$templateArchive->close();
P.S. I am working of MAMP on Mac. I just found out that issue is only when PHP 5.6.10 version is selected. When I select 5.5.26, the permissions of files are correct.
You can preserve the Unix permissions in the files you archive by adding the following code after your ZipArchive::addFile() statement:
$templateArchive->setExternalAttributesName($relativePath,
ZipArchive::OPSYS_UNIX,
fileperms($filePath) << 16);
This updates the external attributes of the entry at $filePath with the actual file's permissions.
Unix permissions can be stored in ZIP files in each entry's external attribute, but you have to shift 16 bits to store the permissions in the right place in the external attribute, which is why << 16 is applied to the output of fileperms($filePath).
The documentation of ZipArchive::setExternalAttributesName() also has an example that features Unix permission setting: https://secure.php.net/manual/en/ziparchive.setexternalattributesname.php
As for the permissions of the directories, you'll need to add the directories with ZipArchive::addEmptyDir() (because ZipArchive::addFile() on a directory will result in an error) and then apply the permissions with ZipArchive::setExternalAttributesName() the same way you did for the regular files.
Due to the way that RecursiveDirectoryIterator works, the current directory name will end with /., and due to the way that ZipArchive::addEmptyDir() works, stored directories will end with /. To apply ZipArchive::setExternalAttributesName(), you have to provide the exact entry name, so I suggest lopping off the trailing dot for both methods.
Here is your code edited to support the preservation of permissions of files and directories:
////// Make Template archive object
$templateArchive = new ZipArchive();
$templateArchive->open(PATH_TO_TEMPLATES.'_files/'.$templateName.'/_pack/'.$templateName.'.zip', ZipArchive::CREATE | ZipArchive::OVERWRITE);
$files = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($templateDir."/templates/".$template_archive_name),
RecursiveIteratorIterator::LEAVES_ONLY
);
foreach ($files as $name => $file)
{
// Get real and relative path for current file
$filePath = $file->getRealPath();
// relative path is full path, reduced with length of templateDir string and 11 more chars for /templates/
$relativePath = substr($filePath, strlen($templateDir) + 11);
// Add regular files
if (!$file->isDir())
{
// Add current file to archive
$templateArchive->addFile($filePath, $relativePath);
}
elseif (substr($relativePath, -2) === "/.")
{
// Remove the dot representing the current directory
$relativePath = substr($relativePath, 0, -1);
// Add current directory to archive
$templateArchive->addEmptyDir($relativePath);
}
else
{
continue;
}
$templateArchive->setExternalAttributesName($relativePath,
ZipArchive::OPSYS_UNIX,
fileperms($filePath) << 16);
}
// Template Zip archive will be created only after closing object
$templateArchive->close();
My project consist in a big mongodb/gridfs files database, where each file belongs to a "folder" document, and these folders are ordered following a tree structure with one root node.
Now I need to zip a part of the tree (or maybe the whole structure), keeping the tree and files accordingly (the whole tree will be approximately 10To big).
What's the best strategy to do so ? All files are dynamically provided by gridFS (the cache musnt be used in the zip process).
What's the best way to do so ? Thanks for your help !
See answer by Dador https://stackoverflow.com/questions/4914750/how-to-zip-a-whole-folder-using-php
// Get real path for our folder
$rootPath = realpath('folder-to-zip');
// Initialize archive object
$zip = new ZipArchive();
$zip->open('file.zip', ZipArchive::CREATE | ZipArchive::OVERWRITE);
// Create recursive directory iterator
/** #var SplFileInfo[] $files */
$files = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($rootPath),
RecursiveIteratorIterator::LEAVES_ONLY
);
foreach ($files as $name => $file)
{
// Skip directories (they would be added automatically)
if (!$file->isDir())
{
// Get real and relative path for current file
$filePath = $file->getRealPath();
$relativePath = substr($filePath, strlen($rootPath) + 1);
// Add current file to archive
$zip->addFile($filePath, $relativePath);
}
}
// Zip archive will be created only after closing object
$zip->close();
So, I understand it's pretty easy to zip a folder and its contents given that php.net and stackoverflow are full of sample codes. I am trying to zip up a folder as well. This is my code:
$zip = new ZipArchive;
$zip->open('myzip.zip', ZipArchive::CREATE);
foreach (glob("/Volumes/Data/Users/username/Desktop/Archive/some/thisFolder/*") as $file) {
$zip->addFile($file);
}
$zip->close();
My script is running in a folder, say on Desktop, and I want to zip thisFolder and its contents. The above code WORKS. But, the problem is that when I unzip the myzip.zip created, I get a structure like
Volumes>Data>Users>username>Desktop>Archive>some>thisFolder
and then I find the contents inside the 8th folder (thisFolder) in this case. How can I change this code so that when I unzip myzip.zip,I would straightaway see the folder thisFolder with the contents inside it instead of having to navigate through folders 7 times before getting my content?
I tried to change the path and silly things like that. But, it doesn't work.
Thanks
If you want everything in the file to be a name relative to your starting folder, use chdir() to start from there:
chdir("/Volumes/Data/Users/username/Desktop/Archive/some/thisFolder");
foreach (glob("*") as $file) {
$zip->addFile($file);
}
Actually, I don't think this will work when $file is a subdirectory -- addFile doesn't recurse automatically. There's a comment in the documentation that shows how to write a recursive zip function:
http://www.php.net/manual/en/ziparchive.addemptydir.php
bool ZipArchive::addFile ( string $filename [, string $localname ] )
filename
The path to the file to add.
localname
local name inside ZIP archive.
You can use the pathinfo function to each $file in your loop, in order to retrieve the filename without the path, and then, use it as second parameter to the addFile method.
pathinfo doc here
Here is an example that could solve your problem:
// Create your zip archive
$zip = new ZipArchive;
// open it in creation mode
$zip->open('myzip.zip', ZipArchive::CREATE);
// Loop on all your file
$mask = "/Volumes/Data/Users/username/Desktop/Archive/some/thisFolder";
$allAvailableFiles = glob($mask . "/*")
foreach ($allAvailableFiles as $file)
{
// Retrieve pathinfo
$info = pathinfo($file);
// Generate the internal directory
$internalDir = str_replace($mask, "", $info['dirname']);
// Add the file with internal directory
$zip->addFile($file, $internalDir . "/" . $info['basename']);
}
$zip->close();