Select random file using OPENDIR()
Asked Answered
B

2

-4

I have tried:

function random_pic($dir = '../myfolder') {
    $files = opendir($dir . '/*.*');
    $file = array_rand($files);
    return $files[$file];
}

This function works using glob() but not opendir.

This returns a failed to open directory error. I guess opendir cannot accept things like *.*? Is it possible to select all files in a folder and randomly choose one?

Burnight answered 25/8, 2012 at 5:2 Comment(4)
And... what's wrong with using glob()? Also, in order to use the ...dir() functions, you need to use the scandir() function in this case.Axle
Okay? Except you're using it for the wrong thing...Axle
opendir makes no sense in your code. It returns a resource, as per the relevant manual entry. You're calling array_rand on it. Obviously, that won't work because a resource is not an array. I somehow doubt you "benchmarked" the difference between opendir and glob on the same task because that's like comparing apples to smallpox. They aren't the same.Ecumenism
upvote for apples to smallpox comparison. opendir is probably not going to be faster, but it may be slightly more memory efficient since you wouldn't have to generate the whole array.Margalo
A
4

The opendir() function wont return a list of files/folders. It will only open a handle that can be used by closedir(), readdir() or rewinddir(). The correct usage here would be glob(), but as I see that you don't want that, you could also use scandir() like the following:

<?php
$path = "./";

$files = scandir($path);
shuffle($files);

for($i = 0; ($i < count($files)) && (!is_file($files[$i])); $i++);

echo $files[$i];
?>

I'd happily do the timing to see if this takes longer or if glob() takes longer after you admit that I'm not "wrong."

