Check multiple levels of folders is dir - php

When user types in a new folder name and the name all ready exists in sub folders and main folder then will return error.
Currently it returns error even if folder not exist in sub folders etc.
Question How can I make it so that it can check main directory and sub folders and return error if exits else lets me create it.
The post for foldername is $this->input->post('folder')
Checks if any subfolders exists with same name.
if (!$json) {
$results = scandir($DIR_IMAGE);
foreach ($results as $result) {
if ($result === '.' or $result === '..') continue;
if (is_dir($DIR_IMAGE . '/' . $result)) {
$json['error'] = 'This folder name all ready';
}
}
}
Full Function
public function folder() {
$json = array();
$DIR_IMAGE = FCPATH . 'images/';
if ($this->input->get('directory')) {
$directory = $this->input->get('directory') . '/';
} else {
$directory = 'catalog/';
}
if (!$json) {
$arrPathParts = explode('/', $directory);
if (count($arrPathParts) > 3) {
$json['error'] = 'You can not create a new folder here try back one level.';
}
}
if (!$json) {
$re = '/\W/'; // \W matches any non-word character (equal to [^a-zA-Z0-9_])
$str = $this->input->post('folder');
$is_correct_foldername = !preg_match($re, $str) ? true : false;
if (!$is_correct_foldername) {
$json['error'] = 'You have some symbols or no spaces that are not allowed';
}
}
// Checks if any subfolders exists with same name.
if (!$json) {
$results = scandir($DIR_IMAGE);
foreach ($results as $result) {
if ($result === '.' or $result === '..') continue;
if (is_dir($DIR_IMAGE . '/' . $result)) {
$json['error'] = 'This folder name all ready';
}
}
}
// Every thing passes now will create folder
if (!$json) {
mkdir($DIR_IMAGE . $directory . $this->input->post('folder'), 0777, true);
$json['success'] = 'Your folder is now created!';
}
$this->output->set_content_type('Content-Type: application/json');
$this->output->set_output(json_encode($json));
}

In your code:
if (!$json) {
$results = scandir($DIR_IMAGE);
foreach ($results as $result) {
if ($result === '.' or $result === '..') continue;
if (is_dir($DIR_IMAGE . '/' . $result)) {
$json['error'] = 'This folder name all ready';
}
}
}
You are only checking whethe each directory name returned from scandir() is a directory - which would always be true.
Assuming the name of the directory you want to check for is $this->input->post('foldername'), you can do:
if (!$json) {
$results = scandir($DIR_IMAGE);
foreach ($results as $result) {
if ($result === '.' or $result === '..') continue;
if (is_dir($DIR_IMAGE . '/' . $result) && ($result == $this->input->post('foldername'))) {
$json['error'] = 'This folder name all ready';
}
}
}
As a side note, you should try to use the DIRECTORY_SEPARATOR constant instead of '/' directory.
Finally, also be careful that directory name capitalisation could be a factor on different operating systems.

I have now got a solution using RecursiveIteratorIterator and in array
public function folder() {
$json = array();
$DIR_IMAGE = FCPATH . 'images/';
if ($this->input->get('directory')) {
$directory = $this->input->get('directory') . '/';
} else {
$directory = 'catalog/';
}
if (!$json) {
$arrPathParts = explode('/', $directory);
if (count($arrPathParts) > 3) {
$json['error'] = 'You can not create a new folder here try back one level.';
}
}
if (!$json) {
$re = '/\W/'; // \W matches any non-word character (equal to [^a-zA-Z0-9_])
$str = $this->input->post('folder');
$is_correct_foldername = !preg_match($re, $str) ? true : false;
if (!$is_correct_foldername) {
$json['error'] = 'You have some symbols or no spaces that are not allowed';
}
}
// Checks if any subfolders exists with same name. #todo clean paths
if (!$json) {
$root = $DIR_IMAGE . 'catalog/';
$iter = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($root, RecursiveDirectoryIterator::SKIP_DOTS),
RecursiveIteratorIterator::SELF_FIRST,
RecursiveIteratorIterator::CATCH_GET_CHILD // Ignore "Permission denied"
);
$paths = array($root);
foreach ($iter as $path => $dir) {
if ($dir->isDir()) {
$paths[] = basename($path);
}
}
if (in_array($this->input->post('folder'), $paths)) {
$json['error'] = 'You have all ready created a folder called ' . $this->input->post('folder') . ' in one of your directories!';
}
}
if (!$json) {
mkdir($DIR_IMAGE . $directory . $this->input->post('folder'), 0777, true);
$json['success'] = 'Your folder is now created!';
}
$this->output->set_content_type('Content-Type: application/json');
$this->output->set_output(json_encode($json));
}

