views:

85

answers:

4

I am using PHP and I need to script something like below:

I have to compare two folder structure and with reference of source folder I want to delete all the files/folders present in other destination folder which do not exist in reference source folder, how could i do this?

EDITED:

$original = scan_dir_recursive('/var/www/html/copy2');
$mirror = scan_dir_recursive('/var/www/html/copy1');
function scan_dir_recursive($dir) {

  $all_paths = array();
  $new_paths = scandir($dir);

  foreach ($new_paths as $path) {
    if ($path == '.' || $path == '..') {
      continue;
    }
    $path = $dir . DIRECTORY_SEPARATOR . $path;
    if (is_dir($path)) {
      $all_paths = array_merge($all_paths, scan_dir_recursive($path));
    } else {
      $all_paths[] = $path;
    }
  }

  return $all_paths;

}
foreach($mirror as $mirr)
{
   if($mirr != '.' && $mirr != '..')
   {
     if(!in_array($mirr, $original))
     {
        unlink($mirr);
        // delete the file
     }

   }
}

The above code shows what i did.. Here My copy1 folder contains extra files than copy2 folders hence i need these extra files to be deleted.

EDITED: Below given output is are arrays of original Mirror and of difference of both..

Original Array
(
    [0] => /var/www/html/copy2/Copy (5) of New Text Document.txt
    [1] => /var/www/html/copy2/Copy of New Text Document.txt
)

Mirror Array
(
    [0] => /var/www/html/copy1/Copy (2) of New Text Document.txt
    [1] => /var/www/html/copy1/Copy (3) of New Text Document.txt
    [2] => /var/www/html/copy1/Copy (5) of New Text Document.txt
)

Difference Array
(
    [0] => /var/www/html/copy1/Copy (2) of New Text Document.txt
    [1] => /var/www/html/copy1/Copy (3) of New Text Document.txt
    [2] => /var/www/html/copy1/Copy (5) of New Text Document.txt
)

when i iterate a loop to delete on difference array all files has to be deleted as per displayed output.. how can i rectify this.. the loop for deletion is given below.

$dirs_to_delete = array();
foreach ($diff_path as $path) {
    if (is_dir($path)) {
        $dirs_to_delete[] = $path;
    } else {
        unlink($path);
    }
}

while ($dir = array_pop($dirs_to_delete)) {
    rmdir($dir);
}
+2  A: 

First you need a recursive listing of both directories. A simple function like this will work:

function scan_dir_recursive($dir, $rel = null) {

  $all_paths = array();
  $new_paths = scandir($dir);

  foreach ($new_paths as $path) {

    if ($path == '.' || $path == '..') {
      continue;
    }

    if ($rel === null) {
        $path_with_rel = $path;
    } else {
        $path_with_rel = $rel . DIRECTORY_SEPARATOR . $path;
    }

    $full_path = $dir . DIRECTORY_SEPARATOR . $path;
    $all_paths[] = $path_with_rel;

    if (is_dir($full_path)) {
      $all_paths = array_merge(
        $all_paths, scan_dir_recursive($full_path, $path_with_rel)
      );
    }

  }

  return $all_paths;

}

Then you can compute their difference with array_diff.

$diff_paths = array_diff(
    scan_dir_recursive('/foo/bar/mirror'),
    scan_dir_recursive('/qux/baz/source')
);

Iterating over this array, you will be able to start deleting files. Directories are a bit trickier because they must be empty first.

// warning: test this code yourself before using on real data!

$dirs_to_delete = array();
foreach ($diff_paths as $path) {
    if (is_dir($path)) {
        $dirs_to_delete[] = $path;
    } else {
        unlink($path);
    }
}

while ($dir = array_pop($dirs_to_delete)) {
    rmdir($dir);
}

I've tested things and it should be working well now. Of course, don't take my word for it. Make sure to setup your own safe test before deleting real data.

