i have a directory with 1000+ images and piece of code (by codaddict) which selects only first 10 and display it:
<?php
foreach (array_slice(glob("/directory/*.jpg"),0,10) as $path)
?>
ok this works, but i need to select 10 RANDOM images, not the first 10
yes, i can use shuffle first, then slice, but with 1000+ (or 10k+) images, it's not smart to shuffle long arrays just for 10 images, or maybe it is?
also, 2nd problem is that this is not just for one folder with 1000+ images, i need to use this script in other folders too, and some of them will only have 1 image, so i don't want to see errors if there is less than 10 images in a folder
i saw in php manual code for 2 random items, but i won't know how many images will be in folders - 1, 10, 10k... you see the problem
<?php
$input = array("Neo", "Morpheus", "Trinity", "Cypher", "Tank");
$rand_keys = array_rand($input, 2);
echo $input[$rand_keys[0]] . "\n";
echo $input[$rand_keys[1]] . "\n";
?>
thanks!
function imageGlobber($myDir, $imgCount) {
$globVar = glob($myDir."/*.jpg");
$imgCount = ($imgCount > count($globVar)) ? $imgCount : count($globVar);
$randKeys = array_rand($globVar, $imgCount);
$retArray = array();
foreach($randKeys as $key)
array_push($retArray, $globVar[$key]);
return $retArray;
}
I think this is what you are looking for.
Edit : Added duplicate handling as well.
Edit : Improved performance.
Related
I have a really simple code with a problem I can't solve:
$dirname = "some/directory";
$images = glob($dirname."*.{png,jpg,jpeg}", GLOB_BRACE);
sort($images);
foreach($images as $item){
$title = explode('/', trim($item, '/'));
$fourth_segment = $title[3];
$title= str_replace([".jpg", ".jpeg", ".png"], "", $title[3]);
echo '<h3>'.$title.'</h3><br /><img src="'.$item.'" style="width:500px;" /><br /><br />';
}
This sorts my directory and posts its images in an sorted order on my webpage. Problem I have now is, that it is only working up to number 9.
My Directory:
1 01.01.2020.jpg
2 03.04.2020.jpg
[3-8 following]
9 05.06.2020.jpg
10 08.07.2020.jpg
How it is sorted and shown by my code on the webpage:
1 01.01.2020.jpg
10 08.07.2020.jpg
2 03.04.2020.jpg
[3-8 following]
9 05.06.2020.jpg
So its sorting as it should up to Number 9, but I don't get behind why the 10 is following the 1 and how I can solve this.
Does someone have an idea?
best regards
It seem the sort is being done in an Alphabetic way. In Alphabetic sort, it makes sense for the 10 to appear before 9. In the same way it makes sense to "BA" appears before "I" for words sorted alphabetic. (0 = A, 1 = B, I = 9).
According to the documentation, the sort funcion accepts a flag parameter to modify the sorting behaviour. You can try to use the sort function like this:
sort($images, SORT_NATURAL);
I never intended to have to use PHP - heck, two days ago I didn't even know what it was, so excuse me if any of my terminology is weird or incorrect.
My predicament is that I need a working code that will end up outputting a list of writer names (that's why the array is called "writers") that are linked to their writer pages/profiles. Here's what I have so far that correctly displays the list of writer names:
<?php
$writers = get_post_meta($post->ID, 'writer', false);
$last = array_slice($writers, -1);
$first = join(', ', array_slice($writers, 0, -1));
$both = array_filter(array_merge(array($writers), $last), 'strlen');
echo join(' and ', $both);
?>
And the correct writer page link can be generated with this code:
<?php echo get_post_meta($post->ID, 'writerlink', true); ?>
I just don't have the skill to get these puzzle pieces to fit together. Since there are often multiple writers, there will often be more than one writer link. Is it possible to have each list/array value to have its correct link attached?
Take a look at the code
$link = "http://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
echo dirname(dirname($link));
Question 1. Is it elegant to use dirname twice to go two levels up?
Question 2. In case you want to go three levels up, would it be a good practise to use dirname three times?
If you're looking to be more flexible in how many levels up you would like to go, then I would suggest writing a small function to help take care of this for you.
Here's an example piece of code which might do what you would like. Instead of using dirname multiple times or calling a for loop, it uses preg_split, array_slice, and implode, assuming that / is your directory separator.
$string = 'http://example.com/some_folder/another_folder/yet_another/folder/file
.txt';
for ($i = 0; $i < 5; $i++) {
print "$i levels up: " . get_dir_path($string, $i) . "\n";
}
function get_dir_path($path_to_file, $levels_up=0) {
// Remove the http(s) protocol header
$path_to_file = preg_replace('/https?:\/\//', '', $path_to_file);
// Remove the file basename since we only care about path info.
$directory_path = dirname($path_to_file);
$directories = preg_split('/\//', $directory_path);
$levels_to_include = sizeof($directories) - $levels_up;
$directories_to_return = array_slice($directories, 0, $levels_to_include);
return implode($directories_to_return, '/');
}
The result is:
0 levels up: example.com/some_folder/another_folder/yet_another/folder
1 levels up: example.com/some_folder/another_folder/yet_another
2 levels up: example.com/some_folder/another_folder
3 levels up: example.com/some_folder
4 levels up: example.com
Question 1. Is it elegant to use dirname twice to go two levels up?
I don't think it's elegant but at the same time it's probably fine for 2 levels
Question 2. In case you want to go three levels up, would it be a good
practise to use dirname three times?
The more levels you have the less readable it becomes. For a large number of levels I would use a foreach and if it's used often enough then I'd put it inside a function
function multiple_dirname($path, $number_of_levels) {
foreach(range(1, $number_of_levels) as $i) {
$path = dirname($path);
}
return $path;
}
So I am looking to alternate between 5 different variables but want the 'load' to be equal on each variable. I have seen it done with just two variables and alternating based on random number generated withe limits being set. But trying to expand that idea on to five variables. Thanks in advance.
Just for example purposes say I had 5 images and wanted each image to be shown equally after 100 tests. This is the easiest way I can think of explaining it.
This is how I did it with only 2 variables but trying to think about how to do it with more.
$ad1 = '<img src... >';
$ad2 = '<img src...2 >';
echo mt_rand(0, 1) ? $ad1 : $ad2;
Source:PHP Switching between two variables equally without using database
So this is what I have going just want to know what the ideas on equally being between the different variables.
$input = array("a", "b", "c", "d");
$rand_keys = array_rand($input);
echo 'var key ="'.$input[$rand_keys].'"';
Two options below, because your question is titled "swithcing between 5 variables equally" - There is an equal distribution solution and a randomized solution.
Notice you need apc installed for the equal rotation solution to work. It is a fairly common php module and can be installed quite easily if you have permission to do so:
Redhat/centos : yum install php-apc
Ubuntu: sudo apt-get php-apc
If you are using shared hosting and they don't have apc installed then this won't work for you :(
<?php
//If you want perfectly equal distribution.
$variables = array('a', 'b', 'c', 'd', 'e');
if (!($this_var = apc_fetch('last'))) $this_var = 0;
echo $variables[$this_var];
$this_var++;
$this_var = $this_var % 5;
apc_store('last', $this_var);
//If you want random distribution
$variables = array('a', 'b', 'c', 'd', 'e');
$index = mt_rand(0, 4);
echo $variables[$index];
If you want a random pick out of a set you can use array_rand().
$images = array( '<img src="img1.png">', '<img src="img2.png">', '<img src="img3.png">', '<img src="img4.png">', '<img src="img5.png">' );
$pick = array_rand( $images );
$pick will be a random key from the $images array.
This is easily extensible as you can keep adding elements to the array. Here I am of course following your example of adding the <img> tag to the array but you could just as easily add only some identifier to the array.
I would suggest using a Class to handle each "object":
<?php
...
...
class RandObjClass
{
var $myCounter = 1;
var $mySeed = time();
var $myReference = "...path-to-image-file..."; # Image for example
function getWeight() {
srand($mySeed);
$myWeight = $this->myCounter * rand();
return($myWeight);
}
setSeed($xSeed) {
$this->mySeed = $xSeed;
}
}
...
...
Fill an array of x "RandObjClass" objects and use the "getWeight" to select the next one of "highest" weight.
You can play with affecting the weight via various methods, like counting. This can influence which is chosen next.
i need to print out numbers 1-100 in a random order. the print statement should be:
echo 'h{'.$num.'}';
what is the shortest code to do this?
The easiest way is to use shuffle with an array containing the 100 numbers
e.g.
$sequence = range(1, 100);
shuffle($sequence);
foreach ($sequence as $num) {
echo 'h{'.$num.'}';
}
Also see the range function
EDIT
I thought I might add a little on what shuffle does. Although php.net doesn't explicitly say so, it is likely based on the modern version of the Fisher-Yates shuffle algorithm. For a video demonstration of how it works, see http://www.youtube.com/watch?v=Ckh2DJrP7F4. Also see this excellent flash demonstration
The shuffle algorithm essentially works like this:
For a given set of elements A1 to AN, and n = N;
Randomly select an element Ak between A1 and An inclusive
Swap Ak and An
Set n = n - 1
Repeat from step 2
Hope that helps.
See the example for shuffle():
$numbers = range(1, 20);
shuffle($numbers);
foreach ($numbers as $number) {
echo "$number ";
}