Related

Loop through paths / files in array and remove path

i'm working on a Joomla 3.x component, I'm trying to build an array with folders, files and filenames, I can get the Folders and Files , including paths, which I want, but have been unable to get it to return the names using "basename()" to get just the name.ext . I get an error regarding passing an array to "basename()" in lieu of a string, I've tried "foreach" but it only returns the last item in the array.
Below is the code
function getPathContents() {
$this->directory = 'some/directory';
$recursive = '1';
$this->recursive = ($recursive == 'true' || $recursive == 'recursive' || $recursive == '1');
$this->exclude_folders = '';
$this->exclude_files = '';
$options = array();
$filenames = array();
$filename = basename($filenames);
$path = $this->directory;
if (!is_dir($path))
{
if (is_dir(JPATH_ROOT . '/' . $path))
{
$path = JPATH_ROOT . '/' . $path;
}
else
{
return;
}
}
$path = JPath::clean($path);
$folders = JFolder::folders($path, $this->filter, $this->recursive, true);
// Build the options list from the list of folders.
if (is_array($folders))
{
foreach ($folders as $folder)
{
$options['folders'] = $folders;
$files = JFolder::files($folder, $this->filter, $this->recursive, true);
if (is_array($files))
{
foreach ($files as $file)
{
$options['files'] = $files;
}
$filenames = JFolder::files($folder, $this->filter, $this->recursive, true);
if (is_array($filenames))
{
foreach ($files as $filename)
{
$options['filenames'] = $filename;
}
}
}
}
return $options;
}
any help would be great
UPDATE: Below Code will provide list of Folders and additional arrays of files located in each folder. Each file array is labeled with the Folders name.
Code
function getFolersfiles() {
$this->directory = 'yourpath';
$recursive = '1';
$this->recursive = ($recursive == 'true' || $recursive == 'recursive' || $recursive == '1');
$this->exclude_folders = '';
$this->exclude_files = '';
$path = $this->directory;
if (!is_dir($path))
{
if (is_dir(JPATH_ROOT . '/' . $path))
{
$path = JPATH_ROOT . '/' . $path;
}
else
{
return;
}
}
$path = JPath::clean($path);
$options2['folders'] = JFolder::folders($path, $this->filter, $this->recursive, true);
// Build the options list from the list of folders.
if (is_array($options2))
{
foreach ($options2['folders'] as $option2)
{
$optionname = basename($option2);
$options2[$optionname] = JFolder::files($option2, $this->filter, $this->recursive, true);
//$options2['filepath'] = JFolder::files($option2, $this->filter, $this->recursive, true);
}
return $options2;
}
Thank you for the help

How can I prevent double checks in this function?

Here is a code to search and return the existing files from the given directories:
<?php
function getDirContents($directories, &$results = array()) {
$length = count($directories);
for ($i = 0; $i < $length; $i++) {
if(is_file($directories[$i])) {
if(file_exists($directories[$i])) {
$path = $directories[$i];
$directory_path = basename($_SERVER['REQUEST_URI']);
$results[] = 'https://' . $_SERVER['SERVER_NAME'] . str_replace($directory_path, "", $_SERVER['REQUEST_URI']) .$path;
}
} else {
$files = array_diff(scandir($directories[$i]), array('..', '.'));
foreach($files as $key => $value) {
$path = $directories[$i].DIRECTORY_SEPARATOR.$value;
if(is_dir($path)) {
getDirContents([$path], $results);
} else {
$directory_path = basename($_SERVER['REQUEST_URI']);
$results[] = 'https://' . $_SERVER['SERVER_NAME'] . str_replace($directory_path, "", $_SERVER['REQUEST_URI']) .$path;
}
}
}
}
return $results;
}
echo json_encode(getDirContents($_POST['directories']));
So you can pass an array of file addresses and directories and get what ever files inside those directories, Note if you pass a file address instead of a directory address the function checks if there is such a file and if there is it returns its address in the result .
The issue is for the directories it works fine but the files repeat twice in the result and for each file the function double checks this if statement in the code:
if(is_file($directories[$i]))
Here is a result of the function note that contemporary.mp3 and Japanese.mp3
has been re checked and added to the result.
How can I solve this?
If $directories contains both a directory and a file within that directory, you'll add the file to the result for the filename and also when scanning the directory.
A simple fix is to check whether the filename is already in the result before adding it.
<?php
function getDirContents($directories, &$results = array()) {
foreach ($directories as $name) {
if(is_file($name)) {
$path = $name;
$directory_path = basename($_SERVER['REQUEST_URI']);
$new_path = 'https://' . $_SERVER['SERVER_NAME'] . str_replace($directory_path, "", $_SERVER['REQUEST_URI']) .$path;
if (!in_array($new_path, $results)) {
$results[] = $new_path;
}
} elseif (is_dir($name)) {
$files = array_diff(scandir($name), array('..', '.'));
foreach($files as $key => $value) {
$path = $name.DIRECTORY_SEPARATOR.$value;
if(is_dir($path)) {
getDirContents([$path], $results);
} else {
$directory_path = basename($_SERVER['REQUEST_URI']);
$new_path = 'https://' . $_SERVER['SERVER_NAME'] . str_replace($directory_path, "", $_SERVER['REQUEST_URI']) .$path;
if (!in_array($new_path, $results)) {
$results[] = $new_path;
}
}
}
}
}
return $results;
}

building a simple directory browser using php RecursiveDirectoryIterator

Hi
i am trying to build simple directory browser to browse folders and sub-folders uing php RecursiveDirectoryIterator .. i need help of how to create this. i have started with the following code.
$dir = dirname(__FILE__); //path of the directory to read
$iterator = new RecursiveDirectoryIterator($dir);
foreach (new RecursiveIteratorIterator($iterator, RecursiveIteratorIterator::CHILD_FIRST) as $file) {
if (!$file->isFile()) { //create hyperlink if this is a folder
echo "" . $file->getFilename() . "\";
}else{ //do not link if this is a file
$file->getFilename()
}
}
Allow me to code that for you....
<?php
$root = __DIR__;
function is_in_dir($file, $directory, $recursive = true, $limit = 1000) {
$directory = realpath($directory);
$parent = realpath($file);
$i = 0;
while ($parent) {
if ($directory == $parent) return true;
if ($parent == dirname($parent) || !$recursive) break;
$parent = dirname($parent);
}
return false;
}
$path = null;
if (isset($_GET['file'])) {
$path = $_GET['file'];
if (!is_in_dir($_GET['file'], $root)) {
$path = null;
} else {
$path = '/'.$path;
}
}
if (is_file($root.$path)) {
readfile($root.$path);
return;
}
if ($path) echo '..<br />';
foreach (glob($root.$path.'/*') as $file) {
$file = realpath($file);
$link = substr($file, strlen($root) + 1);
echo ''.basename($file).'<br />';
}

How to sync two folders in PHP?

I am using windows, Mysql DB, PHP
I am building the Joomla Component whose one of the functionality is to synchronize the folders
I want to sync two folders of different name.. How can I do this? It has to be dne in the same machine, no two different servers are involved in it..
How to sync two folders in PHP?
UPDATED
IN Context of Alex Reply
What if i am editing any .jpg file in one folder and saving it with same name as it has, also this file is already present in other folder. And I want this edited pic to be transfered to the other folder.? also I have Joomla's nested file structured to be compared
UPDATE 2
I have a recursive function which will output me the complete structure of folder... if u can just use it to concat ur solution in...
<?
function getDirectory($path = '.', $ignore = '') {
$dirTree = array ();
$dirTreeTemp = array ();
$ignore[] = '.';
$ignore[] = '..';
$dh = #opendir($path);
while (false !== ($file = readdir($dh))) {
if (!in_array($file, $ignore)) {
if (!is_dir("$path/$file")) {
$stat = stat("$path/$file");
$statdir = stat("$path");
$dirTree["$path"][] = $file. " === ". date('Y-m-d H:i:s', $stat['mtime']) . " Directory == ".$path."===". date('Y-m-d H:i:s', $statdir['mtime']) ;
} else {
$dirTreeTemp = getDirectory("$path/$file", $ignore);
if (is_array($dirTreeTemp))$dirTree = array_merge($dirTree, $dirTreeTemp);
}
}
}
closedir($dh);
return $dirTree;
}
$ignore = array('.htaccess', 'error_log', 'cgi-bin', 'php.ini', '.ftpquota');
$dirTree = getDirectory('.', $ignore);
?>
<pre>
<?
print_r($dirTree);
?>
</pre>
I just ran this, and it seems to work
function sync() {
$files = array();
$folders = func_get_args();
if (empty($folders)) {
return FALSE;
}
// Get all files
foreach($folders as $key => $folder) {
// Normalise folder strings to remove trailing slash
$folders[$key] = rtrim($folder, DIRECTORY_SEPARATOR);
$files += glob($folder . DIRECTORY_SEPARATOR . '*');
}
// Drop same files
$uniqueFiles = array();
foreach($files as $file) {
$hash = md5_file($file);
if ( ! in_array($hash, $uniqueFiles)) {
$uniqueFiles[$file] = $hash;
}
}
// Copy all these unique files into every folder
foreach($folders as $folder) {
foreach($uniqueFiles as $file => $hash) {
copy($file, $folder . DIRECTORY_SEPARATOR . basename($file));
}
}
return TRUE;
}
// usage
sync('sync', 'sync2');
You simply give it a list of folders to sync, and it will sync all files. It will attempt to skip files that appear the same (i.e. of whom their hash collides).
This however does not take into account last modified dates or anything. You will have to modify itself to do that. It should be pretty simple, look into filemtime().
Also, sorry if the code sucks. I had a go at making it recursive, but I failed :(
For a one way copy, try this
$source = '/path/to/source/';
$destination = 'path/to/destination/';
$sourceFiles = glob($source . '*');
foreach($sourceFiles as $file) {
$baseFile = basename($file);
if (file_exists($destination . $baseFile)) {
$originalHash = md5_file($file);
$destinationHash = md5_file($destination . $baseFile);
if ($originalHash === $destinationHash) {
continue;
}
}
copy($file, $destination . $baseFile);
}
It sounds like you just want to copy all files from one folder to another. The second example will do this.
I using this, and it seems to work, also make new dir if not exist .....
//sync the files and folders
function smartCopy($source, $dest, $options=array('folderPermission'=>0755,'filePermission'=>0755))
{
//$result = false;
if (is_file($source)) {
if ($dest[strlen($dest)-1]=='/') {
if (!file_exists($dest)) {
cmfcDirectory::makeAll($dest,$options['folderPermission'],true);
}
$__dest=$dest."/".basename($source);
} else {
$__dest=$dest;
}
$result = copy($source, $__dest);
chmod($__dest,$options['filePermission']);
} elseif(is_dir($source)) {
if ($dest[strlen($dest)-1]=='/') {
if ($source[strlen($source)-1]=='/') {
//Copy only contents
} else {
//Change parent itself and its contents
$dest=$dest.basename($source);
#mkdir($dest);
chmod($dest,$options['filePermission']);
}
} else {
if ($source[strlen($source)-1]=='/') {
//Copy parent directory with new name and all its content
#mkdir($dest,$options['folderPermission']);
chmod($dest,$options['filePermission']);
} else {
//Copy parent directory with new name and all its content
#mkdir($dest,$options['folderPermission']);
chmod($dest,$options['filePermission']);
}
}
$dirHandle=opendir($source);
while($file=readdir($dirHandle))
{
if($file!="." && $file!="..")
{
if(!is_dir($source."/".$file)) {
$__dest=$dest."/".$file;
} else {
$__dest=$dest."/".$file;
}
echo "$source/$file ||| $__dest<br />";
$result=smartCopy($source."/".$file, $__dest, $options);
}
}
closedir($dirHandle);
} else {
$result=false;
}
return $result;
}
//end of function
echo smartCopy('media', 'mobile/images');
function recurse_copy($src,$dst) {
$dir = opendir($src);
#mkdir($dst);
while(false !== ( $file = readdir($dir)) ) {
if (( $file != '.' ) && ( $file != '..' )) {
if ( is_dir($src . '/' . $file) ) {
recurse_copy($src . '/' . $file,$dst . '/' . $file);
}
else {
if(md5_file($src . '/' . $file) !== md5_file($dst . '/' . $file))
{
echo 'copying' . $src . '/' . $file; echo '<br/>';
copy($src . '/' . $file, $dst . '/' . $file);
}
}
}
}
closedir($dir);
}
If its on a Linux/Posix system then (depending on what access you have) it may be a lot simpler / faster to:
$chk=`rsync -qrRlpt --delete $src $dest`;
C.

PHP read sub-directories and loop through files how to?

I need to create a loop through all files in subdirectories. Can you please help me struct my code like this:
$main = "MainDirectory";
loop through sub-directories {
loop through filels in each sub-directory {
do something with each file
}
};
Use RecursiveDirectoryIterator in conjunction with RecursiveIteratorIterator.
$di = new RecursiveDirectoryIterator('path/to/directory');
foreach (new RecursiveIteratorIterator($di) as $filename => $file) {
echo $filename . ' - ' . $file->getSize() . ' bytes <br/>';
}
You need to add the path to your recursive call.
function readDirs($path){
$dirHandle = opendir($path);
while($item = readdir($dirHandle)) {
$newPath = $path."/".$item;
if(is_dir($newPath) && $item != '.' && $item != '..') {
echo "Found Folder $newPath<br>";
readDirs($newPath);
}
else{
echo ' Found File or .-dir '.$item.'<br>';
}
}
}
$path = "/";
echo "$path<br>";
readDirs($path);
You probably want to use a recursive function for this, in case your sub directories have sub-sub directories
$main = "MainDirectory";
function readDirs($main){
$dirHandle = opendir($main);
while($file = readdir($dirHandle)){
if(is_dir($main . $file) && $file != '.' && $file != '..'){
readDirs($file);
}
else{
//do stuff
}
}
}
didn't test the code, but this should be close to what you want.
I like glob with it's wildcards :
foreach (glob("*/*.txt") as $filename) {
echo "$filename\n";
}
Details and more complex scenarios.
But if You have a complex folders structure RecursiveDirectoryIterator is definitively the solution.
Come on, first try it yourself!
What you'll need:
scandir()
is_dir()
and of course foreach
http://php.net/manual/en/function.is-dir.php
http://php.net/manual/en/function.scandir.php
Another solution to read with sub-directories and sub-files (set correct foldername):
<?php
$path = realpath('samplefolder/yorfolder');
foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path)) as $filename)
{
echo "$filename <br/>";
}
?>
Minor modification on what John Marty posted, if we can safely eliminate any items that are named . or ..
function readDirs($path){
$dirHandle = opendir($path);
while($item = readdir($dirHandle)) {
$newPath = $path."/".$item;
if (($item == '.') || ($item == '..')) {
continue;
}
if (is_dir($newPath)) {
pretty_echo('Found Folder '.$newPath);
readDirs($newPath);
} else {
pretty_echo('Found File: '.$item);
}
}
}
function pretty_echo($text = '')
{
echo $text;
if (PHP_OS == 'Linux') {
echo "\r\n";
}
else {
echo "</br>";
}
}
<?php
ini_set('max_execution_time', 300); // increase the execution time of the file (in case the number of files or file size is more).
class renameNewFile {
static function copyToNewFolder() { // copies the file from one location to another.
$main = 'C:\xampp\htdocs\practice\demo'; // Source folder (inside this folder subfolders and inside each subfolder files are present.)
$main1 = 'C:\xampp\htdocs\practice\demomainfolder'; // Destination Folder
$dirHandle = opendir($main); // Open the source folder
while ($file = readdir($dirHandle)) { // Read what's there inside the source folder
if (basename($file) != '.' && basename($file) != '..') { // Ignore if the folder name is '.' or '..'
$folderhandle = opendir($main . '\\' . $file); // Open the Sub Folders inside the Main Folder
while ($text = readdir($folderhandle)) {
if (basename($text) != '.' && basename($text) != '..') { // Ignore if the folder name is '.' or '..'
$filepath = $main . '\\' . $file . '\\' . $text;
if (!copy($filepath, $main1 . '\\' . $text)) // Copy the files present inside the subfolders to destination folder
echo "Copy failed";
else {
$fh = fopen($main1 . '\\' . 'log.txt', 'a'); // Write a log file to show the details of files copied.
$text1 = str_replace(' ', '_', $text);
$data = $file . ',' . strtolower($text1) . "\r\n";
fwrite($fh, $data);
echo $text . " is copied <br>";
}
}
}
}
}
}
static function renameNewFileInFolder() { //Renames the files into desired name
$main1 = 'C:\xampp\htdocs\practice\demomainfolder';
$dirHandle = opendir($main1);
while ($file = readdir($dirHandle)) {
if (basename($file) != '.' && basename($file) != '..') {
$filepath = $main1 . '\\' . $file;
$text1 = strtolower($filepath);
rename($filepath, $text1);
$text2 = str_replace(' ', '_', $text1);
if (rename($filepath, $text2))
echo $filepath . " is renamed to " . $text2 . '<br/>';
}
}
}
}
renameNewFile::copyToNewFolder();
renameNewFile::renameNewFileInFolder();
?>
$allFiles = [];
public function dirIterator($dirName)
{
$whatsInsideDir = scandir($dirName);
foreach ($whatsInsideDir as $fileOrDir) {
if (is_dir($fileOrDir)) {
dirIterator($fileOrDir);
}
$allFiles.push($fileOrDir);
}
return $allFiles;
}

Categories