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]));
Related
I have my folder /images (with ~ 95.000 files), and i check every file if is in the database.
Table : images
Row : hash
The folder containt all my image with sha1 name.
I use shuffle($images); to make sure the verification is random, otherwise it only verifies the first 35,000 images.
If I go over 35,000 checks, the script puts a timeout and the page blocks it.
Example name of an image : d0a0bb3149bea2335e8784812fef706ad0a13156.jpg
My Script :
I select the images in the database
I'm putting it in a array
I make the array random (to avoid always checking the first 35,000
images)
I create a array of images file in the folder /images
I check for missing database files using the array created by the
opendir(); function
I display the answer
<?php
set_time_limit(0);
$images = [];
$q = $mysqli->query('SELECT hash FROM images');
while($r = $q->fetch_assoc())
{
$images[] = $r['hash'].'.jpg';
}
shuffle($images);
$i_hors_bdd = 0;
$images_existent_hors_bdd = [];
if($dh = opendir($_SERVER['DOCUMENT_ROOT'].'/images'))
{
while(($file = readdir($dh)) !== false)
{
if(!in_array($file, $fichiers_a_exclures))
{
if(!is_sha1($file) OR !in_array($file, $images))
$images_existent_hors_bdd[] = '<p>Name of File: '.$file.'</p>';
}
if($i_hors_bdd > 35000)
{
break;
}
$i_hors_bdd++;
}
}
closedir($dh);
if(count($images_existent_hors_bdd) > 0)
{
echo '<p>Image exist, but not in the databse.</p>';
sort($images_existent_hors_bdd);
foreach($images_existent_hors_bdd as $image_existe_hors_bdd)
echo $image_existe_hors_bdd;
}
else
echo '<p>All images are in datase.</p>';
echo '<p>'.$i_hors_bdd.' images checked.</p>';
So my question is: How can I optimize this script to improve the speed of the script to allow checking more images without blocking the script? Knowing that my VPS is not very powerful and I don't have SSD.
Here are some things to consider or try:
Concatenate '.jpg' to hash in the sql, then use fetch_all into a numeric array.
use scandir to build an array of files in the directory
use array_diff to remove $fichiers_a_exclures and $images
iterate over this smallest array to do the sha1 test
So I have a URL which contains &title=blabla
I know how to extract the title, and return it. But I've been searching my ass off to get the full path to the filename when I only have the filename.
So what I must have is an way to search in all directories for an html file called 'blabla' when the only thing it has is blabla. After finding it, it must return the full path.
Anyone who does have an solution for me?
<?php
$file = $_GET['title'];
if ($title = '') {
echo "information.html";
} else {
//here it must search for the filepath and echo it.
echo "$filepath";
}
?>
You can use the solution provided here.
It allows you to recurse through a directory and list all files in the directory and sub-directories. You can then compare to see if it matches the files you are looking for.
$root = '/'; // directory from where to start search
$toSearch = 'file.blah'; // basename of the file you wish to search
$it = new RecursiveDirectoryIterator($root);
foreach(new RecursiveIteratorIterator($it) as $file){
if($file->getBasename() === $toSearch){
printf("Found it! It's %s", $file->getRealPath());
// stop at the first match
break;
}
}
Keep in mind that depending on the number of files you have, this can be slow as hell
For a start this line is at fault
if ($title = '') {
See http://www.php.net/manual/en/reserved.variables.files.php
I have created my own l($text) function in php for a multi lingual website. i use it like this in my documents :
echo '<h1>' . l('Title of the page') . '</h1';
echo '<p>' . l('Some text here...') . '</p>';
My question is, with a php script, how can i scan all my .php files to catch all this function usages and list all the arguments used into a mysql table?
the goal, of course, is to not forget any sentences in my traduction files.
I didn't find anything on google or here, so if you have any ideas, or need some more information.
Could you:
read all *.php files with glob()
then use a regex to pull the strings out (preg_match())
strings simple mysql insert?
Seems simple enough?
i just finished, your help was usefull ! :-)
here is my ugly code for those who can be interested. it's not beautifuly coded, but not made to be loaded 10000 times per day so...
<?php
// define a plain text document to see what appen on test
header('Content-Type: text/plain; charset=UTF-8');
$dossier = 'pages/'; // folder to scan
$array_exclude = array('.', '..', '.DS_Store'); // system files to exclude
$array_sentences_list = array();
if(is_dir($dossier)) // verify if is a folder
{
if($dh = opendir($dossier)) // open folder
{
while(($file = readdir($dh)) !== false) // scan all files in the folder
{
if(!in_array($file, $array_exclude)) // exclude system files previously listed in array
{
echo "\n".'######## ' . strtoupper($file) . ' ##########'."\n";
$file1 = file('pages/'.$file); // path to the current file
foreach($file1 AS $fileline)
{
// regex : not start with a to z characters or a (
// then catch sentences into l(' and ')
// and put results in a $matchs array
preg_match_all("#[^a-z\(]l\('(.+)'\)#U", $fileline, $matchs);
// fetch the associative array
foreach($matchs AS $match_this)
{
foreach($match_this AS $line)
{
// technique of "I do not want to break my head"
if(substr($line, 0, 3) != "l('" AND substr($line, 0, 4) != " l('" AND substr($line, 0, 4) != ".l('")
{
// check if the sentence is not already listed
if(!in_array($line, $array_sentences_list))
{
// if not, add it to the sentences list array and write it for fun !
$array_sentences_list[] = $line;
echo $line . "\n";
}
}
}
}
}
}
}
closedir($dh);
}
}
?>
small precision : i do have to escape various cases as :
-> CSS : background: url('image.jpg');
and
-> jQuery : $(this).html('bla bla');
so here is why the regex starts with [^a-z(] :-)
it works very well now! just have to finish later with recording entries in a mysql table and ensure that i can load the script from time to time when there are changes on the site... keep the existing translation, overwrite the existing files etc... no problem with that.
thanks a gain, this website is really helpful ! :-)
I have a double question. Part one: I've pulled a nice list of pdf files from a directory and have appended a file called download.php to the "href" link so the pdf files don't try to open as a web page (they do save/save as instead). Trouble is I need to order the pdf files/links by date created. I've tried lots of variations but nothing seems to work! Script below. I'd also like to get rid of the "." and ".." directory dots! Any ideas on how to achieve all of that. Individually, these problems have been solved before, but not with my appended download.php scenario :)
<?php
$dir="../uploads2"; // Directory where files are stored
if ($dir_list = opendir($dir))
{
while(($filename = readdir($dir_list)) !== false)
{
?>
<p><a href="http://www.duncton.org/download.php?file=login/uploads2/<?php echo $filename; ?>"><?php echo $filename;
?></a></p>
<?php
}
closedir($dir_list);
}
?>
While you can filter them out*, the . and .. handles always come first. So you could just cut them away. In particular if you use the simpler scandir() method:
foreach (array_slice(scandir($dir), 2) as $filename) {
One could also use glob("dir/*") which skips dotfiles implicitly. As it returns the full path sorting by ctime then becomes easier as well:
$files = glob("dir/*");
// make filename->ctime mapping
$files = array_combine($files, array_map("filectime", $files));
// sorts filename list
arsort($files);
$files = array_keys($files);
Instead of the traditional navigation, I am trying to emulate the terminal navigation, or how you navigate with vim.
Example:
..
index
otherfile
This is my code:
$dir = realpath(dirname(__FILE__));
if(is_dir($dir)){
if($open = opendir($dir)){
while(($file = readdir($open)) !==false){
if(is_dir($file)){
if($file == '.'){ }
else{
echo "".$file."<br/>";
}
}
else{
$name = explode('.php',$file);
echo "".$name[0]."<br/>";
}
}
}
}
else{
echo $dir." Was not found";
}
}
How can I remove the file or folder I am in from the list? For example, if I am on the page index.php, it is still appearing on the list.
I want to sort files by given them a number example '1file.php' '2anotherfile.php'..
How could I sort them by the number, then remove the number and '.php', and finally print it out?
If you feel like refactoring something please do so...
"How can I remove the file or folder I am in from the list? For example, if I am on the page index.php, it is still appearing on the list."
Just check if the current item is the current file, if it is then skip it:
else {
if ($name == basename(dirname(__FILE__))) continue; // if this is the current file, go to the next iteration of the loop
$name = explode('.php',$file);
echo "".$name[0]."<br/>";
}
Note that this assumes you are in the same directory as the file (which it can do because $dir is always the directory the script is in), if not you can just add a directory check as well.
"How can add a number to the start of the file or folder, example 1index.php, then on the code, organize all the files and folder by number, and print them without the number and '.php'?"
Well I'm not too sure what you mean by this, but if you mean sort alphabetically, then it is already alphabetically sorted when you get the list.