dirname() X amount of times on path of file PHP - php

I need to do a dirname() on a file path multiple times to exclude sub-folders, so like this:
dirname(dirname(dirname(__FILE__)));
The amount of times I need to do this on a file path is completely dynamic (not fixed) so I need to somehow do it variable $x amount of times...
I could do this:
$x=6;//amount of sub-folders involved in the path
if($x==1){dirname(__FILE__);}
elseif($x==2){dirname(dirname(__FILE__));}
elseif($x==3){dirname(dirname(dirname(__FILE__)));}
elseif($x==4){dirname(dirname(dirname(dirname(__FILE__))));}//and so on.....
But thats not exactly a professional way of going about it, and it will never be reliable (if $x=9999999....).
Does anyone know how I'd go about doing this??

You need to invoke the dirname function $x times, that's called a loop:
$x=6; //amount of sub-folders involved in the path
$dir = dirname(__FILE__);
while(max(0, --$x)) {
$dir = dirname($dir);
}

Recursion is the answer my friend!
function go_up_x_times($path, $x) {
if ($x <= 0) {
return $path; // we're done, yay!
}
return dirname(go_up_x_times($path, $x - 1));
}
go_up_x_times(__FILE__, 5);

Related

Name each new dir with the next available number with php

I'm working on a php file where I want to create one or more directories with names ranging from 1 to 999 or more. I'm creating the first of all directories using the following code:
<?php
$id = '001';
mkdir($id)
?>
What I want to succeed is to automatically create a new directory using as a name the next available number (i.e. 002, 003, 004, 005 etc) either as a string or an integer. However, I really stuck and I try to use:
<?php
$id = 001;
if (file_exists($id)) {
$id = $id + 1;
mkdir($id);
}
?>
..but it doesn't work. Any ideas?
I forgot to mention that the above code is part of the if statement inside the same php code.
Several ways to do this, depending on your use case. This function may work for you:
<?PHP
function makedir($id){
if(file_exists($id)){
$id++;
makedir($id);
}else{
mkdir($id);
return true;
}
}
makedir(1);
This solution of incremented directory names is going to become ugly after a while though; you should probably find a better solution to your problem.
You could do something like this:
// Loop through all numbers.
for ($i = 1; $i <= 999; $i++) {
// Get the formatted dir name (prepending 0s)
$dir = sprintf('%03d', $i);
// If the dir doesn't exist, create it.
if (!file_exists($dir)) {
mkdir($dir);
}
}
Edit: the above was assuming you wanted to make all 999 directories. You could do the following to just append the next available number:
function createDir($dir) {
$newDir = $dir;
$num = 1;
while (file_exists($newDir)) {
$newDir = $dir.sprintf('%03d', $num++);
}
return $newDir;
}

PHP cant calculate directory

I got a small problem with my PHP webpage. I want to calculate the size of a directory, but I got 2 folders in them, that I don't want to include in the final size. I use following:
function foldersize($directory){
$size = 0;
foreach (glob(rtrim($directory, '/').'/*', GLOB_NOSORT) as $each) {
$size += is_file($each) ? filesize($each) : foldersize($each);
}
return $size;
}
$home_directory = "./files/" . $user_data['unique_id'] . "/";
$dir = foldersize($home_directory);
$dirdel = foldersize($home_directory . "del/");
$dirtmp = foldersize($$home_directory . "tmp/");
$userspace = $dir - $dirdel - $dirtmp;
When I test, which variable the server is able to return I get following result: The server is able to calculate $dir, but it seems to have problems with calculating $dirdel and $dirtmp. So it returns 0. Both folders, however, have files in them. I hope anybody can help me with that. Thank you
i have tried your code and I think is OK - except one small mistake,
$dirtmp = foldersize($$home_directory . "tmp/"); ... there is typo, double dollar, $$home_directory ... other results from function are fine I think

glob() function only returns empty array in php