erisco
Its not working as I want it do, I want only those files to be deleted from the mirror folder which are not in the source folder, but the code deletes all the files from mirror folder... pls help
OM The Eternity
This is likely because your mirror is at `/foo/bar/mirror` and your source is at `/baz/qux/source`. `array_diff` will of course then see everything as different. Either slice off these parts of the paths or build in functionality to `scan_dir_recursive` to exclude them in the first place.
erisco
I have changed `scan_dir_recursive` to act more like `scandir` by not pushing the initial directory onto each path. Now you should have an easier time with `array_diff`.
erisco
Thanks a lot Erisco for giving ur precious to my work, but still to make it work I just added a single line to unlink the files and folders.. ls see my reply below the change made in the code is commented as "added code to unlink"
OM The Eternity
A: 

For recursive directories please use:

$modified_directory = new RecursiveIteratorIterator(
       new RecursiveDirectoryIterator('path/to/modified'), true
);
$modified_files = array();
foreach ($modified_directory as $file)
{
    $modified_files []= $file->getPathname();
}

You can do other things like $file->isDot(), or $file->isFile(). For more file commands with SPLFileInfo visit http://www.php.net/manual/en/class.splfileinfo.php

Gorilla3D
+1 for suggesting Spl
Gordon
pls give an example as others have given I m aware of the fact that spl will help, can u pls provide the example @GORDON and @Gorilla3D
OM The Eternity
@OMTheEternity the example is right up there. Use the RecursiveDirectoryIterator. http://www.phpro.org/tutorials/Introduction-to-SPL.html
Gordon
A: 
Gaurav Sharma
Not working, it deletes all my files...
OM The Eternity
simply copying and pasting the code is not going to help completely my dear friend. Paste your own code here first, then only one can properly understand what actually you are trying to do.
Gaurav Sharma
Yaar gaurav I am trying to do this since morning and ur code is doing the same thing as of "erisco" It deletes all my files, i need only those files to be deleted from the mirror folder which does not exist in the source folder
OM The Eternity
Chk the updated question Gaurav Bhai
OM The Eternity
ok, I know it irritates a lot when a code does not work accordingly. Take a print_r() of the original array and mirror array and then see the output if they have any common elements.I can only suggest at my level best brother. you must have been doing some different logic here. Try having some rest and then rethink your logic. I will code this problem by myself and then post answer to this post here. :-)
Gaurav Sharma
Thanks Mate.. I will do that and wait for ur reply as welll.... pls revert again...
OM The Eternity
sure take some rest now
Gaurav Sharma
pls chk the updated question I have displayed the print_r() out-put and their array_diff print_r output..
OM The Eternity
A: 

Thanks all for the precious time given to my work, Special Thanks to erisco for his dedication for my problem, Below Code is the perfect code to acomplish the task I was supposed to do, with a little change in the erisco's last edited reply...

$source = '/var/www/html/copy1';
$mirror = '/var/www/html/copy2';

function scan_dir_recursive($dir, $rel = null) {

  $all_paths = array();
  $new_paths = scandir($dir);

  foreach ($new_paths as $path) {

    if ($path == '.' || $path == '..') {
      continue;
    }

    if ($rel === null) {
        $path_with_rel = $path;
    } else {
        $path_with_rel = $rel . DIRECTORY_SEPARATOR . $path;
    }

    $full_path = $dir . DIRECTORY_SEPARATOR . $path;
    $all_paths[] = $path_with_rel;

    if (is_dir($full_path)) {
      $all_paths = array_merge(
        $all_paths, scan_dir_recursive($full_path, $path_with_rel)
      );
    }

  }

  return $all_paths;

}
$diff_paths = array_diff(
    scan_dir_recursive($mirror),
    scan_dir_recursive($source)
);



echo "<pre>Difference ";print_r($diff_paths);

$dirs_to_delete = array();
foreach ($diff_paths as $path) {
    $path = $mirror."/".$path;//added code to unlink.
    if (is_dir($path)) {

        $dirs_to_delete[] = $path;
    } else {

        if(unlink($path))
        {
            echo "File ".$path. "Deleted.";
        }
    }
}

while ($dir = array_pop($dirs_to_delete)) {
    rmdir($dir);
}
OM The Eternity