PHP move chosen files from A folder to B folder - php

This is a tricky one and I'm not sure where to start, so any help will be grateful.
I have a parent folder called 'source' (c:/dev/source) which contains several child folders.
I need a PHP script that will display the child folders with checkboxes next to each, and a text field for a new folder name, allowing users to tick the checkboxes of the ones they want to copy to a 'destination of c:/dev/destination/the_folder_name_they_typed_in
When they click submit, the selected child folders will be copied from c:/dev/source to c:/dev/destination/the_folder_name_they_typed_in
This is all running on a local internal development server. The child folders will always be in c:/dev/source/

Somme advice:
Use a whitelist for allowed characters in destination folder. Only commit the operation if it matches:
^[a-z0-9_-]+$
You can use array indices for directory names. This way you can iterate thru the ckeckboxes with foreach ($_POST["dirs"]) { ... }
<input type="checkbox" name="dirs[directory_name]"/>
<input type="checkbox" name="dirs[other_dir_name]"/>
<input type="checkbox" name="dirs[third_directory_name]"/>
Always checkthe directory names against a whitelist like above. (If you allow characters like . or / or many other it can be a security risk).

Here's a not well known little bit of code called DirectoryIterator. It's not fully documented on the PHP site, but heres the jist of it:
Create a list of files and folders with checkboxes next to them, slap them all in an array.
$Directory = new RecursiveDirectoryIterator('c:/dev/source');
$Iterator = new RecursiveIteratorIterator($Directory);
?><form method="post"><?
foreach($Iterator as $r){
if($r->isDot()) continue;
echo "<input type=\"checkbox\" name=\"copy[]\" value=\"".($r->getSubPathName())."\"> ".$r->getSubPathName() . " <br>";
}
?></form><?
Now add this part to the top of the file
<?php
if($_POST){
if(is_array($_POST['copy'])) foreach($_POST['copy'] as $c){
#copy($c, str_replace('c:/dev/source','c:/dev/dest', $c));
echo "copied: $c to ". str_replace('c:/dev/source','c:/dev/dest', $c) . "<br>";
}
}
I'm not fully sure what result you get from $r->getSubPathName() can you let me know if it outputs an array? if so it might be that you replace that with $r->getSubPath() and then add the "c:/dev/source" to the variable $c when you copy it?
Further Reading:
here

Related

File structure in database

I'm making a simple file listing function in PHP, just to recursively list all the files in a directory.
The function I have right now looks something like this:
<?php
function listFiles($dir){
echo "<ul class=\"filebrowser\">";
$dirCont = scandir($dir); // scan the whole directory
sortFoldersFirst($dirCont,$dir); // sort alphabetically, folders first
foreach ($dirCont as $value) {
if (!in_array($value,array(".","..",".deleted"))){ // don't list the parent folder, current folder, or the (hidden) .deleted folder
if (is_dir($dir . DIRECTORY_SEPARATOR . $value)){ // if it's a folder
echo "<h3 class=\"filebrowser\">" . $value . "</h3>"; // show the folder name
listFiles($dir . DIRECTORY_SEPARATOR . $value); // do the same again for the child folder
} else {
echo "<li>".$value."</li>"; // a link to the file
}
}
}
echo "</ul>";
}
?>
This gives me something like this:
This technique works just fine, however, I'd like to store a little more information about the files, like the author, comments, maybe a link to a thumbnail etc.
I'd like to get rid of the 'real' directory structure, and store everything in a database. (Just all files in 1 big folder, and links to the files in the database, not the actual files)
How can I store this information in the database, and how can I get it back out, without changing the result in the browser.
In other words: how can I get the tree structure in and out of the database, and how do I recursively loop through it.
I found this answer.
It shows how to make a database tree structure by saving the parent folder's id for every file/folder. This makes it easy to get the full path of a file, but it seems a bit less convenient to list all contents of a folder.
Is there a better solution to this problem?
Thanks in advance,
Pieter

How to sort results of directory search...?

