Php ZipArchive add's extra folder - php

zipping some directory on the server I receive extra folder inside zip-archive under Windows and Linux.
Extra folder "3b84" is the ending of using md5(integer) function to set filename inside getExportPaths() method. If I try to make filename shorter - it makes me a zip archive where all files placed in one directory without their subdirectories like "CSS", "fonts" etc.
And one important thing why I'm using md5() - I need to paste into one directory a lot of zip archives. So their name should be unique.
How to fix this and remove such extra folder with a name like "3b84"?
public function actionExportdocument($id)
{
$model = Order::findOne(['id' => $id, 'user_id' => Yii::$app->user->getId()]);
if (!$model) {
throw new BadRequestHttpException('Export not found.');
}
$paths = Order::getExportPaths($model->id, $model->design->path);
$prepareFiles = Order::prepareFiles($paths, $model);
$zip = new ZipArchive();
$zip->open($paths['exportRoot'] . DIRECTORY_SEPARATOR . $paths['exportFile'],
ZipArchive::CREATE | ZipArchive::OVERWRITE);
$files = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($paths['exportPath']),
RecursiveIteratorIterator::LEAVES_ONLY
);
foreach ($files as $name => $file)
{
// Skip directories (they would be added automatically)
if (!$file->isDir())
{
$filePath = $file->getRealPath();
$relativePath = substr($filePath, strlen($paths['designPath']) + 1);
$zip->addFile($filePath, $relativePath);
}
}
$zip->close();
FileHelper::sendFile($paths['exportRoot'] . DIRECTORY_SEPARATOR . $paths['exportFile'], 'script.zip');
}
Order class contains:
public static function getExportPaths($modelId, $designPath)
{
$paths['orderIdHash'] = md5($modelId);
$paths['designPath'] = \Yii::getAlias('#app') . DIRECTORY_SEPARATOR . 'designs' . DIRECTORY_SEPARATOR . $designPath;
$paths['exportRoot'] = \Yii::getAlias('#webroot') . DIRECTORY_SEPARATOR . 'export-document';
$paths['exportPath'] = $paths['exportRoot'] . DIRECTORY_SEPARATOR . $paths['orderIdHash'];
$paths['exportFile'] = $paths['orderIdHash'] . '.zip';
return $paths;
}
public static function prepareFiles($paths, $model)
{
$exportDir = \Yii::getAlias('#webroot') . DIRECTORY_SEPARATOR . 'export-document';
if (!is_dir($exportDir)) {
mkdir($exportDir);
}
FileHelper::deleteDirectory($paths['exportPath']);
FileHelper::copyRecursive($paths['designPath'], $paths['exportPath']);
$content = '';
foreach ($model->orderTemplates as $template) {
$content .= $template->value;
}
$str = file_get_contents($paths['exportPath'] . DIRECTORY_SEPARATOR . 'index.html');
$str = str_replace("{{CONTENT}}", $content, $str);
file_put_contents($paths['exportPath'] . DIRECTORY_SEPARATOR . 'index.html', $str);
}

If I've read your question correctly; you wish to remove folders like /3b84/ from being generated.
Look inside your Order class:
public static function getExportPaths($modelId, $designPath)
{
$paths['orderIdHash'] = md5($modelId);
$paths['designPath'] = \Yii::getAlias('#app') . DIRECTORY_SEPARATOR . 'designs' . DIRECTORY_SEPARATOR . $designPath;
$paths['exportRoot'] = \Yii::getAlias('#webroot') . DIRECTORY_SEPARATOR . 'export-document';
$paths['exportPath'] = $paths['exportRoot'] . DIRECTORY_SEPARATOR . $paths['orderIdHash'];
$paths['exportFile'] = $paths['orderIdHash'] . '.zip';
return $paths;
}
See $paths['exportPath'] = $paths['exportRoot'] . DIRECTORY_SEPARATOR . $paths['orderIdHash']; ?
Remove that and you your new path will no longer have folders like /3b84/.

The problem was that I've specified wrong $relativePath.
This string was incorrect
$relativePath = substr($filePath, strlen($paths['designPath']) + 1);
And instead of it
$relativePath = substr($filePath, strlen($paths['exportPath']) + 1);

