More elegant solution to this nested loop, anyone? - php

I have a php procedure that scans a directory where its content is thumbnail images of pdf files. The thumbnails are then displayed in a table, and included in an iframe of a parent web page. Each thumbnail is itself a hyperlink when clicked will open the actual pdf file. To avoid having a horizontal scroll bar, 9 images in a table row is perfect. I wrote a nested loop that in effect acts like a word wrap, where it displays 9 images and then begins another row. The actual code is much more entailed, so I have it pared down to a bare minimum example. It seems almost counter intuitive on first glance, decrementing $i on the second line of the outer loop, but it works. I wonder if anyone has a more elegant solution?
$ary = array(1,2,3,4,5,6,7,8,9,10);
for ($i=1; $i<(count($ary)+1); $i++) {
$i = $i-1;
for($j=0; $j<9; $j++) {
if ($i === count($ary)) break;
echo ($ary[$i].", ");
$i+=1;
}
echo "<br>";
}
The completed code now where $ndx is the count of the array, $dir is the scanned directory containing the png images, and $rtDir is the directory where the pdf's are saved:
if ($ndx > 0) {
$tbl = '<div id="draggable" class="ui-widget-content">
<ul>
<table><tr>';
/* place 9 images on one row */
foreach ($myfiles as $index => $image) {
$pdf = basename($image, ".png");
$pdf = $pdf . ".pdf";
$pdf = $rtDir.$pdf;
$tbl .= '<td>
<span class="zoom">
<a href="'.$pdf.'" target="_blank">
<li><img id="pdfthumb'.$index.'" class="myPhotos" alt="pdf'.$index.'" src="'.$dir.$image.'" ></li>
</a>
</span>
</td>';
if ($index % 9 == 8) {
/* end the current row and start a new one */
$tbl.= "</tr></table><br><br><table style='margin-top:-40px'><tr>";
}
}
$tbl .= "</tr></table></ul></div>";
printf($tbl);
unset($myfiles);
}
Thanks everyone for your suggestions.

So you want 9 images on each row? There are usually two logical choices:
Alternative 1: You use array_chunk(), e.g. like this:
$chunks = array_chunk($images, 9);
foreach ($chunks as $chunk) {
foreach ($chunk as $image) {
// image printing goes here
}
echo '<br'>;
}
Alternative 2: You use the modulo operator, e.g. like this:
foreach ($images as $index => $image) {
// images printing goes here
if ($index % 9 == 0) { // or 8, since it's a 0-index array... I don't remember
echo '<br>';
}
}
I mostly use the second version, myself, if I have to - or I ask one of our designers to make it fit to a proper width through css. Do note also that the second version won't work if your images array is associative.

$b = count( $ary ) - 1 ;
for( $i = 0 ; $i <= $b ; $i++ ) :
echo $ary[$i] ;
if( ( $i + 1 ) % 9 == 0 ) :
echo "<br>" ;
endif ;
endfor ;
like the above comment i like modulus but i also prefer the for loop, hope this helps.

Related

PHP foreach loop that creates four colums on flexbox

