PHP: Recursive copy - php

I'm using this code to recursive copy of directories (and files). I can't understand why but, after a copy, my $source folder increase ... it has 76.3MB, after a copy it will increase to 123 MB! Any ideia?
<?php
class MyDirectory {
public function copy($source, $destination, $directoryPermission = 0755, $filePermission = 0644) {
$source = $this->addSlash($source);
$destination = $this->addSlash($destination);
$directoryIterator = new DirectoryIterator($source);
if (!file_exists($destination)) {
mkdir($destination, $directoryPermission);
}
foreach ($directoryIterator as $fileInfo) {
$filePath = $fileInfo->getPathname();
$newDestination = str_replace($source, $destination, $filePath);
if (!$fileInfo->isDot()) {
if ($fileInfo->isFile()) {
copy($filePath, $newDestination);
chmod($newDestination, $filePermission);
} else if ($fileInfo->isDir()) {
mkdir($newDestination, $directoryPermission);
$this->copy($filePath, $newDestination);
}
}
}
}
private function addSlash($directory) {
if (!empty($directory)) {
if (!preg_match('/\/$/', $directory)) {
$directory .= '/';
}
return $directory;
}
}
}
UPDATE: There is no significance differences to increase the source size!
$ diff -rq mag/ copy-mag/
Only in mag//app/etc: local.xml
Thank you.

It's very tough to deduce from the source code what goes wrong.
Analyze the directory instead, compare the differences, and update your question with the results. You can use a tool like Beyond Compare (commercial but 30-day trial available) to find out what went wrong.

Related

Php unlink() function and cyrillic