I have a sub directory called "logs" where I store files for download. I'm trying to create a dynamic download page.
There are 5 raids that are referenced (dragonsoul, firelands, tier11, tier14 and ulduar) and the files in the log folder and named by the format ex. dragonsoul07072013.csv (where the end of the name is a date).
The download page:
I have a form with a select list for each of the raids that submits to itself.
<?php
$raidref=$_POST['raid'];
function getfilename($filedate)
{
return $filedate[1];
}
$path = realpath('logs');
foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path)) as $file)
{
if (isset($raidref) and $raidref!="")
{
$filedate=explode($raidref,$file);
$filedatestr=getfilename($filedate);
$filename=$raidref.$filedatestr;
if ($filedatestr=="")
{unset($filename);}
if (isset($filename))
{ echo"$filename<br /><br /><input type=\"button\" value=\"Download\" onClick=\"download('../logs/".$filename."')\"><br /><br />";}
}
}
This code works as is but I want to be able to sort the files found so that the most recent file is on top.
The way the code works now is you select a raid from the drop down, submit and it will display the name of the file and a download button and it will repeat these for each file found that includes the name of the raid in the file.
Seeing as the file name includes dates in it, it'd be easier for people to get to the right download if the most recent link is at the top.
How should I go about printing my results sorted descending?
How it currently displays:
dragonsoul07072013.csv
Download
dragonsoul07142013.csv
Download
dragonsoul07212013.csv
Download
How I'd like it to display:
dragonsoul07212013.csv
Download
dragonsoul07142013.csv
Download
dragonsoul07072013.csv
Download
Also as a note, please explain your answers. I'm learning php from trial and error and research as I need to do things so your explanations will help a lot so I can figure this out on my own in the future (I actually hate to ask for help but I just don't have a clue of how to even approach this).
Seeing as I'm new to the website, I can't answer my own question for another 8 hours but I just wanted to let you guys know your answers helped. This is my revised code, which seems to be doing the trick!
<?php
$raidref=$_POST['raid'];
function getfilename($filedate) {return $filedate[1];}
$files=array();
$path = realpath('logs');
foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path)) as $file)
{
if (isset($raidref) and $raidref!="")
{
$filedate=explode($raidref,$file);
$filedatestr=getfilename($filedate);
$filename=$raidref.$filedatestr;
if ($filedatestr=="") {unset($filename);}
if (isset($filename)) {$files[]=$filename;}
}
}
arsort($files);
foreach ($files as $files)
{
echo"$files<br /><br /><input type=\"button\" value=\"Download\" onClick=\"download('../logs/".$files."')\"><br /><br />";
}
?>
Put the files into an array.
Use the sort() function.
Loop through array.

PHP copy a file to multiple child folders with random names

I have an HTML form and one of the inputs creates a folder. The folder name is chosen by the website visitor. Every visitor creates his own folder on my website so they are randomly generated. They are created using PHP Code.
Now I would like to write a PHP code to copy a file to all of the child directories regardless the quantity of directories being generated.
I do not wish to stay writing a PHP line for every directory that is created - i.e. inserting the filename name manually (e.g. folder01, xyzfolder, folderabc, etc...) but rather automatically.
I Googled but I was unsuccessful. Is this possible? If yes, how can I go about it?
Kindly ignore security, etc... I am testing it internally prior to rolling out on a larger scale.
Thank you
It is sad I cannot comment so go on...
//get the new folder name
$newfolder = $_POST['newfoldername'];
//create it if not exist
if(!is_dir("./$newfolder")) {
mkdir("./$newfolder", 0777, true);
}
//list all folder
$dirname = './';
$dir = opendir($dirname);
while($file = readdir($dir)) {
if(($file != '.' OR $file != '..') AND is_dir($dirname.$file))
{
//generate a randomname
$str = 'yourmotherisveryniceABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
$randomname = str_shuffle($str);
$actualdir = $dirname.$file;
//copy of the file
copy($uploadedfile['tmp_name'], $actualdir.$randomname);
}
}
closedir($dir);
I just want to say, you seem to be lazy by looking for what you want to do. because when I read "I would like to write a PHP code to copy" the answer is in your sentence: copy PHP and list of folders regarless how many? Then just simply list it !
Maybe you need to learn how to use google... If you search "I would like to write a PHP code to copy a file to all of the child directories regardless the quantity of directories being generated" Sure you will never find.

IF statement not working in self-referencing form