Related

Locate file in from the file system root knowing sub-folder

I made this code below to find the path of file in my locat system, I would like to change this code to locate my-file and return its absolute path knowing that the only thing we remember about this file is that it is saved in a sub-folder /tmp/documents:
/tmp/documents can contain nested sub-folders and my-file can belong to any one of them.
If my-file cannot be found then your program should return NULL
Example:
locateFile() returns /tmp/documents/a/b/c/my-file if my-file is found into the folder /tmp/documents/a/b/c.
<?php
function locatefile(){
$flags = 0;
$pattern = 'my-file';
$files = glob($pattern, $flags);
foreach (glob(dirname($pattern) . '/*', GLOB_ONLYDIR | GLOB_NOSORT) as $dir)
{
$files = array_merge($files, locatefile($dir . '/' .basename($pattern), $flags));
}
return $files;
}
// code test do not change it
$folder = '/tmp/documents/' . rand() . '/' . rand();
mkdir($folder, 0700, true);
touch($folder . '/my-file');
echo "EXAMPLE:$folder/my-file\n";
echo "RESULT:" . locatefile();

Laravel Chumper Zipper close() not creating zip file

I am trying to create a zip file with folders inside it.
Now the code is :
{
$zipper = new \Chumper\Zipper\Zipper;
$zipper->make(storage_path('app/' . $zipPath));
.
.
Storage::makeDirectory($zipPath . DIRECTORY_SEPARATOR . $user->username , 0777);
$zipper->folder($zipPath . DIRECTORY_SEPARATOR . $user->username);
$currentZipPath = $zipPath . DIRECTORY_SEPARATOR . $user->username;
Storage::makeDirectory($currentZipPath . DIRECTORY_SEPARATOR . $myfolder->name , 0777);
$zipper->folder($currentZipPath . DIRECTORY_SEPARATOR . $myfolder->name);
.
.
$this->addDataToZip($contents, $currentZipPath . DIRECTORY_SEPARATOR . $myfolder->name, $zipper, $user);
Log::info('Zip status : ' . $zipper->getStatus()); //Gives "No error"
$zipper->close();
}
public function addDataToZip($contents, $path, &$zipper, $user)
{
foreach ($contents as $content) {
$filebasepath = storage_path('app/' . $path);
Storage::copy(
$this->model->getActiveStorageBasePath($user)
. DIRECTORY_SEPARATOR . $content->unique_name,
$path . DIRECTORY_SEPARATOR . $content->unique_name
);
$zipper->add(storage_path() . DIRECTORY_SEPARATOR . 'app'
. DIRECTORY_SEPARATOR . $path
. DIRECTORY_SEPARATOR . $content->unique_name);
}
}
Now when I view the folder locally, the entie admin.zip folder is created with complete heirarchy and content.
But on $zipper->close, the zip file is not created and the admin.zip folder remains there.
Also there is no error in the API call or the logs.
Please guide on where I might be making an error
See with example Chumper/Zipper. This is the simple and straightforward way to use.
OR you can place this line "status ::". $zipper->status . "\n" after $zipper->add() to check status.

php function to search paths for filename WITHOUT extension