I'm trying to make something like a flexbox with CSS and PHP. The idea is to upload .jpg images to a folder and then sort them into four columns equally. My current approach is to count the total number of files in the folder, divide by four and with that create indices for a foreach loop to iterate and put the images into the columns. I need it to look like this.
Later on I'll have to make a popup on each of these images which should bring some basic HTML/CSS thing. Not sure if that's something to take in mind for this particular case.
This is my (incomplete/not working) code:
<?php
$fi = new FilesystemIterator("../../showoff_images", FilesystemIterator::SKIP_DOTS);
printf("There were %d Files", iterator_count($fi));
$fi = iterator_count($fi);
#Divided $f1 by four to get the number of items in columns
$fby4 = intdiv($fi,4);
#Create start index for each image
$f0 = 0;
$f1 = $fby4-1;
$f2 = $fby4*2-1;
$f3 = $fby4*3-1;
$f4 = $fby4*4-1;
#CHECK THE INDEX FOR THE IMAGES. START AT 0 AND START ITERATING WITH THE $fn VALUES FOR THE FOLLOWING FUNCTION!
#Iterates images
$directory="../../showoff_images/";
$images=glob($directory . "*.jpg");
$lazyload = "lazy";
$measure = "100%";
$distance = "20px";
foreach($images as $image=>$value) {
if($value > 4) continue;
++$value;
echo
"
<h2 style = padding-top= ".$distance." padding-bottom= ".$distance." padding-right= ".$distance." padding-left= ".$distance."></h2>
<img src=" .$image." loading =". $lazyload ." height=".$measure." width=".$measure.">
";
#++$f0;
}
?>
Really appreciate your help and glad to be joining the forum!
Comment to answer
You should be able to use array_chunk for this, which will allow you to break your array up into sub-arrays.
Here's a sample, not really bound to your data but it should make sense.
$letters = range('a', 'z');
$rows = array_chunk($letters, 4);
foreach($rows as $row){
echo '<div>', PHP_EOL;
foreach($row as $letter) {
echo $letter, PHP_EOL;
}
echo '</div>', PHP_EOL;
}
Demo here: https://3v4l.org/HpTSH

Controlling for-loop output

Is it possible to control a for-loop when it reaches a certain condition?
Explanation:
I'm retrieving the folder path to a collection of images from a database: these images are then printed out via a for-loop. What I would need to do is control how these images are displayed on the page (say, 5 images per row).
As of now, the for-loop prints out 40 images in a single row, which makes you scroll to the furthest right of the page.
Is there a solution for controlling the for-loop, as in for instance, after 5 successful loops, echo out a < br >? Here's a vulgar thought:
for ($i = 1; $i < $rows; $i++) {
$path = $image[$i];
$folder_path = $path['folder_path']; //since it's an array
echo '<img src="' . $folder_path . '">';
//pseudocode
if ($i == 5) {
echo '<br>';
...continue with the loop
}
}
I know the pseudocode looks crazy, but that's pretty much what I need to do: loop for x amount of instances, add something, then continue.
As per #m69's comment, the best option would be to use the % (modulus) comparison operator. As explained by the PHP docs:
$a % $b returns the remainder of $a divided by $b.
So, in your case:
for ($i = 0; $i < $rows; $i++) {
$path = $image[$i];
$folder_path = $path['folder_path']; //since it's an array
echo '<img src="' . $folder_path . '">';
if ($i % 5 == 0) { //do this if $i divided by 5 has a remainder of 0
echo '<br>';
}
}
As a side note, you should set $i to 0 at the beginning of your for loop, assuming $rows is set to the number of rows returned from your query. Setting it to 1 will keep it from iterating through the last row, because $i will == 40 (assuming 40 rows), and so will NOT be < 40.
The same loop. The condition for inserting the is ($i % 5 == 0), which means (if this element is the fifth one of his series) will be useful for you.
<?php
for ($i = 1; $i < $rows; $i++) {
$path = $image[$i];
$folder_path = $path['folder_path'];
echo '<img src="' . $folder_path . '">';
if ($i % 5 == 0) {
echo '<br>';
}
}

How can I loop through an array, starting at an offset and looping round again?