I've been trying to make a simple website that lets you specify a directory, and embeds a player for each mp3 in whatever directory the user specifies. The problem is that no matter how I enter the directory name, glob() does not return any files. I've tried this with local folders, server directories, and the same folder as the php file.
'directoryPath' is the name of the text box where the user enters, you guessed it, the directory path. The 'echo $files' statement displays nothing onscreen. The 'echo "test"' statement DOES run, but the 'echo "hello"' statement in the loop does not execute.
Any help is appreciated!
if (!empty($_POST['directoryPath']))
{
$path = ($_POST['directoryPath']);
$files = glob("$path/{*.mp3}", GLOB_BRACE);
echo $files[0];
echo "test";
foreach($files as $i)
{
echo "hello";
echo $files[$i];
?>
<embed src=<?php $files[$i]; ?> width=256 height=32 autostart=false repeat=false loop=false></embed><?php echo $files[$i] ?></p>
<?php;
}
unset($i);
}
Validate the input first:
$path = realpath($_POST['directoryPath']);
if (!is_dir($path)) {
throw new Exception('Invalid path.');
}
...
Additionally check the return value glob returns false on error. Check for that condition (and ensure you are not using one of those systems that even return false when there are no files found).
I hope this is helpful. And yes, check your error log and enable error logging. This is how you can see what is going wrong.
Also see the following related function for a usage-example and syntax of GLOB_BRACE:
Running glob() from an included script returns empty array
One one tool I find very useful in helping debug variables in PHP is var_dump(). It's a function that provides you with information about a variable's type, it's contents, and any useful metadata it can attain from that variable. This would be a very useful tool for you here, because you'll quickly realize what you have in the variable $i is not at all what you expect.
$files = glob("$path/{*.mp3}", GLOB_BRACE);
foreach ($files as $i) {
var_dump($i);
}
/* Here's a hint, $i is not an index to the $files array.
So $files[$i] makes no sense. $i is actually the value not the key.*/
foreach ($files as $key => $value) { // very different from
// $key is the key to the current element of $files we're iterating over
// $value is the value of the current element we're iterating over
}
So in your code $i is the value not the key. See http://php.net/foreach for more information on how the construct works.
Also, what should be noted here is that you are using a relative path, whereas glob will return an absolute path. By relative this means your searching relative to the CWD (Current Working Directory) of your PHP script. To see wha that is you can use the following code.
var_dump(real_path('.'));
// similarly ...
var_dump(getcwd());

Discovering folder tree via depth-first or breadth-first

I had to find the paths to the "deepest" folders in a folder. For this I implemented two algorithms, and one is way faster than the other.
Does anyone know why ? I suppose this has some link with the hard-disk hardware but I'd like to understand.
Here is the fast one :
private function getHostAux($path) {
$matches = array();
$folder = rtrim($path, DIRECTORY_SEPARATOR);
$moreFolders = glob($folder.DIRECTORY_SEPARATOR.'*', GLOB_ONLYDIR);
if (count($moreFolders) == 0) {
$matches[] = $folder;
} else {
foreach ($moreFolders as $fd) {
$arr = $this->getHostAux($fd);
$matches = array_merge($matches, $arr);
}
}
return $matches;
}
And here is the slow-one :
/**
* Breadth-first function using glob
*/
private function getHostAux($path) {
$matches = array();
$folders = array(rtrim($path, DIRECTORY_SEPARATOR));
$i = 0;
while($folder = array_shift($folders)) {
$moreFolders = glob($folder.DIRECTORY_SEPARATOR.'*', GLOB_ONLYDIR);
if (count($moreFolders == 0)) {
$matches[$i] = $folder;
}
$folders = array_merge($folders, $moreFolders);
$i++;
}
return $matches;
}
Thanks !
You haven't provided additional informations that might be crucial for understanding these "timings" which you observed. (I intentionally wrote the quotes since you haven't specified what "slow" and "fast" mean and how exactly did you measure it.)
Assuming that the supplied informations are true and that the speedup for the first method is greater than a couple of percent and you've tested it on directories of various sizes and depth...
First I would like to comment on the supplied answers:
I wouldn't be so sure about your answer. First I think you mean "kernel handles". But this is not true since glob doesn't open handles. How did you come up with this answer?
Both versions have the same total iteration count.
And add something from myself:
I would suspect array_shift() may cause the slowdown because it reindexes the whole array each time you call it.
The order in which you glob may matter depending on the underlying OS and file system.
You have a bug (probably) in your code. You increment $i after every glob and not after adding an element to the $matches array. That causes that the $matches array is sparse which may cause the merging, shifting or even the adding process to be slower. I don't know exactly if that's the case with PHP but I know several languages in which arrays have these properties which are sometimes hard to keep in mind while coding. I would recommend fixing this, timing the code again and seeing if that makes any difference.
I think that your first algorithm with recursion does less iterations than the second one. Try to watch how many iterations each algorithm does using auxilary variables.

