Seleccione un archivo aleatorio usando OPENDIR()

Yo he tratado:

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?

preguntado el 25 de agosto de 12 a las 06:08

And... what's wrong with using glob()? Also, in order to use the ...dir() functions, you need to use the scandir() función en este caso. -

Okay? Except you're using it for the wrong thing... -

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 y glob on the same task because that's like comparing apples to smallpox. They aren't the same. -

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

2 Respuestas

El 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() como el siguiente:

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

Respondido 14 Jul 16, 21:07

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. - nórdico

What do you mean benchmark results reveal me wrong... That makes no sense. You can't use opendir() here. Your options are scandir() y 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(), pero opendir() still doesn't return the array of files... - Jeremy

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

@Norse: Guess what? Messing up faster is still just messing up. Performance comparisons mean precisely nada 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

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

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;
}

Úselo tan simple como:
//  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;
}

Úselo tan simple como:
//  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.

linea sola

/** 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.
Usar scandir had very little if any difference in benchmarks (from -.001 to +.003)
Usar glob was quite noticeably slower! Anywhere from +.5 to +1.100 difference on each call.

Respondido 16 Jul 16, 21:07

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

@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

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.