Newb question: I'm using a foreach loop to get items from an array.
I need to start looping at an offset number- (I'm using a $i variable to do this, no problem).
But when my foreach reaches the end of the array I want it to start going through the array again until it reaches the offset number.
I need to do this so I can have a user open any image in an artist's portfolio and have this image used as the first image presented in a grid of thumbnail icons , with all the other images subsequently populating the rest of the grid.
Any ideas?
Please bear in mind I'm new to PHP! :)
See below for an example of my current code...
$i=0;
$limit=50;// install this in the if conditional with the offset in it (below) to limit the number of thumbnails added to the page.
$offset=$any_arbitrary_link_dependant_integer;
foreach($portfolio_image_array as $k=>$image_obj){//$k = an integer counter, $image_obj = one of the many stored imageObject arrays.
$i++;
if ($i > $offset && $i < $limit) {// ignore all portfolio_array items below the offset number.
if ($img_obj->boolean_test_thing===true) {// OK as a way to test equivalency?
// do something
} else if ($img_obj->boolean_test_thing===false) { // Now add all the non-see_more small thumbnails:
// do something else
} else {
// error handler will go here.
}
} // end of offset conditional
}// end of add boolean_test_thing thumbnails foreach loop.
};// end of add thumbnails loop.
$i = 0;
$limit = 50;
$offset = $any_arbitrary_link_dependant_integer;
$count = count($portfolio_image_array);
foreach($portfolio_image_array as $k=>$image_obj){//$k = an integer counter, $image_obj = one of the many stored imageObject arrays.
$i++;
if ($i > $offset && $i < $limit && $i < ($count - $offset)) {// ignore all portfolio_array items below the offset number.
if ($img_obj->boolean_test_thing===true) {// OK as a way to test equivalency?
// do something
} else if ($img_obj->boolean_test_thing===false) { // Now add all the non-see_more small thumbnails:
// do something else
} else {
// error handler will go here.
}
} // end of offset conditional
}// end of add boolean_test_thing thumbnails foreach loop.
};
Only thing I added was a $count variable.
Edit: If your array starts at 0 I would suggest you put the $i++; at the end of your foreach loop.
A simple method is to use two separate numeric for loops, the first going from offset to end, and the second going from beginning to offset.
<?php
// Create an example array - ignore this line
$example = array(1,2,3,4,5,6);
$offset = 3;
// Standard loop stuff
$count = count($example);
for($i = $offset; $i < $count; $i++)
{
echo $example[$i]."<br />";
}
for($i = 0; $i < $offset; $i++)
{
echo $example[$i]."<br />";
}
?>
This is also almost certainly cheaper than doing multiple checks on every single element in the array, and it expresses exactly what you are trying to do to other programmers who look at this code - including yourself in 2 weeks time.
Edit: depending on the nature of the array, in order to use numeric keys you may first need to do $example = array_values($portfolio_image_array);.
Using Answer Question to force StackOverflow to let me post a decent length of text!
OK #Mark Walet et al, not sure how to post correctly on this forum yet but here goes. I got the issue sorted as follows:
$i=0;
$offset=$image_to_display_number;
$array_length = count($portfolio_image_array);
// FIRST HALF LOOP:
foreach($portfolio_image_array as $k=>$img_obj){// go through array from offset (chosen image) to end.
if ($i >= $offset && $i <= $array_length) {
echo write_thumbnails_fun($type_of_thumbnail, $image_path, $k, $i, $portfolio_image_array, $title, $image_original);
$t_total++;// update thumbnail total count.
}
$i++;
}// end of foreach loop 1.
$looped=true;// Just FYI.
$i=0;// Reset.
// SECOND HALF LOOP:
foreach($portfolio_image_array as $k=>$img_obj){// go through array from beginning to offset.
if ($i < $offset) {
echo write_thumbnails_fun($type_of_thumbnail, $image_path, $k, $i, $portfolio_image_array, $title, $image_original);
}
$i++;
}// end of foreach loop 2.
Thankyou so much for all the help!
:)
as #arkascha suggested use modulo operator
<?php
$example = array(1,2,3,4,5,6);
$count = count($example);
$offset = 3;
for($i = 0; $i < $count; $i++) {
$idx = ($offset + $i) % count
echo $example[$idx]."<br />";
}
?>

how to generate a random image output