Multiple Random Includes from Directory with Sub-Directories

I have a directory containing sub directories which each contain a series of files. I'm looking for a script that will look inside the sub directories and randomly return a specified number of files.
There are a few scripts that can search a single directories (not sub folders), and other scripts that can search sub folders but only return one file.
To put a little context on the situation, the returned files will be included as li's in an rotating banner.
Thanks in advance for any help, hopefully this is possible.
I think I've got there, not exactly what I set out to achieve but works good enough, arguably better for the purpose, I'm using the following function:
<?php function RandomFile($folder='', $extensions='.*'){
// fix path:
$folder = trim($folder);
$folder = ($folder == '') ? './' : $folder;
// check folder:
if (!is_dir($folder)){ die('invalid folder given!'); }
// create files array
$files = array();
// open directory
if ($dir = #opendir($folder)){
// go trough all files:
while($file = readdir($dir)){
if (!preg_match('/^\.+$/', $file) and
preg_match('/\.('.$extensions.')$/', $file)){
// feed the array:
$files[] = $file;
}
}
// close directory
closedir($dir);
}
else {
die('Could not open the folder "'.$folder.'"');
}
if (count($files) == 0){
die('No files where found :-(');
}
// seed random function:
mt_srand((double)microtime()*1000000);
// get an random index:
$rand = mt_rand(0, count($files)-1);
// check again:
if (!isset($files[$rand])){
die('Array index was not found! very strange!');
}
// return the random file:
return $folder . "/" . $files[$rand];
}
$random1 = RandomFile('project-banners/website-design');
while (!$random2 || $random2 == $random1) {
$random2 = RandomFile('project-banners/logo-design');
}
while (!$random3 || $random3 == $random1 || $random3 == $random2) {
$random3 = RandomFile('project-banners/design-for-print');
}
?>
And echoing the results into the container (in this case the ul):
<?php include($random1) ;?>
<?php include($random2) ;?>
<?php include($random3) ;?>
Thanks to quickshiftin for his help, however it was a little above my skill level.
For info the original script which I changed an be found at:
http://randaclay.com/tips-tools/multiple-random-image-php-script/
Scrubbing the filesystem every single time to randomly select a file to display will be really slow. You should index the directory structure ahead of time. You can do this many ways, try a simple find command or if you really want to use PHP my favorite choice would be RecursiveDirectoryIterator plus RecursiveIteratorIterator.
Put all the results into one file and just read from there when you select a file to display. You can use the line numbers as an index, and the rand function to pick a line and thus a file to display. You might want to consider something more evenly distributed than rand though, you know to keep the advertisers happy :)
EDIT:
Adding a simple real-world example:
// define the location of the portfolio directory
define('PORTFOLIO_ROOT', '/Users/quickshiftin/junk-php');
// and a place where we'll store the index
define('FILE_INDEX', '/tmp/porfolio-map.txt');
// if the index doesn't exist, build it
// (this doesn't take into account changes to the portfolio files)
if(!file_exists(FILE_INDEX))
shell_exec('find ' . PORTFOLIO_ROOT . ' > ' . FILE_INDEX);
// read the index into memory (very slow but easy way to do this)
$aIndex = file(FILE_INDEX);
// randomly select an index
$iIndex = rand(0, count($aIndex) - 1);
// spit out the filename
var_dump(trim($aIndex[$iIndex]));

Categories