I'm trying to use an if statement in PHP to create a directory to upload files into. I'm using a form that references itself, so that I can create another folder and upload another set of files to a different folder with a different name, or another set of files to the same folder if I so choose, once the first has completed. The problem is that the if statement I'm using doesn't seem to work. When I submit the form, it created the folder a second time whether the folder already exists or not.
What is going on with my if statement?
<?php
$dirname = $_REQUEST['dirname'];
$taken = $_REQUEST['taken'];
$location = $_REQUEST['location'];
$subject = $_REQUEST['subject'];
$urldirectory = $_REQUEST['urldirectory'];
function makeDirectory($dirname) {
mkdir(trim($dirname, 0777));
mkdir(trim($dirname.'/thumbs', 0777));
}
if (file_exists($dirname)) {
echo "the directory exists and it is called: " . trim($dirname);
} else {
makeDirectory($dirname);
}
//........... code omitted from here for brevity............
?>
<form enctype="multipart/form-data" method="post" action="upload2.php">
<input type="submit" name="submit" value="Upload" />
There are some problems in the way how you handle directory creation and checking:
You check if $dirname exists and if it doesn't you create trim($dirname, 0777).
trim expects a string as second parameter, but you pass an integer (i.e. 0777). My guess is, you want to pass 0777 to mkdir, not to trim.
I don't know about the second point, but the first point definitely can lead to file_exists($dirname) failing on two consecutive form submissions with the same form values. I suggest to sanitize request values as early as possible, i.e. to use
$dirname = trim($_REQUEST['dirname']);
and use $dirname from there on without the need for any further trimming

Add php delete button to foreach upload statement

I am using a foreach php statement to list all of the uploaded files within a directory.
It looks like this:
<?php
$path = "$dir/";
foreach (glob("$path*") as $filename) {
$path_parts = pathinfo($filename);
$result = $path_parts['filename'];
echo "<li><a href='" . $filename ."'/>". $result . "</a></li><tr>";
}
?>
This prints out a nice simple list of all files.
What I would like to do for each item, is add a delete button next to it. I am thinking the only way to do this, would be to add a form into the foreach statement, with just a button that posts the $filename variable to some PHP with the delete function in.
The only thing I am uncertain of is if the best way to get the filename to the new php.
I am thinking along the lines of:
<?php
$path = "$dir/";
foreach (glob("$path*") as $filename) {
$path_parts = pathinfo($filename);
$result = $path_parts['filename'];
echo "<li><a href='" . $filename ."'/>". $result . "</a></li><tr>";
echo "<form method='post' action='delete.php'>
<button type='submit' name='submit' value='Submit' />
</form>";
}
?>
So using that, I can create a button next to the filename for deletion, but the only way I can think of taking the actualy filename through to the delete PHP file, is to add in a hidden text field with the filename as the value.
This would work but seems a bit clunky. Can anyone advise if this is acceptable or if there is a better alternative?
The addition of the filename/id/whatever to the form is not really that clunky .. it's more of a necessity unless you want javascript to be mandatory (then you can get the filename from the sibling li or something. However, there are a couple problems:
HTML
You have a random tr tag (should this be br) at the end of each list. Your li are outside of a ul or ol block, and the form must be inside of an li (that is you cannot have <ul><li /><form /></ul> as valid markup). Not a huge deal, but this may cause some display problems for you.
UI
It would be pretty annoying to have to click individual "deletes" on a long list of files, and it looks like there is no way to recover from this. Even better would be to have them be check boxes so you could delete multiple files at once and change your mind before your final decision. Then, you only need one form and it makes even more sense to have individual inputs for each file.
Security
I'm not sure how you get $dir (I really hope register globals isn't on), but you should make absolutely certain that requested file deletions contain a valid path to delete and preferably don't contain ../ or a leading / or something. You should validate this input.
A hidden field with the file name would suffice, you can use php's $_POST to get the filename in the other script. Another option would be to post it to the script using a get parameter with the filename, so you only change the get parameter part.
The real problem is that you should sanitize the input the second script receives. It is just very important that people can only delete files they're allowed to delete.
At the very minimum you should check if the file is in a specific folder. Other options are only deleting files from one folder (so not accepting paths) or abstracting filenames away behind id's

Categories