directory listing with restrictions - php

I am trying to make a script that lists only folders within a folder. The thing is that I have users who can create folders within their folders so basically what I'm trying to do is to have a way for users to manage their folders and storing files... My problem is that I want to make php "think" that the root folder is their home directory and they cannot go upper than their home directory. Currently my php function doesn't do that, it only shows the content of the directory...and if the user goes one level up and again one level up ...and so on....he could browse the entire hard drive.
function directoryList($path) {
$dirStruct = array();
if(is_dir($path)) {
$handle = opendir($path);
while(($file = readdir($handle)) !== false) {
if(#opendir($path.$file)) {
chdir($path.$file);
$absolutepath = getcwd();
$dirStruct[] = array('path' => $absolutepath.'\\', 'name'=>$file);
}
}
}
return $dirStruct;
}

Instead of giving the user an absolute path, only allow them to specify paths which are relative to a given base path. Next, write a function which removes any "/../" for the relative path and you're safe (as long as users can't create links on the server ...).
If you want to be nice, you can match the ".." with the element before that (so "a/../b" would become "b", i.e. the ".." remove the "a") or ignore the ".." if there is no path element before it.

Here is a little something to expand on:
function listFolders($folderPath, $homeFolder)
{
$folderPath = realpath($folderPath);
$homeFolder = realpath($homeFolder);
if(strpos($folderPath, $homeFolder) === 0) {
return glob("$folderPath/*", GLOB_ONLYDIR);
}
}
$dirs = listFolders('/home/gordon/code/php', '/home/gordon');
print_r($dirs);
For $folderPath you pass in the folder you want to list the directories from. For $homeFolder pass in the folder you want to be the top most folder. By realpathing both paths you make sure they are resolved to absolute paths. If the $folderPath is below the $homeFolder, then the $folderPath string will start with and contain the entire $homeFolder string. If this is the case, we just glob all directories in the $folderPath and return their absolute pathes in an array.
To get the relative path of the $folderPath from the $homeFolder, just do
ltrim(str_replace('/home/gordon/', './', '/home/gordon/code/php/'), '/');
which would return ./code/php/.
If you want to do this with OOP, you might be interested in the SPL DirectoryIterator.

Related

Get full path while opening a directory

I'm creating a script to run through a given folder and list all files inside it.
The problem is: The user may or may not give the full path or just the folder name (if the target folder is inside the script folder).
Is there a way to get the full/absolute path of that folder even if the user gives only its name ?
//Check if the folder path was given as an argument
if( $argc >= 2) {
$folderPath = $argv[1]; //Read the folder path argument
if( !is_dir($folderPath) ) {
echo "Folder does NOT exists !";
}
else {
if( $handle = opendir($folderPath) ) {
//Find the $folderPath absolute path here
$folderPath may be:
- C:\wamp64\www\myfolder\documents
- Or just: documents
either cases the script will find the folder, open it and list it's files. But I need to write the fullPath later on the code.
You may want realpath, which cuts through all the issues - relative paths, symbolic links, etc.

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.

How to select second or third level directory names to style

I am trying to create a directory tree to display for a product page.IT looks thru the main directory and finds the Categories Collections, loose diamonds and tennis bracelets. The collection directory will have quite a few sub directories and those may have some as well. What i am trying to figure out is how to detect/select when the directory that is is being looked at how a subdirectory or sub directories so that i may apply a different style to the directory name. For example I would have the sub directories indented or something.
Below is teh snippet of code that i was able to find on SO. I tried adding a second while just after the filetype line in an attempt to see if i could manually set a sub file variable and look to see if the sub directory has any directories in it. I broke it when i did that:(
$dir = "Images/Categories/";
function recurseDirs($main, $count=0){
$dirHandle = opendir($main);
while($file = readdir($dirHandle)){
if(filetype($main.$file."/")=="dir" && $file != '.' && $file != '..'){
echo "<li>$file</li>";
$count = recurseDirs($main.$file."/",$count); // Correct call and fixed counting
}
}
return $count;
}

How to build a file path correctly by using php?

I have a directory and a dynamic file name. Are there any functions I can use to make sure it is impossible to break out from the specified directory?
for example:
secure_path('/tmp/', 'file.txt') -> /tmp/file.txt
secure_path('/tmp/', '../file.txt') -> /tmp/file.txt
If you're only working in the single directory and not subdirectories below you could do
$file = "/tmp/".basename($input);
Which should give you the filename at the end of any path given in input, and append it to the directory you wanted.
Use realpath() to get a canonic form of the path, and eliminate any ../-s. Then verify that it contains the full path of the directory you want to contain it to.
Such as:
$path = "/tmp/file.txt";
$directory = "{full path of your files directory}";
if (strpos(realpath($path), $directory) === 0) {
// path OK
}
else {
// path not ok
}
I don't really know how ../file.txt is supposed to turn into /tmp/file.txt in your example, but to check whether a path is a subpath of another, use realpath with a simple comparison:
$path = '../foo';
$allowedPath = '/tmp/';
$path = realpath($path);
if (substr($path, 0, strlen($allowedPath)) !== $allowedPath) {
// path is not within allowed path!
}

PHP: moving directories with contents?

I'm having an array $bundle that stores filenames and directory names.
I'm running through the array with a foreach loop and I want to move them inside of another directory. I'm using the rename method therefore and it works pretty fine with JUST FILES.
However directories with other files in there don't respond to the rename() method.
$folder = 'files';
foreach ($bundle as $value) {
$ext = pathinfo($value, PATHINFO_EXTENSION);
if ($ext != "") { //if $value has no suffix it's a fil
rename(PATH . '/' .$value, $folder . '/' . $value);
}
if ($ext == "") { // it's a folder/directory
//rename doesn't work for directories with contents
//what method should i use here???
}
}
I know the pathinfo() method is not the best way to find out if it's a directory or not, however for my little project it's fine. I just need to know how I can move any directory with all it's contents into the "files" folder.
Thank you for your help.
You will have to get all the filenames in that directory using glob or scandir. Then you would have to loop through them with the rename and move them.
Your other option, if you host allows it, is to use shell_exec and do the mv for linux or copy / xcopy for windows command and move them that way. If you choose the exec route, make sure to secure the input etc to prevent any bad stuff from happening.

Categories