I have a problem with deleting files through unlink() function. When the file is with a cyrillic name the function doesn't work.
[24-Jul-2012 00:33:35 UTC] PHP Warning:
unlink(/home/gtsvetan/public_html/мениджър.doc) [function.unlink]: No such file or directory
in /home/gtsvetan/public_html/deleter.php on line 114
So how to delete the file when the name is cyrillized?
The code is:
$dir = is_array($dir) ? $dir : explode(',', $dir);
foreach($dir as $dirv) {
if(is_dir($dirv)) {
$objects = scandir($dirv);
foreach($objects as $object) {
if($object != "." && $object != "..") {
if(filetype($dirv."/".$object) == "dir") {
$this->delete($dirv."/".$object);
}
else {
unlink($dirv."/".$object);
}
}
}
reset($objects);
rmdir($dirv);
}
else {
unlink($dirv);
}
}
The solution:
public function delete($dir) {
$dir = is_array($dir) ? $dir : explode(',', $dir);
foreach($dir as $dirv) {
if(is_dir($dirv)) {
$d = #dir($dirv) or die();
while(false !== ($entry = $d->read())) {
if($entry[0] == ".") {
continue;
}
if(is_dir($dirv.$entry.'/')) {
$this->delete($dirv.$entry.'/');
#rmdir($dirv.$entry);
}
elseif(is_readable($dirv.$entry)) {
#unlink($dirv.$entry);
}
}
$d->close();
}
else {
#unlink($dirv);
}
#rmdir($dirv);
}
}
And here is the ajax.php which make a instance of the class :)
case 'delete':
$location = $_POST['location'];
if(is_array($location)) {
foreach($location as $v) {
$loc[] = iconv('utf-8', 'cp1251', $v);
}
$pfm->delete($loc);
}
else {
$location = iconv('utf-8', 'cp1251', $location);
$pfm->delete($location);
}
break;
It works perfect for me :)
I'd suggest renaming it first if it not plays well.
i have found that sanitizing file names is always a good idea. personally i like to have my scripts name files itself, not users (esp if it's an uploaded file). create a cleaning function that converts cyrillic characters. take a look at convert_cyr_string :: http://php.net/manual/en/function.convert-cyr-string.php
another idea, does renaming the file have the same problem as deleting them? if not, rename it to something like tobedeleted.ext then unlink it.
unlink from PHP just forwards to the corresponding system call. The file name will be passed to that function as-is, since PHP strings are just opaque sequences of bytes. This means that the name needs to be in an encoding that the system call understands. In other words, it depends on your OS. You also need to know what is the current encoding of the file name; this depends on where the input is coming from.
If you know that the system call wants UTF-8 (which is true on Linux) and that currently the name is in ISO-8859-5, then a solution using iconv would look like
unlink(iconv('iso-8859-5', 'utf-8', $dirv."/".$object));
Of course you can do the same with mb_convert_encoding as well. The same treatment is also necessary for all the other filesystem-related calls.
Hmm, I made this, It might come in useful.
<?php
function delete($link) {
foreach($link as $u) {
if(is_dir($u)) {
delete(glob($u . DIRECTORY_SEPARATOR . "*"));
rmdir($u);
} else; unlink($u);
}
return;
}
delete(glob(__DIR__ . DIRECTORY_SEPARATOR . "*"));
?>

PHP: Unlink All Files Within A Directory, and then Deleting That Directory

I there a way I can use RegExp or Wildcard searches to quickly delete all files within a folder, and then remove that folder in PHP, WITHOUT using the "exec" command? My server does not give me authorization to use that command. A simple loop of some kind would suffice.
I need something that would accomplish the logic behind the following statement, but obviously, would be valid:
$dir = "/home/dir"
unlink($dir . "/*"); # "*" being a match for all strings
rmdir($dir);
Use glob to find all files matching a pattern.
function recursiveRemoveDirectory($directory)
{
foreach(glob("{$directory}/*") as $file)
{
if(is_dir($file)) {
recursiveRemoveDirectory($file);
} else {
unlink($file);
}
}
rmdir($directory);
}
Use glob() to easily loop through the directory to delete files then you can remove the directory.
foreach (glob($dir."/*.*") as $filename) {
if (is_file($filename)) {
unlink($filename);
}
}
rmdir($dir);
The glob() function does what you're looking for. If you're on PHP 5.3+ you could do something like this:
$dir = ...
array_walk(glob($dir . '/*'), function ($fn) {
if (is_file($fn))
unlink($fn);
});
unlink($dir);
A simple and effective way of deleting all files and folders recursively with Standard PHP Library, to be specific, RecursiveIteratorIterator and RecursiveDirectoryIterator. The point is in RecursiveIteratorIterator::CHILD_FIRST flag, iterator will loop through files first, and directory at the end, so once the directory is empty it is safe to use rmdir().
foreach( new RecursiveIteratorIterator(
new RecursiveDirectoryIterator( 'folder', FilesystemIterator::SKIP_DOTS | FilesystemIterator::UNIX_PATHS ),
RecursiveIteratorIterator::CHILD_FIRST ) as $value ) {
$value->isFile() ? unlink( $value ) : rmdir( $value );
}
rmdir( 'folder' );
Try easy way:
$dir = "/home/dir";
array_map('unlink', glob($dir."/*"));
rmdir($dir);
In Function for remove dir:
function unlinkr($dir, $pattern = "*") {
// find all files and folders matching pattern
$files = glob($dir . "/$pattern");
//interate thorugh the files and folders
foreach($files as $file){
//if it is a directory then re-call unlinkr function to delete files inside this directory
if (is_dir($file) and !in_array($file, array('..', '.'))) {
unlinkr($file, $pattern);
//remove the directory itself
rmdir($file);
} else if(is_file($file) and ($file != __FILE__)) {
// make sure you don't delete the current script
unlink($file);
}
}
rmdir($dir);
}
//call following way:
unlinkr("/home/dir");
You can use the Symfony Filesystem component, to avoid re-inventing the wheel, so you can do
use Symfony\Component\Filesystem\Filesystem;
$filesystem = new Filesystem();
if ($filesystem->exists('/home/dir')) {
$filesystem->remove('/home/dir');
}
If you prefer to manage the code yourself, here's the Symfony codebase for the relevant methods
class MyFilesystem
{
private function toIterator($files)
{
if (!$files instanceof \Traversable) {
$files = new \ArrayObject(is_array($files) ? $files : array($files));
}
return $files;
}
public function remove($files)
{
$files = iterator_to_array($this->toIterator($files));
$files = array_reverse($files);
foreach ($files as $file) {
if (!file_exists($file) && !is_link($file)) {
continue;
}
if (is_dir($file) && !is_link($file)) {
$this->remove(new \FilesystemIterator($file));
if (true !== #rmdir($file)) {
throw new \Exception(sprintf('Failed to remove directory "%s".', $file), 0, null, $file);
}
} else {
// https://bugs.php.net/bug.php?id=52176
if ('\\' === DIRECTORY_SEPARATOR && is_dir($file)) {
if (true !== #rmdir($file)) {
throw new \Exception(sprintf('Failed to remove file "%s".', $file), 0, null, $file);
}
} else {
if (true !== #unlink($file)) {
throw new \Exception(sprintf('Failed to remove file "%s".', $file), 0, null, $file);
}
}
}
}
}
public function exists($files)
{
foreach ($this->toIterator($files) as $file) {
if (!file_exists($file)) {
return false;
}
}
return true;
}
}
One way of doing it would be:
function unlinker($file)
{
unlink($file);
}
$files = glob('*.*');
array_walk($files,'unlinker');
rmdir($dir);
for removing all the files you can remove the directory and make again.. with a simple line of code
<?php
$dir = '/home/files/';
rmdir($dir);
mkdir($dir);
?>

Problems copying file to home directory PHP

I'm trying copy a single file from the Plugin directory inside of my Wordpress installation to the root directory of the Wordpress installation. I need the functionality to do this no matter where the installation is located. It's for my Wordpress plugin, and it doesn't seem to be working on a site I tested.
Somehow I'm thinking that I'm not capturing each possible directory location in my function destpath() function. I need it to successfully find the exact directories of the Plugin folder so that it copies the file (process.php) to the exact root directory, no matter the location of the Wordpress install.
function destpath()
{
$base = dirname(__FILE__);
$path = false;
if (#file_exists(dirname(dirname($base))."/wp-config.php")) {
$path = dirname(dirname($base))."/process.php";
} else
if (#file_exists(dirname(dirname(dirname($base)))."/wp-config.php")) {
$path = dirname(dirname(dirname($base)))."/process.php";
} else
$path = false;
if ($path != false) {
$path = str_replace("\\", "/", $path);
}
return $path;
}
function pluginpath()
{
$base = dirname(__FILE__);
$path = false;
if (#file_exists(dirname(dirname($base))."/wp-content/plugins/malware finder/process.php")) {
$path = dirname(dirname($base))."/wp-content/plugins/malware finder/process.php";
} else
if (#file_exists(dirname(dirname(dirname($base)))."/wp-content/plugins/malware finder/process.php")) {
$path = dirname(dirname(dirname($base)))."/wp-content/plugins/malware finder/process.php";
} else
$path = false;
if ($path != false) {
$path = str_replace("\\", "/", $path);
}
return $path;
}
copy(pluginpath(), destpath());
According to the source code, it looks like the destpath and pluginpath methods of the MalwareFinder class are being injected into the printAdminPage function:
Source code line:83:
function printAdminPage() {
Source code line:108 (appears to close if):
<?php }
Source code line:111-133 (still within printAdminPage):
function destpath() { ... }
Source code line:136-158 (still within printAdminPage):
function pluginpath() { ... }
Source code line:205:
}//End function printAdminPage()
Also, on lines 62 and 65, these php tags appear unnecessary.