i have some basic php code that pulls an image from a particular image folder when the user asks using a form.
I will have many image folders and want to generate a random image instead of using
case 'A' : echo "<a href=\"Alphabet-Letters/Letters-A\">
<img src=\"image/data/A/A_001.jpg\" id=\"A1\" width=\"70\" height=\"120\" title=\"A1\"/> </a>" ; break;
My question is this as the form is processed with someone using the letter A the picture of that letter appears. The php code for this is
if (array_key_exists('check_submit', $_POST))
{
$letters = $_POST['Comments'];
$num_letters = strlen($letters);
for($i = 0; $i < $num_letters; $i++)
{
switch ($letters[$i]) {
case 'A' : echo "<a href=\"Alphabet-Letters/Letters-A\">
<img src=\"image/data/A/A_001.jpg\" id=\"A1\" width=\"70\" height=\"120\" title=\"A1\" alt=\"Image A\"/>
</a>" ;
break;
This only pulls the exact image i have asked, but i have hundreds in that folder and would like a more simple code to work with.
Please can someone help, they gave advise on using random image from folder, but that only works as a starting point not on the code I already have.
Thanks for your time
The solution posted at the link below should achieve the functionality you are looking for.
https://stackoverflow.com/a/4478788/1152375
so you should be able to do something like
case 'A' : echo "<a href=\"Alphabet-Letters/Letters-A\">
<img src=\"image/data/A/" . random_pic("folder_with_pics") . "\" id=\"A1\" width=\"70\" height=\"120\" title=\"A1\</a>";
break;
before you get to the output code, you will want to get a list of all files in the relevent directory ( http://php.net/manual/en/function.dir.php ) in a numbered array.
count the number of items in the array ( http://php.net/manual/en/function.count.php ) and randomly pick one ( http://php.net/manual/en/function.rand.php ) using the min and max settings of rand.
Try using the scandir function to find all the files in the folder, and then use the rand function to randomly choose one:
if(!empty($_POST['check_submit']))
{
$letters = strtoupper(trim($_POST['Comments']));
$num_letters = strlen($letters);
for($i = 0; $i < $num_letters; $i++)
{
$letter = $letters[$i];
$folder = 'image/data/'.$letter;
$files = scandir($folder);
array_shift($files);
array_shift($files);
$index = rand(0, count($files) - 1);
$file = $files[$index];
echo "<a href=\"Alphabet-Letters/Letters-{$letter}\">\n";
echo "<img src=\"image/data/{$letter}/{$file}\" id=\"{$letter}{$index}\" width=\"70\" height=\"120\" title=\"{$letter}{$index}\" alt=\"Image {$letter}\"/>\n";
echo "</a>\n";
}
}
Found the answer by using #Buchow_php and trial and error.
for ($i=0; $i<$num_letters; $i++)
{
$image_num = '$image'.$i;
echo "<input type=\"hidden\" name=\"option[$image_num]\" value=\"$skus[$i]\" />";
}
together with the previous code and now it brings all the image files into an array for posting to my submit

PHP reapet foreach until

I print img html elements by a foreach cycle.
Images are stored in db so if they are 40 foreach will print 40 img
Now i need that if they are 40 in db and i need to print 100 img elements, to repeat the cycle until they are 100, is it possible to do that?
EDIT:
to be clear, i retrieve 40 img from db, i need to print "100 OF THEM" (repeat them if they are less than 100) ... hope is clear :P
You can use Iterators:
$images = new LimitIterator(
new InfiniteIterator(
new ArrayIterator($imgArray)
),
0, 100
);
foreach ($images as $image) {
// print images
}
The ArrayIterator makes your $imgArray iterateable by other Iterators. The InfiniteIterator will make the wrapped ArrayIterator start over at the beginning when it has reached the end of $imgArray. Finally, the LimitIterator will limit the iteration to 100 items.
So, when you iterate over $images, foreach will go over the elements in the image array repeating them over and over until 100 elements have been printed, e.g. this will output images 1-40, then again 1-40 and finally 1-20 because 40+40+20=100.
Demo: http://codepad.org/YeDgpsVc
Repeat 100 times and use the modulus operator on the index:
$images = function_to_fetch_images();
for($i=0, $count = count($images); $i<100; $i++) {
echo $images[$i % $count];
}
I'm not quite sure if I understand the question, but I'm guessing that you want to show 100 images, but repeat some of the images if there's less than 100. If so, you can use a for loop that iterates through all the images, then when you're at the last image, and there hasn't been 100 images outputted, go back to the first one.
for ($i = 0, $j = count($images); $i < 100; $i++)
{
echo $images[$i % $j];
}
You will need a nested loop for this. I am assuming you meant that you wish to repeat through the elements in the image set until you've got 100 images on the screen, even if that means some images are duplicated.
for ($i = 0; $i < 100;) {
foreach($imageSet as $image) {
echo $image;
$i++;
if ($i < 100) break;
}
}

Categories