Right so i'm making a configuration class that will use an array of different file types in 4 main locations. Now I want to make it so that the configuration class will search these locations in order at the moment i'm using the following
if (file_exists(ROOT . DS . 'Application/Config/' . APP_ENV . DS . $file)) {
$this->filePath = ROOT . DS . 'Application/Config/' . APP_ENV . DS . $file;
echo $this->filePath;
} else {
if (file_exists(ROOT . DS . "Application/Config/$file")) {
$this->filePath = ROOT . DS . "Application/Config/$file";
echo $this->filePath;
} else {
if (file_exists(CARBON_PATH . 'Config' . DS . APP_ENV . DS . $file)) {
$this->filePath = CARBON_PATH . 'Config' . DS . APP_ENV . DS . $file;
echo $this->filePath;
} else {
if (file_exists(CARBON_PATH . "Config/$file")) {
$this->filePath = CARBON_PATH . "Config/$file";
echo $this->filePath;
} else {
throw new \Exception("Unable to locate: $file, Please check it exists");
}
}
}
}
pretty messy and not very flexible.
What I want to be able to do is search the locations in the same order BY FILE NAME ONLY after finding the first match It would then return the file with the extension for the configuration class to use the correct method to parse into a php array and so on.
What is the best way to search these locations for a file name
Example
Say we want a database configuration file as you can see there are 2
ConfigLocation1/Dev/
/file.php
/database.json
ConfigLocation1/
/database.ini
/anotherfile.json
I would want to use the function like so
config::findFile('database');
and it return
$result = ConfigLocation1/Dev/database.json
but if it wasnt found here then then
$result = ConfigLocation1/database.ini
Not very good at explaining things so hope the example helps
As you mentioned you need to check for file in 4 locations, so instead of if conditions, create an array of directories and loop through.
and you can use glob, to find a file irrespective of extension. see my example below:-
//Make a array of directory where you want to look for files.
$dirs = array(
ROOT . DS . 'Application/Config/' . APP_ENV . DS,
CARBON_PATH . 'Config' . DS . APP_ENV . DS
);
function findFiles($directory, $filename){
$match = array();
foreach ($directory => $dir) {
$files = glob($dir.$filename);
foreach ($files as $file) {
$match[] = $file;
}
}
return $match;
}
// to find database
$results = findFiles($dirs, 'database.*');

Create Folder and Insert if Not Present

I wonder whether someone may be able to help me please.
I'm using Aurigma's Image uploader software to allow users to upload images for locations they visit. The information is saved via the script shown below:
<?php
//This variable specifies relative path to the folder, where the gallery with uploaded files is located.
//Do not forget about the slash in the end of the folder name.
$galleryPath = 'UploadedFiles/';
require_once 'Includes/gallery_helper.php';
require_once 'ImageUploaderPHP/UploadHandler.class.php';
/**
* FileUploaded callback function
* #param $uploadedFile UploadedFile
*/
function onFileUploaded($uploadedFile) {
$packageFields = $uploadedFile->getPackage()->getPackageFields();
$username=$packageFields["username"];
$locationid=$packageFields["locationid"];
global $galleryPath;
$absGalleryPath = realpath($galleryPath) . DIRECTORY_SEPARATOR;
$absThumbnailsPath = $absGalleryPath . 'Thumbnails' . DIRECTORY_SEPARATOR;
if ($uploadedFile->getPackage()->getPackageIndex() == 0 && $uploadedFile->getIndex() == 0) {
initGallery($absGalleryPath, $absThumbnailsPath, FALSE);
}
$locationfolder = $_POST['locationid'];
$locationfolder = preg_replace('/[^a-z0-9_\-\.()\[\]{}]/i', '_', $locationfolder);
if (!is_dir($absGalleryPath . $locationfolder)) {
mkdir($absGalleryPath . $locationfolder, 0777);
}
$dirName = $_POST['folder'];
$dirName = preg_replace('/[^a-z0-9_\-\.()\[\]{}]/i', '_', $dirName);
if (!is_dir($absGalleryPath . $dirName)) {
mkdir($absGalleryPath . $dirName, 0777);
}
$path = rtrim($dirName, '/\\') . '/';
$originalFileName = $uploadedFile->getSourceName();
$files = $uploadedFile->getConvertedFiles();
// save converter 1
$sourceFileName = getSafeFileName($absGalleryPath, $originalFileName);
$sourceFile = $files[0];
/* #var $sourceFile ConvertedFile */
if ($sourceFile) {
$sourceFile->moveTo($absGalleryPath . $sourceFileName);
}
// save converter 2
$thumbnailFileName = getSafeFileName($absThumbnailsPath, $originalFileName);
$thumbnailFile = $files[1];
/* #var $thumbnailFile ConvertedFile */
if ($thumbnailFile) {
$thumbnailFile->moveTo($absThumbnailsPath . $thumbnailFileName);
}
//Load XML file which will keep information about files (image dimensions, description, etc).
//XML is used solely for brevity. In real-life application most likely you will use database instead.
$descriptions = new DOMDocument('1.0', 'utf-8');
$descriptions->load($absGalleryPath . 'files.xml');
//Save file info.
$xmlFile = $descriptions->createElement('file');
$xmlFile->setAttribute('name', $_POST['folder'] . '/' . $originalFileName);
$xmlFile->setAttribute('source', $sourceFileName);
$xmlFile->setAttribute('size', $uploadedFile->getSourceSize());
$xmlFile->setAttribute('originalname', $originalFileName);
$xmlFile->setAttribute('thumbnail', $thumbnailFileName);
$xmlFile->setAttribute('description', $uploadedFile->getDescription());
//Add additional fields
$xmlFile->setAttribute('username', $username);
$xmlFile->setAttribute('locationid', $locationid);
$xmlFile->setAttribute('folder', $dirName);
$descriptions->documentElement->appendChild($xmlFile);
$descriptions->save($absGalleryPath . 'files.xml');
}
$uh = new UploadHandler();
$uh->setFileUploadedCallback('onFileUploaded');
$uh->processRequest();
?>
In additon to the original script I've added code that creates a folder, with it's name based on the current 'locationid'. This is shown below.
$locationfolder = $_POST['locationid'];
$locationfolder = preg_replace('/[^a-z0-9_\-\.()\[\]{}]/i', '_', $locationfolder);
if (!is_dir($absGalleryPath . $locationfolder)) {
mkdir($absGalleryPath . $locationfolder, 0777);
}
What I like to incorporate, is a check that looks to see whether there is a folder already setup with the current 'locationid' value, if not create the folder. I'm ceratianly no expert in PHP, but I know that to check to see whether a file exists, the if(file exists....) can be used, but I just wondered whether someone could tell me please how I can implement this check for the folder name?
Many thanks
Chris
I think is_dir() is what you are looking for.
UPDATE:
The code you have:
if (!is_dir($absGalleryPath . $locationfolder)) {
mkdir($absGalleryPath . $locationfolder, 0777);
}
Does exactly what you want. It checks for the folder and if it does not exist then it creates one for you (with CHMOD 777). Don't see what your question is then...

