I am currently using mt_rand to display a random file from the specified folder each time the page is loaded.
After doing lots of searching i think i need to create an array and then shuffle the array, but not sure how to go about this.
Most of the examples i have found use an array and then echo the results where as i'm trying to include the result.
<?php
$fict = glob("spelling/*.php");
$fictional = $fict[mt_rand(0, count($fict) -1)];
include ($fictional);
?>
You can use session cookies to hold a random, non-repeating list of files. Actually, for security, the session cookie should only store a list of indices into an array of files.
For example, suppose we have the following file list in an array:
index file
----------------------------
0 spelling/file1.txt
1 spelling/file2.txt
2 spelling/file3.txt
3 spelling/file4.txt
We can create an array of the indices, e.g. array(0,1,2,3), shuffle them to get something like array(3,2,0,1), and store that list in the cookie. Then, as we progress through this random list of indices, we get the sequence:
spelling/file4.txt
spelling/file3.txt
spelling/file1.txt
spelling/file2.txt
The cookie also stores the current position in this list of indices and when it reaches the end, we reshuffle and start over.
I realize all this may sound a bit confusing so maybe this gorgeous diagram will help:
… or maybe some code:
<?php
$fictional = glob("spelling/*.php"); // list of files
$max_index = count($fictional) - 1;
$indices = range( 0, $max_index ); // list of indices into list of files
session_start();
if (!isset($_SESSION['indices']) || !isset($_SESSION['current'])) {
shuffle($indices);
$_SESSION['indices'] = serialize($indices);
$_SESSION['current'] = 0; // keep track of which index we're on
} else {
$_SESSION['current']++; // increment through the list of indices
// on each reload of the page
}
// Get the list of indices from the session cookie
$indices = unserialize($_SESSION['indices']);
// When we reach the end of the list of indices,
// reshuffle and start over.
if ($_SESSION['current'] > $max_index) {
shuffle($indices);
$_SESSION['indices'] = serialize($indices);
$_SESSION['current'] = 0;
}
// Get the current position in the list of indices
$current = $_SESSION['current'];
// Get the index into the list of files
$index = $indices[$current];
// include the pseudo-random, non-repeating file
include( $fictional[$index] );
?>
Related
As the title sais, I'm trying to get the next and previous file from the same directory. So I did some this like this. Is there any better way of doing it? (This is from next auto index file.php code about related files, I have change it for my needs.)
db screenshot if you want to look - ibb.co/wzkDxd3
$title = $file->name; //get the current file name
$in_dir=$file->indir; //current dir id
$r_file = $db->select("SELECT * FROM `". MAI_PREFIX ."files` WHERE `indir`='$in_dir'"); //all of the file from the current dir
$rcount=count($r_file);
$related='';
if($rcount > 2){
$i = 0; // temp variable
foreach($r_file as $key => $r){ //foreach the array to get the key
if($r->name == $title){ //Trying to get the current file key number
$next =$key+1; //Getting next and prev file key number
$prv =$key-1;
foreach($r_file as $keyy => $e){ //getting the file list again to get the prev file
if($prv == $keyy){
$related .=$e->name;
}
}
foreach($r_file as $keyy => $e){ // same for the next file
if($next == $keyy){
$related .=$e->name;
}
}
}
}
Without knowing your DB background and use case, there still should be the possibility to use something like $r_file[$key], $r_file[$next] and $r_file[$prev] to directly access the specific elements. So at least two of your foreach loops could be avoided.
Please note, that nesting loops is extremely inefficient. E. g., if your $r_file contains 100 elements, this would mean 10.000 iterations (100 times 100) with your original code!
Also, you should leave a loop as soon as possible once its task is done. You can use break to do this.
Example, based on the relevant part of your code and how I understand it is supposed to work:
foreach($r_file as $key => $r){ //foreach the array to get the key
if($r->name == $title) { //Trying to get the current file key number
$next =$key+1; //Getting next and prev file key number
$prv =$key-1;
$related .= $r_file[$prv]->name; //Directly accessing the previous file
$related .= $r_file[$next]->name; //Directly accessing the next file
break; // Don't go on with the rest of the elements, if we're already done
}
}
Possibly, looping through all the elements to compare $r->name == $title could also be avoided by using some numbering mechanisms, but without knowing your system better, I can't tell anything more about that.
I searched all day on this forum but couldn't find any answer.
I use following php code to display the next line from myfile.txt on each pageload (looping when gone through entire file):
<?php
session_start();
$item = file("myfile.txt");
$itemCount = count($item);
if ($_SESSION['sess_row'] === NULL) {
$_SESSION['sess_row'] = 0;
} else {
$_SESSION['sess_row'] = ($_SESSION['sess_row'] + 1) % $itemCount;
}
echo $item[$_SESSION['sess_row']];
?>
Now I want to shuffle the lines in myfile.txt before each session.
For example, if myfile.txt contains 5 lines, it now displays lines in same order every session: 123451234512345...
With shuffle it should display one session: 325413254132541..., another session: 413254132541325..., another session: 142351423514235..., and so on.
How can above code be changed to shuffle myfile.txt before each session?
Use shuffle to shuffle your array each time.
$item = file("myfile.txt");
shuffle($item);
If you need to have different number for each user, you should have a database or something (it could be just a single file containing one number) to keep track of how many of your items are already assigned to users. Each time, read that number (call it cursor), assign the number associated with that cursor, increment the cursor by one and write it back to the file (or database ...)
If you need unique data, you can use array_unique:
$item = file("myfile.txt");
$item = array_unique($items);
shuffle($item);
I am successfully able to get random images from my 'uploads' directory with my code but the issue is that it has multiple images repeat. I will reload the page and the same image will show 2 - 15 times without changing. I thought about setting a cookie for the previous image but the execution of how to do this is frying my brain. I'll post what I have here, any help would be great.
$files = glob($dir . '/*.*');
$file = array_rand($files);
$filename = $files[$file];
$search = array_search($_COOKIE['prev'], $files);
if ($_COOKIE['prev'] == $filename) {
unset($files[$search]);
$filename = $files[$file];
setcookie('prev', $filename);
}
Similar to slicks answer, but a little more simple on the session front:
Instead of using array_rand to randomise the array, you can use a custom process that reorders based on just a rand:
$files = array_values(glob($dir . '/*.*'));
$randomFiles = array();
while(count($files) > 0) {
$randomIndex = rand(0, count($files) - 1);
$randomFiles[] = $files[$randomIndex];
unset($files[$randomIndex]);
$files = array_values($files);
}
This is useful because you can seed the rand function, meaning it will always generate the same random numbers. Just add (before you randomise the array):
if($_COOKIE['key']) {
$microtime = $_COOKIE['key'];
else {
$microtime = microtime();
setcookie('key', $microtime);
}
srand($microtime);
This does means that someone can manipulate the order of the images by manipulating the cookie, but if you're okay with that this this should work.
So you want to have no repeats per request? Use session. Best way to avoid repetitions is to have two arrays (buckets). First one will contains all available elements that your will pick from. The second array will be empty for now.
Then start picking items from first array and move them from 1st array to the second. (Remove and array_push to the second). Do this in a loop. On the next iteration first array won't have the element you picked already so you will avoid duplicates.
In general. Move items from a bucket to a bucket and you're done. Additionally you can store your results in session instead of cookies? Server side storage is better for that kind of things.
in "file.txt" i have some numbers like 1234,123456,12345678 etc.
so i was wondering how i can get dynamically just one element, for example echo just 12345,then echo 123456, but one by one ???when user comes i want to show him one element,and then next time i want to show another element on the page, it would be good also if i could erase elements that i have echo...When i manually enter position it works... Please help...
I have a following code:
function test($n){
$file=file_get_contents("file.txt");
$array = explode(",", $file);
return print_r($array[$n]);
};
The solution will need deleting the number on your filesystem or marking it as already showed either on the filesystem or on the database, after the number gets echoed.
Shuffling the numbers or generating a random index will never quite be full proof since the same number could be shown again.
First of all, this is usually a terrible way of doing this.
It's much better to use a database, for example.
But you could do the following:
<?php
function getRandomNumber() {
// retrieve and parse the numbers
$numbers = file_get_contents('file.txt');
$numbers = explode(',' $numbers);
// select a random index
$randomIndex = array_rand($numbers);
// get the chosen number
$randomNumber = $numbers[$randomIndex];
// remove it from array
unset($numbers[$randomIndex]);
// save updated file
file_put_contents('file.txt', implode(',', $numbers));
return $randomNumber;
}
I'd like to,
Check the word count for a folder full of text files.
Output a list of the files arranged by word count in the format - FILENAME is WORDCOUNT
I know str_word_count is used to get individual wordcounts for files but I'm not sure how to rearrange the output.
Thanks in advance.
Adapted from here.
<?php
$files = array();
$it = new DirectoryIterator("/tmp");
$it->rewind();
while ($it->valid()) {
$count = str_word_count(file_get_contents($it->getFilename()));
$files[sprintf("%010d", $count) . $it->getFilename()] =
array($count, $it->getFilename());
$it->next();
}
ksort($files);
foreach ($files as $tup) {
echo sprintf("%s is %d\n", $tup[1], $tup[0]);
}
EDIT It would be more elegant to have $file's key be the file name and $file's value be the word count and then sort by value.
I don't use php but I would
create array to hold filename and
wordcount
read through the folder full of text
files and for each save the filename
and wordcount to the array
sort the array by wordcount
output the array
To store the information (#2) I would put the information into a 2D array. There is more information about 2D arrays here at Free PHP Tutorial. Thus array[0][0] would equal the name of the first file and array0 would be the wordcount. array1[0] and array1 would be the for the next file.
To sort the array (#3) you can use the tutorial firsttube.com.
The to output I would do a loop through the array and output the first and second location.
for ($i = 0; $i < sizeof($array); ++$i) {
print the filename ($array[$i][0]) and wordcount ($array[$i][1])
}
If you would like to keep the iterator-style approach (yet still do essentially the same as Artefacto's answer) then something like the following would suffice.
$dir_it = new FilesystemIterator("/tmp");
// Build array iterator with word counts
$arr_it = new ArrayIterator();
foreach ($dir_it as $fileinfo) {
// Skip non-files
if ( ! $fileinfo->isFile()) continue;
$fileinfo->word_count = str_word_count(file_get_contents($fileinfo->getPathname()));
$arr_it->append($fileinfo);
}
// Sort by word count descending
$arr_it->uasort(function($a, $b){
return $b->word_count - $a->word_count;
});
// Display sorted files and their word counts
foreach ($arr_it as $fileinfo) {
printf("%10d %s\n", $fileinfo->word_count, $fileinfo->getFilename());
}
Aside: If the files are particularly large (read: loading each one entirely into memory just to count the words is too much) then you could loop over the file line-by-line (or byte-by-byte if you really wanted to) with the SplFileObject.