I am using this function in codeigniter to try to check and make directories and sub directories only if they do not exist. Only the k_uploads is made but an error occurs in making the sub directory in the main directory 'k_upoloads'. The structure should be as
k_uploads (main directory)
-2012 (subdirectory in main directory - made per year in k_uploads)
-Jan(subdirectory in 2012 - made every month in 2012)
-subdirx (subdirectory in Jan - holds the excel files for that month)
xxyyy.xlsx (month files in subdirx)
Each year and month directories and sub directories should be created. I cant figure where the problem is, it works with plain php but not in codeigniter.
public function makeDir(){
$labref = $this->uri->segment(3);
$dirName='k_uploads';
echo $store_dir= date('Y').'/'.date('M').'/'.$subdirx;
if(!is_dir($dirName))
$k= mkdir($dirName, 0777);
if($k){
echo $dirName. 'dir has been created';
}else{
echo 'An error occured';
}
if(is_dir($dirName))
$w= mkdir($store_dir,0777);
if($w){
echo $sore_dir. 'subdirs have been created';
}else{
echo 'An error occured';
}
}
mkdir has a recursive flag which can be set. This will create the full path. See PHP: mkdir
so you should use mkdir($store_dir,0777, true)
The function could look something like the following:
public function makeDir(){
$subdirx = $this->uri->segment(3);
$store_dir= APPPATH . 'k_uploads/' . date('Y').'/'.date('M').'/'.$subdirx;
if(!is_dir($store_dir)) {
return mkdir($dirName, 0777, true);
} else {
return true;
}
}
In order to do this, you will need to create each sub-directory in a sequence, as PHP will not do this for you. You might want to check if the directory already exists using is_dir() while doing so.
Here's an example:
function createDir($dirToMake) {
$root = "/home/sites/test/www/";
$dArray = explode("/",$dirToMake);
if (file_exists($root) && is_dir($root)) {
// just a quick check
if (substr($root,0,-1) !== "/") $root .= "/";
foreach ($dArray as $v) {
if (strlen($v) == 0) continue;
$root = $root.$v."/";
if (file_exists($root) && is_dir($root)) continue;
mkdir($root);
}
}
else throw new Exception("Root directory does not exist");
}
This function also allows for the usual mistakes (// being one of them), and will loop through, creating the sub-directory architecture needed if it doesn't exist already.
Related
I am looking to select files over a certain age from a local directory tree. The following code works but is very inefficient, and because the directory is so large, it causes timeouts.
$dir = new RecursiveDirectoryIterator('store/', FilesystemIterator::SKIP_DOTS | FilesystemIterator::UNIX_PATHS);
$files = new RecursiveCallbackFilterIterator($dir, function ($current, $key, $iterator) {
// Allow recursion
if ($iterator->hasChildren()) {
return TRUE;
}
// Check for target folder name
if ($current->isFile() && strpos($current->getPath(), '/target-folder/')) {
return TRUE;
}
return FALSE;
});
$expiry = new DateTime();
$expiry = date_modify($expiry,"-28 days");
foreach (new RecursiveIteratorIterator($files) as $file) {
$cTime = new DateTime();
$cTime->setTimestamp($file->getCTime());
if ($cTime < $expiry) {
echo $file->getPath() . "/" . $file->getFileName() . " file Created " . $cTime->format('Y-m-d j:i:s') . "<br/>\n";
}
}
At the moment the code is scanning every file and folder and just returning the matches, but I know that the target-folder is always 3 levels deep (store/[sub-folder]/[sub-folder]/target-folder/[recursive search from here]) so I am searching the top 2 levels for nothing. However there is not always a target folder and I also need to search recursively within the target folder as the files I need will be in it's children. Is there any way to ignore the top 2 levels within the 'store' tree?
I am using the following PHP code:
if (!file_exists('../products'))
{
mkdir('../products', 0777, true);
$target = "Main Not Present, ";
}
else
{
if(file_exists('../products'))
{
$timezone = new DateTimeZone("Asia/Kolkata");
$datetime = new DateTime();
$datetime->setTimezone($timezone);
$year = $datetime->format('Y');
$month = $datetime->format('M');
$day = $datetime->format('D');
$timestamp = $datetime->format('Y-m-d H:i:s');
if(!file_exists('../products/'.$year))
{
mkdir('../products/'.$year, 0777, true);
$target = $target."With year not present also, ";
}
else
{
if(file_exists('../products/'.$year))
{
if(!file_exists('../products/'.$year."/".$month))
{
$target = $target."With not not present also";
}
}
}
}
}
I am creating an ecommerce website using CMS technique like Wordpress, however i am trying to check whether certain directories exist or not, if they don't then to create them and proceed. The problem with my code is that when this code is encountered true
if (!file_exists('../products'))
{
mkdir('../products', 0777, true);
$target = "Main Not Present, ";
}
it creates the directory and the data is stored in the variable, the problem is that it isn't processing further and going in the else statement whether the other folders in that products folder exists or not.
What I am trying to achieve is that
1.) check the products folder, if it doesn't exists then create if it exists then proceed further, lets take worse case that it isn't present then in this case if i want to create that folder and make my code work further but with this code it only satisfy the 1st if condition and don't go in the else statement to satisfy the code further.
Can anyone help me with this? Thanks in advance.
The above-Provided code was too buggy and big, I achieved it using the recursive method.
//recursive function created here
function check_create($path)
{
if (is_dir($path)) return true;
$prev_path = substr($path, 0, strrpos($path, '/', -2) + 1 );
$return = check_create($prev_path);
return ($return && is_writable($prev_path)) ? mkdir($path) : false;
}
//call the recursive function to check and create if not exists
check_create("path/to/directory");
I have a zip file containing one folder, that contains more folders and files, like this:
myfile.zip
-firstlevel
--folder1
--folder2
--folder3
--file1
--file2
Now, I want to extract this file using PHPs ZipArchive, but without the "firstlevel" folder. At the moment, the results look like this:
destination/firstlevel/folder1
destination/firstlevel/folder2
...
The result I'd like to have would look like this:
destination/folder1
destination/folder2
...
I've tried extractTo, which produces the first mentioned result, and copy(), as suggested here, but this doesn't seem to work at all.
My current code is here:
if($zip->open('myfile.zip') === true) {
$firstlevel = $zip->getNameIndex(0);
for($i = 0; $i < $zip->numFiles; $i++) {
$entry = $zip->getNameIndex($i);
$pos = strpos($entry, $firstlevel);
if ($pos !== false) {
$file = substr($entry, strlen($firstlevel));
if(strlen($file) > 0){
$files[] = $file;
}
}
}
//attempt 1 (extractTo):
//$zip->extractTo('./test', $files);
//attempt 2 (copy):
foreach($files as $filename){
copy('zip://'.$firstlevel.'/'.$filename, 'test/'.$filename);
}
}
How can I achieve the result I'm aiming for?
Take a look at my Quick Unzipper script. I wrote this for personal use a while back when uploading large zip files to a server. It was a backup, and 1,000s of files take forever with FTP so using a zip file was faster. I use Git and everything, but there wasn't another option for me. I place this php file in the directory I want the files to go, and put the zip file in the same directory. For my script, they all have to operate in the same directory. It was an easy way to secure it for my needs, as everything I needed was in the same dir.
Quick Unzipper: https://github.com/incomepitbull/QuickUnzipper/blob/master/unzip.php
I linked the file because I am not showcasing the repo, just the code that makes the unzip tick. With modern versions of PHP, there should't be anything that isn't included on your setup. So you shouldn't need to do any server config changes to use this.
Here is the PHP Doc for the ZipArchive class it uses: http://php.net/manual/en/class.ziparchive.php
There isn't any included way to do what you want, which is a shame. So I would unzip the file to a temp directory, then use another function to copy the contents to where you want. So when using ZipArchive, you will need to return the first item to get the folder name if it is unknown. If the folder is known, ie: the same pesky folder name every time, then you could hard code the name.
I have made it return the first item from the index. So if you ALWAYS have a zip with 1 folder inside it, and everything in that folder, this would work. However, if you have a zip file without everything consolidated inside 1 folder, it would fail. The code I have added will take care of your question. You will need to add further logic to handle alternate cases.
Also, You will still be left with the old directory from when we extract it to the temp directory for "processing". So I included code to delete it too.
NOTE: The code uses a lot of if's to show the processing steps, and print a message for testing purposes. You would need to modify it to your needs.
<?php
public function copyDirectoryContents($source, $destination, $create=false)
{
if ( ! is_dir($source) ) {
return false;
}
if ( ! is_dir($destination) && $create === true ) {
#mkdir($destination);
}
if ( is_dir($destination) ) {
$files = array_diff(scandir($source), array('.','..'));
foreach ($files as $file)
{
if ( is_dir($file) ) {
copyDirectoryContents("$source/$file", "$destination/$file");
} else {
#copy("$source/$file", "$destination/$file");
}
}
return true;
}
return false;
}
public function removeDirectory($directory, $options=array())
{
if(!isset($options['traverseSymlinks']))
$options['traverseSymlinks']=false;
$files = array_diff(scandir($directory), array('.','..'));
foreach ($files as $file)
{
if (is_dir("$directory/$file"))
{
if(!$options['traverseSymlinks'] && is_link(rtrim($file,DIRECTORY_SEPARATOR))) {
unlink("$directory/$file");
} else {
removeDirectory("$directory/$file",$options);
}
} else {
unlink("$directory/$file");
}
}
return rmdir($directory);
}
$file = dirname(__FILE__) . '/file.zip'; // full path to zip file needing extracted
$temp = dirname(__FILE__) . '/zip-temp'; // full path to temp dir to process extractions
$path = dirname(__FILE__) . '/extracted'; // full path to final destination to put the files (not the folder)
$firstDir = null; // holds the name of the first directory
$zip = new ZipArchive;
$res = $zip->open($file);
if ($res === TRUE) {
$firstDir = $zip->getNameIndex(0);
$zip->extractTo($temp);
$zip->close();
$status = "<strong>Success:</strong> '$file' extracted to '$temp'.";
} else {
$status = "<strong>Error:</strong> Could not extract '$file'.";
}
echo $status . '<br />';
if ( empty($firstDir) ) {
echo 'Error: first directory was empty!';
} else {
$firstDir = realpath($temp . '/' . $firstDir);
echo "First Directory: $firstDir <br />";
if ( is_dir($firstDir) ) {
if ( copyDirectoryContents($firstDir, $path) ) {
echo 'Directory contents copied!<br />';
if ( removeDirectory($directory) ) {
echo 'Temp directory deleted!<br />';
echo 'Done!<br />';
} else {
echo 'Error deleting temp directory!<br />';
}
} else {
echo 'Error copying directory contents!<br />';
}
} else {
echo 'Error: Could not find first directory';
}
}
can someone please tell me what I'm doing wrong in this code?
if($id != '') {
if(is_dir("../public_html".$tem_pasta['path']."/pics/".$id)) {
echo "pasta já existia";
$destination_file = "../public_html".$tem_pasta['path']."/pics/".$id."/".$myFileName;
} else {
//pasta nao existia
if (ftp_mkdir($conn_id, "../public_html".$tem_pasta['path']."/pics/".$id)) {
$destination_file = "../public_html".$tem_pasta['path']."/pics/".$id."/".$myFileName;
//echo "pasta criada<br>";
} else {
echo "erro, não criou a pasta<br>";
}
}
} else {
$destination_file = "../public_html".$tem_pasta['path']."/pics/".$myFileName;
}
it checks if I've a folder ($id) within my pics directory, and if not the script creates a new one.
works good, but if I try to upload another file to the previous created folder it does return an error, saying it didn't create the folder...
thanks
I don't think you can use is_dir on a FTP resource, what you should do is check if the size of the dir/file is -1 with ftp_size.
Because I think what now happens is: you are trying to make the same folder again, and this is why a error occurs.
Edit:
Or check with ftp_chdir!
<?php
function ftp_directory_exists($ftp, $dir)
{
// Get the current working directory
$origin = ftp_pwd($ftp);
// Attempt to change directory, suppress errors
if (#ftp_chdir($ftp, $dir))
{
// If the directory exists, set back to origin
ftp_chdir($ftp, $origin);
return true;
}
// Directory does not exist
return false;
}
?>
Should work!
is_dir works only on the local file-system. If you want to check if a ftp-directory already exists try this:
function ftp_is_dir($ftp, $dir)
{
$pushd = ftp_pwd($ftp);
if ($pushd !== false && #ftp_chdir($ftp, $dir))
{
ftp_chdir($ftp, $pushd);
return true;
}
return false;
}
if($id != '') {
if(ftp_is_dir($conn_id, "../public_html".$tem_pasta['path']."/pics/".$id)) {
// and so on...
Use ftp_nlist and in_array
$ftp_files = #ftp_nlist($this->connection, $directory);
if ($ftp_files === false) {
throw new Exception('Unable to list files. Check directory exists: ' . $directory);
}
if (!in_array($directory, $ftp_files)) {
$ftp_mkdir = #ftp_mkdir($this->connection, $directory);
if ($ftp_mkdir === false) {
throw new Exception('Unable to create directory: ' . $directory);
}
}
With PHP 8.0 (on AWS) the solution with #ftp_chdir() does not hide the error and causes the program to stop. The solution with ftp_nlist() doesn't give good results because it returns either false if the path doesn't exist or an element if the path is a file or a list if it's a directory but doesn't give the "." and ".." elements that would identify a directory.
The ftp_mlsd() function seemed more convenient: it returns a list, possibly empty, only if the path is a directory, false otherwise. But it doesn't work correctly on all servers!
Finally it is the ftp_rawlist() function which seems to be the most generalized because it launches a LIST command on the server and returns the result. If the path is a directory we have an array, possibly empty and we have the value false if it is not a directory.
$list = ftp_rawlist( $ftp_conn, $remote_path );
$is_dir = is_array( $list );
I tried to write a script to list all files in directories and subdirectories and so on.. The script works fine if I don't include the check to see whether any of the files are directories. The code doesn't generate errors but it generates a hundred lines of text saying "Directory Listing of ." instead of what I was expecting. Any idea why this isn't working?
<?php
//define the path as relative
$path = "./";
function listagain($pth)
{
//using the opendir function
$dir_handle = #opendir($pth) or die("Unable to open $pth");
echo "Directory Listing of $pth<br/>";
//running the while loop
while ($file = readdir($dir_handle))
{
//check whether file is directory
if(is_dir($file))
{
//if it is, generate it's list of files
listagain($file);
}
else
{
if($file!="." && $file!="..")
echo "<a href='$file'>$file</a><br/>";
}
}
//closing the directory
closedir($dir_handle);
}
listagain($path)
?>
The first enties . and .. refer to the current and parent directory respectivly. So you get a infinite recursion.
You should first check for that before checking the file type:
if ($file!="." && $file!="..") {
if (is_dir($file)) {
listagain($file);
} else {
echo ''.htmlspecialchars($file).'<br/>';
}
}
The problem is, variable $file contains only basename of path. So, you need to use $pth.$file.