< Pete Goodman Web developer >
Labs - PHP File/Folder Deleter
Friday 13th November 2009, 00:25
I've just had to write a quick PHP script to allow the easy deletion of files and folders within a specific directory.
It's a simple solution, a single PHP file that can be uploaded to a web-server. Just browse to the file and select the items you want to delete.
I have included the code for this script below, or it can be downloaded from here
It's fairly straightforward, for my purposes I didn't need to worry about validation or particular security issues with the error-checking of paths, although it would definitely be a good idea to add this if this were used as the basis of a more complicated script.
As ever when working with the removal of files, be careful when using this as there is no undo!
<?php
/**
* Delete files from a web server.
*
* Careful!
*
* @author PG
*/
// initialise the page - optionally passing through a path to index
$deleter = new Deleter("./");
/**
* This class is responsible for deleting files
*/
class Deleter {
/**
* The name of this file, in case it you want to rename it
*
* @var string $filename This file
*/
var $filename;
/**
* A list of filenames & directory names to ignore
*
* @var array $ignorelist The file names to skip over { feel free to add more }
*/
var $ignorelist = array (
'.',
'..',
'file-name-to-ignore.txt'
);
/**
* PHP4 Constructor - for backwards compatibility
*/
function Deleter($path="./") {
$this->__construct($path);
}
/**
* Main Constructor
*
* Builds the page header, footer, and contains the logic to decide what to do next
*/
function __construct($path="./") {
// get current file name, for all internal links
$this->filename = basename(__FILE__);
array_push($this->ignorelist, $this->filename);
// insert page header
$this->createHeader();
// condition: create initial file list?
if (isset($_GET['delete']) && !empty($_GET['delete'])) {
// a path has been set, escape and use
$path = basename($_GET['delete']);
$path = urldecode($path);
//$path = mysql_real_escape_string($path);
// condition : Step 2: seek deletion confirmation?
if (!isset($_GET['confirm']) || $_GET['confirm'] != 'aye') {
$this->createConfirmationStep($path);
// step 3: delete!
} else {
$this->createShowDelete($path);
}
// step 1: no files selected, create file list
} else {
echo '
<p>(Careful how you use this, there\'s no undo!)</p>
<ul>
';
$this->createFileList($path);
echo '</ul>';
}
// insert page footer
$this->createFooter();
}
/**
* Step 1: Create a list of all files within a specific directory
*
* @param string $path The server path to look for files in
* @return array $fileList Array of all files, with file/directory details
* @access public
*/
function createFileList($path) {
// condition : if the path isn't set, assume one
if (!isset($path)) {
$path = "./";
}
// temporary arrays to hold separate file and directory content
$filelist = array();
$directorylist = array();
// get the ignore list, in local scope
$ignorelist = $this->ignorelist;
// Open directory and read contents
if (is_dir($path)) {
// loop through the contents (PHP4 compat)
$dh = opendir($path);
while (false !== ($file = readdir($dh))) {
// skip over any files in the ignore list
if (!in_array($file, $ignorelist)) {
// condition : if it is a directory, add to dir list array
if (is_dir($path.$file)) {
$directorylist[] = array(
"path" => $path,
"file" => $file,
"filetype" => 'directory',
"date" => date("M d Y, H:i", filemtime($path.$file."")),
"filecount" => $this->countRelevantFiles($path.$file),
"filesize" => 0
);
// file, add to file array
} else {
$filelist[] = array(
"path" => $path,
"file" => $file,
"filetype" => $this->getFileType($path.$file) . " file",
"date" => date("M d Y, H:i", filemtime($path.$file."")),
"filecount" => 0,
"filesize" => $this->getFileSize(filesize($path.$file))
);
}
}
}
}
// merge file and directory lists
$finalList = array_merge($directorylist, $filelist);
// loop through each file
foreach ($finalList as $key => $value) {
// condition : add trailing slash for directories
$trailingslash = ($value['filetype'] == 'directory' ) ? '/' : '';
// condition : if it is a directory, display count of subfiles
if ($value['filetype'] == 'directory') {
$fileending = ($value['filecount'] == 1) ? 'item' : 'items';
$filedetails = ' (contains '.$value['filecount'].' '.$fileending.')';
// else, if it is a file, display file size
} else {
$filedetails = ' ('.$value['filesize'].')';
}
// create the html for each project
echo '
<li class="' . $value['filetype'].'" id="file_' . urlencode($value['file']) . '">
<strong>' . $value['file'] . '</strong> /
<em class="type">' . $value['filetype'] . '</em> /
<em class="type">' . $filedetails . '</em> /
';
if ($value['filetype'] != "directory") {
echo '
<em class="size">file size: ' . $value['filesize'] . '</em> /
';
}
echo '
<em class="date">created: ' . $value['date'] . '</em> /
<a href="./'.$this->filename.'?delete='.urlencode($value['file'].$trailingslash).'">
Delete
</a>
</li>
';
}
}
/**
* count the number of files in a directory, not including the list of ignorable files
*
* @param string $path The server path to look for files in
* @return int $count The number of relevant files
* @access private
*/
function countRelevantFiles($path, $count = 0) {
// open the directory
if (is_dir($path)) {
// loop through all files, checking if we should count the current one
$dh = opendir($path);
while (false !== ($file = readdir($dh))) {
if (!in_array($file, $this->ignorelist)) {
$count++;
if(is_dir($path."/".$file)) {
$count = $this->countRelevantFiles($path."/".$file, $count);
}
}
}
}
// return the result
return $count;
}
/**
* list all sub-files of a directory
*
* @param string $path The server path to look for files in
* @return void
* @access private
*/
function listFilesToDelete($path) {
// open the directory
if (is_dir($path)) {
// loop through all files, checking if we should count the current one
$dh = opendir($path);
while (false !== ($file = readdir($dh))) {
if (!in_array($file, $this->ignorelist)) {
echo '<li>'.$path.'/'.$file.'</li>';
if(is_dir($path."/".$file)) {
$this->listFilesToDelete($path."/".$file);
}
}
}
}
}
/**
* Delete files
*
* @param string $path The server path to delete
* @return void
* @access private
*/
function delete($path) {
// Simple delete for a file
if (is_file($path)) {
echo '<li>deleting file: ' . $path . '</li>';
return unlink($path);
} else {
// Loop through the folder
$dir = dir($path);
while (false !== $entry = $dir->read()) {
// ignore specified files
if (in_array($entry, $this->ignorelist)) {
continue;
}
// deep delete
if (is_dir($path."/".$entry)) {
$this->delete($path."/".$entry);
} else {
echo '<li>removing file: ' . $path.'/'.$entry.'</li>';
unlink($path."/".$entry);
}
}
// Clean up
$dir->close();
echo '<li>removing directory: '.$path.'</li>';
return rmdir($path);
}
}
/**
* Create a nice readable filesize from the number of bytes in a file
*
* @param int $size the size in bytes
* @param string $retstring
*
* @return string the size in nice words
*/
function getFileSize($size, $retstring = null)
{
$sizes = array('B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB');
if ($retstring === null) { $retstring = '%01.2f %s'; }
$lastsizestring = end($sizes);
foreach ($sizes as $sizestring) {
if ($size < 1024) { break; }
if ($sizestring != $lastsizestring) { $size /= 1024; }
}
if ($sizestring == $sizes[0]) { $retstring = '%01d %s'; } // Bytes aren't normally fractional
return sprintf($retstring, $size, $sizestring);
}
/**
* Function to find a file type for a given filename
*
* @param string $file filename/path
* @return string $extension file type
*/
function getFileType($file="") {
// get file name
$filearray = explode("/", $file);
$filename = array_pop($filearray);
// condition : if no file extension, return
if(strpos($filename, ".") === false) return false;
// get file extension
$filenamearray = explode(".", $filename);
$extension = $filenamearray[(count($filenamearray) - 1)];
return $extension;
}
/* Page Building Methods */
/**
* Create page header
*/
function createHeader(){
echo '
<!DOCTYPE html>
<html dir="ltr" lang="en-gb">
<head>
<meta charset="utf-8" />
<title>Deleter</title>
<style type="text/css">
* { margin:0; padding:0 }
body { font-family:Arial, sans-serif; background:#999; }
#wrapper { margin:20px; padding:20px; background:#fff }
h1 { margin-bottom:0.5em }
p { margin-bottom:1em; color:#f00; }
em { margin-right:2px; font-size:80%; color:#666; vertical-align:top; }
ul, ol { margin:0 0 1em 2em; }
li { color:#666; margin-bottom:0.5em }
li.directory { color:#000; }
a { color:#f90; }
a:hover { text-decoration:none }
p.confirm a { display:inline-block; clear:both; padding:2px 5px; font-size:110%; font-weight:bold; color:#fff; background:#f90; text-decoration:none; }
p.confirm a:hover { background:#f60; }
</style>
</head>
<body>
<div id="wrapper">
<h1>File deleter</h1>
';
}
/**
* Create page footer
*/
function createFooter(){
echo '
</div>
</body>
</html>
';
}
/**
* Create confirmation step
*/
function createConfirmationStep($path){
echo '
<p><a href="'.$this->filename.'">« back to file list</a></p>
<p>Please confirm that you want to delete the following files:</p>
<p class="confirm"><a href="'.$this->filename.'?delete='.$path.'&confirm=aye">Delete</a></p>
<ol>
<li>'.$path.'</li>
';
$this->listFilesToDelete($path);
echo '
</ol>
<p class="confirm"><a href="'.$this->filename.'?delete='.$path.'&confirm=aye">Delete</a></p>
';
}
/**
* Show the files you're deleting
*/
function createShowDelete($path){
echo '
<p><a href="'.$this->filename.'">« back to file list</a></p>
<p>The following items have been removed:</p>
<ol>
';
$this->delete($path);
echo '
</ol>
<p><strong>Deletion complete.</strong></p>
<p><a href="'.$this->filename.'">« back to file list</a></p>
';
}
}
?>
Comments
Be the first person to comment on this lab...
Please feel free to add a comment
* denotes a required field.
Email addresses are for verification only, and will not be published
The RECAPTCHA spam protection enables me to differentiate between genuine human comments and computer-generated spam.