PHP Directory Listing Code Malfunction - php

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.

Related

php - extract files from folder in a zip

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';
}
}

Instruct PHP To Ignore Scanning A Folder

I've been working with a handy php script, which scans my site and spits out links to all the pages it finds. The problem is, it's also scanning my 'includes' folder, which contains all my .inc.php files.
Obviously I'd rather it ignore this folder when scanning the site, but for the life of me I can't see how to edit the script to tell it to do so.
The script is:
<?php
// starting directory. Dot means current directory
$basedir = ".";
// function to count depth of directory
function getdepth($fn){
return (($p = strpos($fn, "/")) === false) ? 0 : (1 + getdepth(substr($fn, $p+1)));
}
// function to print a line of html for the indented hyperlink
function printlink($fn){
$indent = getdepth($fn); // get indent value
echo "<li class=\"$indent\"><a href=\"$fn\">"; //print url
$handle = fopen($fn, "r"); //open web page file
$filestr = fread($handle, 1024); //read top part of html
fclose($handle); //clos web page file
if (preg_match("/<title>.+<\/title>/i",$filestr,$title)) { //get page title
echo substr($title[0], 7, strpos($title[0], '/')-8); //print title
} else {
echo "No title";
}
echo "</a></li><br>\n"; //finish html
}
// main function that scans the directory tree for web pages
function listdir($basedir){
if ($handle = #opendir($basedir)) {
while (false !== ($fn = readdir($handle))){
if ($fn != '.' && $fn != '..'){ // ignore these
$dir = $basedir."/".$fn;
if (is_dir($dir)){
listdir($dir); // recursive call to this function
} else { //only consider .html etc. files
if (preg_match("/[^.\/].+\.(htm|html|php)$/",$dir,$fname)) {
printlink($fname[0]); //generate the html code
}
}
}
}
closedir($handle);
}
}
// function call
listdir($basedir); //this line starts the ball rolling
?>
Now I can see where the script is told to ignore certain files, and I've tried appending:
&& $dir != 'includes'
...to it in numerous places, but my php knowledge is simply too shaky to know exactly how to integrate that code into the script.
If anyone can help, then you'd be saving me an awfully large headache. Cheers.
Add it this line:
if ($fn != '.' && $fn != '..'){ // ignore these
so it's
if ($fn != '.' && $fn != '..' && $fn != 'includes'){ // ignore these
Your path needs to be absolute. Add it at the top of listdir
function listdir($basedir){
if($basedir == '/path/to/includes') {
return;
} [...]
This also makes sure that only one includes folder will be ignored.

Find all .htaccess files and replace content with PHP script

I need to create a script that will find all my .htaccess files on my server and replace their content with the new content I need in order for my pages to be SEO friendly.
So far I've come across a few scripts that will find all the .htaccess files but I need to be able to open, replace all content with new and save with the proper permissions.
Can anyone help me with the following code to add the extra functionality I need?
<?php
function searchDir($dir) {
$dhandle = opendir($dir);
if ($dhandle) {
// loop through it
while (false !== ($fname = readdir($dhandle))) {
// if the element is a directory, and does not start with a '.' or '..'
// we call searchDir function recursively passing this element as a parameter
if (is_dir( "{$dir}/{$fname}" )) {
if (($fname != '.') && ($fname != '..')) {
echo "Searching Files in the Directory: {$dir}/{$fname} <br />";
searchDir("$dir/$fname");
}
// if the element is an .htaccess file then replace content
} else {
if($fname == ".htaccess")
{
echo "Replacing content of file ".$dir/$fname."<br />";
// I need the code for editing the files here.
}
}
}
closedir($dhandle);
}
}
searchDir(".");
?>
Modify your else loop with this
else {
if($fname == ".htaccess")
{
echo "Replacing content of file ".$dir/$fname."<br />";
// I need the code for editing the files here.
$htaccess_content = " Your htaccess string " ; // you can do this assignment at the top
file_put_contents("{$dir}/{$fname}",$htaccess_content) ;
}
}
Use file_get_contents() and file_put_contents().
http://php.net/manual/en/function.file-get-contents.php
http://php.net/manual/en/function.file-put-contents.php

php directory explorer script help

I have created this php script which displays the contents of a designated directory and allows users to download each file. Here is the code:
<?php
if ($handle = opendir('test')) {
while (false !== ($file = readdir($handle))) {
if ($file != "." && $file != "..") {
echo "<a href='test/$file'>$file\n</a><br/>";
}
}
closedir($handle);
}
?>
This script also displays folders, but when I click a folder, it does display the contents of the folder, but in the default Apache autoindex view.
What I would like the script to do when a folder is clicked, is display the contents, but in the same fashion as the original script does (as this is more editable with css and the like).
Would you know how to achieve this?
Don't create a link to the directory itself, but to a php page which displays the contents.
Change your php code to somthing like:
if(isset($_REQUEST['dir'])) {
$current_dir = $_REQUEST['dir'];
} else {
$current_dir = 'test';
}
if ($handle = opendir($current_dir)) {
while (false !== ($file_or_dir = readdir($handle))) {
if(in_array($file_or_dir, array('.', '..'))) continue;
$path = $current_dir.'/'.$file_or_dir;
if(is_file($path)) {
echo ''.$file_or_dir."\n<br/>";
} else {
echo ''.$file_or_dir."\n<br/>";
}
}
closedir($handle);
}
PS write you html code with double quotes.
You need your HREF to point back to your PHP script, and not the directory. You will then need to update your PHP script to now which directory it needs to read.

move all files in a folder to another?

when moving one file from one location to another i use
rename('path/filename', 'newpath/filename');
how do you move all files in a folder to another folder? tried this one without result:
rename('path/*', 'newpath/*');
A slightly verbose solution:
// Get array of all source files
$files = scandir("source");
// Identify directories
$source = "source/";
$destination = "destination/";
// Cycle through all source files
foreach ($files as $file) {
if (in_array($file, array(".",".."))) continue;
// If we copied this successfully, mark it for deletion
if (copy($source.$file, $destination.$file)) {
$delete[] = $source.$file;
}
}
// Delete all successfully-copied files
foreach ($delete as $file) {
unlink($file);
}
Please try this solution, it's tested successfully ::
<?php
$files = scandir("f1");
$oldfolder = "f1/";
$newfolder = "f2/";
foreach($files as $fname) {
if($fname != '.' && $fname != '..') {
rename($oldfolder.$fname, $newfolder.$fname);
}
}
?>
An alternate using rename() and with some error checking:
$srcDir = 'dir1';
$destDir = 'dir2';
if (file_exists($destDir)) {
if (is_dir($destDir)) {
if (is_writable($destDir)) {
if ($handle = opendir($srcDir)) {
while (false !== ($file = readdir($handle))) {
if (is_file($srcDir . '/' . $file)) {
rename($srcDir . '/' . $file, $destDir . '/' . $file);
}
}
closedir($handle);
} else {
echo "$srcDir could not be opened.\n";
}
} else {
echo "$destDir is not writable!\n";
}
} else {
echo "$destDir is not a directory!\n";
}
} else {
echo "$destDir does not exist\n";
}
tried this one?:
<?php
$oldfolderpath = "old/folder";
$newfolderpath = "new/folder";
rename($oldfolderpath,$newfolderpath);
?>
So I tried to use the rename() function as described and I kept getting the error back that there was no such file or directory. I placed the code within an if else statement in order to ensure that I really did have the directories created. It looked like this:
$tempDir = '/home/site/images/tmp/';
$permanentDir = '/home/site/images/' . $claimid; // this was stored above
mkdir($permanentDir,0775);
if(is_dir($permanentDir)){
echo $permanentDir . ' is a directory';
if(is_dir($tempDir)){
echo $tempDir . ' is a directory';
}else{
echo $tempDir . ' is not a directory';
}
}else{
echo $permanentDir . ' is not a directory';
}
rename($tempDir . "*", $permanentDir);
So when I ran the code again, it spit out that both paths were directories. I was stumped. I talked with a coworker and he suggested, "Why not just rename the temp directory to the new directory, since you want to move all the files anyway?"
Turns out, this is what I ended up doing. I gave up trying to use the wildcard with the rename() function and instead just use the rename() to rename the temp directory to the permanent one.
so it looks like this.
$tempDir = '/home/site/images/tmp/';
$permanentDir = '/home/site/images/' . $claimid; // this was stored above
mkdir($permanentDir,0775);
rename($tempDir, $permanentDir);
This worked beautifully for my purposes since I don't need the old tmp directory to remain there after the files have been uploaded and "moved".
Hope this helps. If anyone knows why the wildcard doesn't work in the rename() function and why I was getting the error stating above, please, let me know.
Move or copy the way I use it
function copyfiles($source_folder, $target_folder, $move=false) {
$source_folder=trim($source_folder, '/').'/';
$target_folder=trim($target_folder, '/').'/';
$files = scandir($source_folder);
foreach($files as $file) {
if($file != '.' && $file != '..') {
if ($move) {
rename($source_folder.$file, $target_folder.$file);
} else {
copy($source_folder.$file, $target_folder.$file);
}
}
}
}
function movefiles($source_folder, $target_folder) {
copyfiles($source_folder, $target_folder, $move=true);
}
try this:
rename('path/*', 'newpath/');
I do not see a point in having an asterisk in the destination
If the target directory doesn't exist, you'll need to create it first:
mkdir('newpath');
rename('path/*', 'newpath/');
As a side note; when you copy files to another folder, their last changed time becomes current timestamp. So you should touch() the new files.
... (some codes for directory looping) ...
if (copy($source.$file, $destination.$file)) {
$delete[] = $source.$file;
$filetimestamp = filemtime($source.$file);
touch($destination.$file,$filetimestamp);
}
... (some codes) ...
Not sure if this helps anyone or not, but thought I'd post anyway. Had a challenge where I has heaps of movies I'd purchased and downloaded through various online stores all stored in one folder, but all in their own subfolders and all with different naming conventions. I wanted to move all of them into the parent folder and rename them all to look pretty. all of the subfolders I'd managed to rename with a bulk renaming tool and conditional name formatting. the subfolders had other files in them i didn't want. so i wrote the following php script to, 1. rename/move all files with extension mp4 to their parent directory while giving them the same name as their containing folder, 2. delete contents of subfolders and look for directories inside them to empty and then rmdir, 3. rmdir the subfolders.
$handle = opendir("D:/Movies/");
while ($file = readdir($handle)) {
if ($file != "." && $file != ".." && is_dir($file)) {
$newhandle = opendir("D:/Movies/".$file);
while($newfile = readdir($newhandle)) {
if ($newfile != "." && $newfile != ".." && is_file("D:/Movies/".$file."/".$newfile)) {
$parts = explode(".",$newfile);
if (end($parts) == "mp4") {
if (!file_exists("D:/Movies/".$file.".mp4")) {
rename("D:/Movies/".$file."/".$newfile,"D:/Movies/".$file.".mp4");
}
else {
unlink("D:/Movies/".$file."/".$newfile);
}
}
else { unlink("D:/Movies/".$file."/".$newfile); }
}
else if ($newfile != "." && $newfile != ".." && is_dir("D:/Movies/".$file."/".$newfile)) {
$dirhandle = opendir("D:/Movies/".$file."/".$newfile);
while ($dirfile = readdir($dirhandle)){
if ($dirfile != "." && $dirfile != ".."){
unlink("D:/Movies/".$file."/".$newfile."/".$dirfile);
}
}
rmdir("D:/Movies/".$file."/".$newfile);
}
}
unlink("D:/Movies/".$file);
}
}
i move all my .json files from root folder to json folder with this
foreach (glob("*.json") as $filename) {
rename($filename,"json/".$filename);
}
pd: someone 2020?

Categories