Moving files into directory in foreach loop?

i've no idea how to do that and need your help!
i have an array of filenames called $bundle. (file_one.jpg, file_two.pdf, file_three.etc)
and i have the name of the folder stored in $folder. (my_directory)
i now would like to move all the files stored in $bundle to move to the directory $folder.
how can i do that?
//print count($bundle); //(file_one.jpg, file_two.pdf, file_three.jpg)
$folder = $folder = PATH . '/' . my_directory;
foreach ($bundle as $value) {
//rename(PATH.'/'.$value, $folder . '/' . $value);
}
just so it's not confusing: PATH just stores the local file-path im using for my project. in my case it's just the folder i'm working in-so it's "files".
i have no idea which method i have to use for this and how i could solve that!
thank you for your help!
The code given by you should work with minor changes:
$folder = PATH . '/' . 'my_directory'; // enclose my_directory in quotes.
foreach ($bundle as $value) {
$old = PATH.'/'.$value, $folder;
$new = $folder . '/' . $value;
if(rename($old,$new) !== false) {
// renamed $old to $new
}else{
// rename failed.
}
}
$folder = PATH . '/' . $folder;
foreach ($bundle as $value) {
$old = PATH.'/'.$value;
$new = $folder . '/' . $value;
if(rename($old,$new) !== false) {
// renamed $old to $new
}else{
// rename failed.
}
}
Untested but should work:
function bulkMove($src, $dest) {
foreach(new GlobIterator($src) as $fileObject) {
if($fileObject->isFile()) {
rename(
$fileObject->getPathname(),
rtrim($dest, '\\/') . DIRECTORY_SEPARATOR . $fileObject->getBasename()
);
}
}
}
bulkMove('/path/to/folder/*', '/path/to/new/folder');
Could add some checks to see if the destination folder is writable. If you dont need wildcard matching, change the GlobIterator to DirectoryIterator. That would also eliminate the need for PHP5.3

Categories