Axle answered 25/8, 2012 at 5:26 Comment(5)
As happy that I am that you seek my admittance of whether I deem you right or wrong, benchmark results reveal you to be wrong. Thanks for your input.Burnight
What do you mean benchmark results reveal me wrong... That makes no sense. You can't use opendir() here. Your options are scandir() and glob(). Before I continue to proceed, is that what we're arguing about (just so I know). Do you think opendir() is useable here? The other alternative is readdir() which would use the handle created by opendir(), but opendir() still doesn't return the array of files...Axle
My first language is english (which it really shouldn't matter if it isnt...). My problem was that what you've said had no relevance to what I'm trying to explain to you. You've also ignored what I asked, could you explain please?Axle
@Norse: Guess what? Messing up faster is still just messing up. Performance comparisons mean precisely nothing unless both programs work correctly. And since yours obviously doesn't, any comparison is meaningless. It doesn't matter how long it takes to do the wrong thing.Lacteal
I did downvote, as I didn't feel this answered the question, nor did it help me when I had the same question. I don't really care about quarrel you and op had, I simply want the best answer. I modified my answer to attempt to show more results after spending a few hours on these methods today, simply to test out what would work best. In the end, I like opendir and as noted, had little difference from scandir. Have a great weekend.Midyear
M
0

The following 2 methods make use of opendir to quickly read through a directory and return a random file or directory.


  • All Benchmarks done use CI3 and are average of 100 pulses.
    Using WAMP on Win10 Intel i54460 w/ 16GB RAM

Get Random File:

function getRandomFile($path, $type=NULL, $contents=TRUE) {
    if (strpos($path, $_SERVER['DOCUMENT_ROOT']) === FALSE) $path = $_SERVER['DOCUMENT_ROOT'] . '/' . $path;
    if (is_dir($path)) {
        if ($dh = opendir($path)) {
            $arr = [];
            while (false !== ($file = readdir($dh))) {
                //  not a directory
                if (!is_dir("$path/$file") && !preg_match('/^\.{1,2}$/', $file)) {
                    //  fits file type
                    if(is_null($type)) $arr[] = $file;
                    elseif (is_string($type) && preg_match("/\.($type)$/", $file)) $arr[] = $file;
                    elseif (is_array($type)) {
                        $type = implode('|', $type);
                        if (preg_match("/\.($type)$/", $file)) $arr[] = $file;
                    }
                }
            }
            closedir($dh);
            if (!empty($arr)) {
                shuffle($arr);
                $file = $arr[mt_rand(0, count($arr)-1)];
                return empty($contents) ? $file : ($contents == 'path' ? "$path/$file" : file_get_contents($file));
            }
        }
    }
    return NULL;
}

Use as simple as:
//  Benchmark 0.0018 seconds *
$this->getRandomFile('directoryName');
//  would pull random contents of file from given directory

//  Benchmark 0.0017 seconds *
$this->getRandomFile('directoryName', 'php');
//  |OR|
$this->getRandomFile('directoryName', ['php', 'htm']);
//  one gets a random php file 
//  OR gets random php OR htm file contents

//  Benchmark 0.0018 seconds *
$this->getRandomFile('directoryName', NULL, FALSE);
//  returns random file name

//  Benchmark 0.0019 seconds *
$this->getRandomFile('directoryName', NULL, 'path');
//  returns random full file path

Get Random Directory:

function getRandomDir($path, $full=TRUE, $indexOf=NULL) {
    if (strpos($path, $_SERVER['DOCUMENT_ROOT']) === FALSE) $path = $_SERVER['DOCUMENT_ROOT'] . '/' . $path;
    if (is_dir($path)) {
        if ($dh = opendir($path)) {
            $arr = [];
            while (false !== ($dir = readdir($dh))) {
                if (is_dir("$path/$dir") && !preg_match('/^\.{1,2}$/', $dir)) {
                    if(is_null($indexOf)) $arr[] = $file;
                    if (is_string($indexOf) && strpos($dir, $indexOf) !== FALSE) $arr[] = $dir;
                    elseif (is_array($indexOf)) {
                        $indexOf = implode('|', $indexOf);
                        if (preg_match("/$indexOf/", $dir)) $arr[] = $dir;
                    }
                }
            }
            closedir($dh);
            if (!empty($arr)) {
                shuffle($arr);
                $dir = $arr[mt_rand(0, count($arr)-1)];
                return $full ? "$path/$dir" : $dir;
            }
        }
    }
    return NULL;
}

Use as simple as:
//  Benchmark 0.0013 seconds *
$this->getRandomDir('parentDirectoryName');
//  returns random full directory path of dirs found in given directory

//  Benchmark 0.0015 seconds *
$this->getRandomDir('parentDirectoryName', FALSE);
//  returns random directory name

//  Benchmark 0.0015 seconds *
$this->getRandomDir('parentDirectoryName', FALSE, 'dirNameContains');
//  returns random directory name

Use in Combo Like:

$dir = $this->getRandomDir('dirName');
$file = $this->getRandomFile($dir, 'mp3', FALSE);
//  returns a random mp3 file name. 
//  Could be used to load random song via ajax.

single line

/** getRandomFile(String)
 *  Simple method for retrieving a random file from a directory
 **/
function getRandomFile($path, $type=NULL, $contents=TRUE) { if (strpos($path, $_SERVER['DOCUMENT_ROOT']) === FALSE) $path = $_SERVER['DOCUMENT_ROOT'] . '/' . $path; if (is_dir($path)) { if ($dh = opendir($path)) { $arr = []; while (false !== ($file = readdir($dh))) { if (!is_dir("$path/$file") && !preg_match('/^\.{1,2}$/', $file)) { if(is_null($type)) $arr[] = $file; elseif (is_string($type) && preg_match("/\.($type)$/", $file)) $arr[] = $file; elseif (is_array($type)) { $type = implode('|', $type); if (preg_match("/\.($type)$/", $file)) $arr[] = $file; } } } closedir($dh); if (!empty($arr)) { shuffle($arr); $file = $arr[mt_rand(0, count($arr)-1)]; return empty($contents) ? $file : ($contents == 'path' ? "$path/$file" : file_get_contents($file)); } } } return NULL; }

/** getRandomDir(String)
 *  Simple method for retrieving a random directory
 **/
function getRandomDir($path, $full=TRUE, $indexOf=NULL) { if (strpos($path, $_SERVER['DOCUMENT_ROOT']) === FALSE) $path = $_SERVER['DOCUMENT_ROOT'] . '/' . $path; if (is_dir($path)) { if ($dh = opendir($path)) { $arr = []; while (false !== ($dir = readdir($dh))) { if (is_dir("$path/$dir") && !preg_match('/^\.{1,2}$/', $dir)) { if(is_null($indexOf)) $arr[] = $file; if (is_string($indexOf) && strpos($dir, $indexOf) !== FALSE) $arr[] = $dir; elseif (is_array($indexOf)) { $indexOf = implode('|', $indexOf); if (preg_match("/$indexOf/", $dir)) $arr[] = $dir; } } } closedir($dh); if (!empty($arr)) { shuffle($arr); $dir = $arr[mt_rand(0, count($arr)-1)]; return $full ? "$path/$dir" : $dir; } } } return NULL; }

/*  This is only here to make copying easier.   */

Just a Note about glob && scandir.
I made alternate versions of the getRandomDir using each.
Using scandir had very little if any difference in benchmarks (from -.001 to +.003)
Using glob was quite noticeably slower! Anywhere from +.5 to +1.100 difference on each call.

Midyear answered 13/7, 2016 at 21:25 Comment(2)
..assuming you dv'd me? why? also this answer is deceptive in that opendir isn't really the function which is selecting the random fileAxle
@Jeremy Nothing deceptive about it. It does as OP asked and as I was seeking to do. It DOES use opendir, as is intended by opendir. Your answer simply does not. opendir is meant to open a directory for reading then use readdir for info needed, then close and go. It's really quite simple and benchmarks quite nicely. Sorry your old answer didn't reach a correct conclusion for this question and certainly didn't help me when seeking this answer.Midyear

© 2022 - 2024 — McMap. All rights reserved.