Deleting all files from a folder using PHP?

For example I had a folder called `Temp' and I wanted to delete or flush all files from this folder using PHP. Could I do this?
$files = glob('path/to/temp/*'); // get all file names
foreach($files as $file){ // iterate files
if(is_file($file)) {
unlink($file); // delete file
}
}
If you want to remove 'hidden' files like .htaccess, you have to use
$files = glob('path/to/temp/{,.}*', GLOB_BRACE);
If you want to delete everything from folder (including subfolders) use this combination of array_map, unlink and glob:
array_map( 'unlink', array_filter((array) glob("path/to/temp/*") ) );
This call can also handle empty directories ( thanks for the tip, #mojuba!)
Here is a more modern approach using the Standard PHP Library (SPL).
$dir = "path/to/directory";
if(file_exists($dir)){
$di = new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS);
$ri = new RecursiveIteratorIterator($di, RecursiveIteratorIterator::CHILD_FIRST);
foreach ( $ri as $file ) {
$file->isDir() ? rmdir($file) : unlink($file);
}
}
foreach (new DirectoryIterator('/path/to/directory') as $fileInfo) {
if(!$fileInfo->isDot()) {
unlink($fileInfo->getPathname());
}
}
This code from http://php.net/unlink:
/**
* Delete a file or recursively delete a directory
*
* #param string $str Path to file or directory
*/
function recursiveDelete($str) {
if (is_file($str)) {
return #unlink($str);
}
elseif (is_dir($str)) {
$scan = glob(rtrim($str,'/').'/*');
foreach($scan as $index=>$path) {
recursiveDelete($path);
}
return #rmdir($str);
}
}
$dir = 'your/directory/';
foreach(glob($dir.'*.*') as $v){
unlink($v);
}
Assuming you have a folder with A LOT of files reading them all and then deleting in two steps is not that performing.
I believe the most performing way to delete files is to just use a system command.
For example on linux I use :
exec('rm -f '. $absolutePathToFolder .'*');
Or this if you want recursive deletion without the need to write a recursive function
exec('rm -f -r '. $absolutePathToFolder .'*');
the same exact commands exists for any OS supported by PHP.
Keep in mind this is a PERFORMING way of deleting files. $absolutePathToFolder MUST be checked and secured before running this code and permissions must be granted.
See readdir and unlink.
<?php
if ($handle = opendir('/path/to/files'))
{
echo "Directory handle: $handle\n";
echo "Files:\n";
while (false !== ($file = readdir($handle)))
{
if( is_file($file) )
{
unlink($file);
}
}
closedir($handle);
}
?>
The simple and best way to delete all files from a folder in PHP
$files = glob('my_folder/*'); //get all file names
foreach($files as $file){
if(is_file($file))
unlink($file); //delete file
}
Got this source code from here - http://www.codexworld.com/delete-all-files-from-folder-using-php/
unlinkr function recursively deletes all the folders and files in given path by making sure it doesn't delete the script itself.
function unlinkr($dir, $pattern = "*") {
// find all files and folders matching pattern
$files = glob($dir . "/$pattern");
//interate thorugh the files and folders
foreach($files as $file){
//if it is a directory then re-call unlinkr function to delete files inside this directory
if (is_dir($file) and !in_array($file, array('..', '.'))) {
echo "<p>opening directory $file </p>";
unlinkr($file, $pattern);
//remove the directory itself
echo "<p> deleting directory $file </p>";
rmdir($file);
} else if(is_file($file) and ($file != __FILE__)) {
// make sure you don't delete the current script
echo "<p>deleting file $file </p>";
unlink($file);
}
}
}
if you want to delete all files and folders where you place this script then call it as following
//get current working directory
$dir = getcwd();
unlinkr($dir);
if you want to just delete just php files then call it as following
unlinkr($dir, "*.php");
you can use any other path to delete the files as well
unlinkr("/home/user/temp");
This will delete all files in home/user/temp directory.
Another solution:
This Class delete all files, subdirectories and files in the sub directories.
class Your_Class_Name {
/**
* #see http://php.net/manual/de/function.array-map.php
* #see http://www.php.net/manual/en/function.rmdir.php
* #see http://www.php.net/manual/en/function.glob.php
* #see http://php.net/manual/de/function.unlink.php
* #param string $path
*/
public function delete($path) {
if (is_dir($path)) {
array_map(function($value) {
$this->delete($value);
rmdir($value);
},glob($path . '/*', GLOB_ONLYDIR));
array_map('unlink', glob($path."/*"));
}
}
}
Posted a general purpose file and folder handling class for copy, move, delete, calculate size, etc., that can handle a single file or a set of folders.
https://gist.github.com/4689551
To use:
To copy (or move) a single file or a set of folders/files:
$files = new Files();
$results = $files->copyOrMove('source/folder/optional-file', 'target/path', 'target-file-name-for-single-file.only', 'copy');
Delete a single file or all files and folders in a path:
$files = new Files();
$results = $files->delete('source/folder/optional-file.name');
Calculate the size of a single file or a set of files in a set of folders:
$files = new Files();
$results = $files->calculateSize('source/folder/optional-file.name');
<?
//delete all files from folder & sub folders
function listFolderFiles($dir)
{
$ffs = scandir($dir);
echo '<ol>';
foreach ($ffs as $ff) {
if ($ff != '.' && $ff != '..') {
if (file_exists("$dir/$ff")) {
unlink("$dir/$ff");
}
echo '<li>' . $ff;
if (is_dir($dir . '/' . $ff)) {
listFolderFiles($dir . '/' . $ff);
}
echo '</li>';
}
}
echo '</ol>';
}
$arr = array(
"folder1",
"folder2"
);
for ($x = 0; $x < count($arr); $x++) {
$mm = $arr[$x];
listFolderFiles($mm);
}
//end
?>
For me, the solution with readdir was best and worked like a charm. With glob, the function was failing with some scenarios.
// Remove a directory recursively
function removeDirectory($dirPath) {
if (! is_dir($dirPath)) {
return false;
}
if (substr($dirPath, strlen($dirPath) - 1, 1) != '/') {
$dirPath .= '/';
}
if ($handle = opendir($dirPath)) {
while (false !== ($sub = readdir($handle))) {
if ($sub != "." && $sub != ".." && $sub != "Thumb.db") {
$file = $dirPath . $sub;
if (is_dir($file)) {
removeDirectory($file);
} else {
unlink($file);
}
}
}
closedir($handle);
}
rmdir($dirPath);
}
public static function recursiveDelete($dir)
{
foreach (new \DirectoryIterator($dir) as $fileInfo) {
if (!$fileInfo->isDot()) {
if ($fileInfo->isDir()) {
recursiveDelete($fileInfo->getPathname());
} else {
unlink($fileInfo->getPathname());
}
}
}
rmdir($dir);
}
I've built a really simple package called "Pusheh". Using it, you can clear a directory or remove a directory completely (Github link). It's available on Packagist, also.
For instance, if you want to clear Temp directory, you can do:
Pusheh::clearDir("Temp");
// Or you can remove the directory completely
Pusheh::removeDirRecursively("Temp");
If you're interested, see the wiki.
I updated the answer of #Stichoza to remove files through subfolders.
function glob_recursive($pattern, $flags = 0) {
$fileList = glob($pattern, $flags);
foreach (glob(dirname($pattern).'/*', GLOB_ONLYDIR|GLOB_NOSORT) as $dir) {
$subPattern = $dir.'/'.basename($pattern);
$subFileList = glob_recursive($subPattern, $flags);
$fileList = array_merge($fileList, $subFileList);
}
return $fileList;
}
function glob_recursive_unlink($pattern, $flags = 0) {
array_map('unlink', glob_recursive($pattern, $flags));
}
This is a simple way and good solution. try this code.
array_map('unlink', array_filter((array) array_merge(glob("folder_name/*"))));

PHP - How to count lines of code in an application [duplicate]

This question already has answers here:
count lines in a PHP project [closed]
(7 answers)
Closed 9 years ago.
I need to count the number of lines of code within my application (in PHP, not command line), and since the snippets on the web didn't help too much, I've decided to ask here.
Thanks for any reply!
EDIT
Actually, I would need the whole snippet for scanning and counting lines within a given folder. I'm using this method in CakePHP, so I'd appreciate seamless integration.
To do it over a directory, I'd use an iterator.
function countLines($path, $extensions = array('php')) {
$it = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($path)
);
$files = array();
foreach ($it as $file) {
if ($file->isDir() || $file->isDot()) {
continue;
}
$parts = explode('.', $file->getFilename());
$extension = end($parts);
if (in_array($extension, $extensions)) {
$files[$file->getPathname()] = count(file($file->getPathname()));
}
}
return $files;
}
That will return an array with each file as the key and the number of lines as the value. Then, if you want only a total, just do array_sum(countLines($path));...
You can use the file function to read the file and then count:
$c = count(file('filename.php'));
$fp = "file.php";
$lines = file($fp);
echo count($lines);
Using ircmaxell's code, I made a simple class out of it, it works great for me now
<?php
class Line_Counter
{
private $filepath;
private $files = array();
public function __construct($filepath)
{
$this->filepath = $filepath;
}
public function countLines($extensions = array('php'))
{
$it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->filepath));
foreach ($it as $file)
{
// if ($file->isDir() || $file->isDot())
if ($file->isDir() )
{
continue;
}
$parts = explode('.', $file->getFilename());
$extension = end($parts);
if (in_array($extension, $extensions))
{
$files[$file->getPathname()] = count(file($file->getPathname()));
}
}
return $files;
}
public function showLines()
{
echo '<pre>';
print_r($this->countLines());
echo '</pre>';
}
public function totalLines()
{
return array_sum($this->countLines());
}
}
// Get all files with line count for each into an array
$loc = new Line_Counter('E:\Server\htdocs\myframework');
$loc->showLines();
echo '<br><br> Total Lines of code: ';
echo $loc->totalLines();
?>
PHP Classes has a nice class for counting lines for php files in a directory:
http://www.phpclasses.org/package/1091-PHP-Calculates-the-total-lines-of-code-in-a-directory.html
You can specify the file types you want to check at the top of the class.
https://github.com/sebastianbergmann/phploc
a little dirty, but you can also use system / exec / passthru wc -l *

Categories