-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?

Norse
  • 5,674
  • 16
  • 50
  • 86
  • 1
    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. – jeremy Aug 25 '12 at 05:08
  • 1
    Okay? Except you're using it for the wrong thing... – jeremy Aug 25 '12 at 05:14
  • 4
    `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. –  Aug 25 '12 at 05:34
  • 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. – nneonneo Aug 25 '12 at 05:37

2 Answers2

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."

jeremy
  • 9,965
  • 4
  • 39
  • 59
  • 1
    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. – Norse Aug 25 '12 at 05:30
  • 3
    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... – jeremy Aug 25 '12 at 05:31
  • 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? – jeremy Aug 25 '12 at 05:35
  • 2
    @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. – cHao Aug 25 '12 at 06:04
  • 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. – SpYk3HH Jul 16 '16 at 00:07
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.

SpYk3HH
  • 22,272
  • 11
  • 70
  • 81
  • ..assuming you dv'd me? why? also this answer is deceptive in that opendir isn't really the function which is selecting the random file – jeremy Jul 14 '16 at 20:08
  • @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. – SpYk3HH Jul 15 '16 at 23:46