How to write an if statement in a foreach statement - php

I am currently writing a script where a user inputs a number into a form, and the script searches through a folder for an image matching that number and displays it for the user (with download button coming). Right now my code looks like this:
$photo_id = trim($_REQUEST['photo_id']);
$dir = "./wp-content/uploads/easter_pics";
$images = (scandir($dir));
foreach ($images as $value); {
$file_ext = strpos($value, ".");
$file_name = substr($value, 0, $file_ext);
if ($file_name === $photo_id) {
echo ("<img src = '../wp-content/uploads/easter_pics/" .
$file_name . ".jpg' />");
}
}
This code works only if the user inputs the number for the last image in the directory. I think I get the basic principle of what is wrong. $images keeps getting assigned the value of the last item in the array for $dir. At least I think.
The problem is I could be wrong, and also I don't know how to fix it. I want the if statement to display the image if the user input matches any photo in the directory then break.

Your foreach is wrong:
foreach ($images as $value); {
should be
foreach ($images as $value) {
(notice the missing semicolon)
That being said, for your particular case, foreach over a scanned dir might not be the best solution. Try validating the input better (e.g. use intval if the ID is always a number) and just see if the file exists.

Related

Optimising a script to scan files in a folder

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

multiple file_exists function in one if statement overwrite each other

I am creating a word to image converter and for multy image words, I need to write a bit more complex if statements.
My first if statement works well for 2 image word(word = image + image):
$words = array("car", "bike",...)
foreach ($words as $x => $word) {
$jpg = "Pictures/".$words[$x] . ".jpg";
$jpg1 = "Pictures/".$word."/".$word. "1.jpg";
$jpg2 = "Pictures/".$word."/".$word. "2.jpg";
$jpg3 = "Pictures/".$word."/".$word. "3.jpg";
if (file_exists($jpg1) && file_exists($jpg2)) {
print '<div class="result1"><div id="result1" style="background-image:url('.$jpg1.')"></div>
<div id="result2" style="background-image:url('.$jpg2.')"></div>
<a id="word'. $x .'">'. $words[$x] .'</a></div>';
}
This if spatement says that if the file in directory jpg1 and jpg2 exists, print this...So if it locates just the two files in those directories it will work.
However, when I try adding a 3rd file_exists function to an else if statement like this:
else if (file_exists($jpg1) && file_exists($jpg2) && file_exists($jpg3)) {
print '<div class="result2"><div id="result3" style="background-image:url('.$jpg1.')"></div>
<div id="result4" style="background-image:url('.$jpg2.')"></div>
<div id="result5" style="background-image:url('.$jpg3.')"></div>
<a id="word'. $x .'">'. $words[$x] .'</a></div>';
}
The first if statement overrides the second one, even though the second one is correct. and the first one isn't.
I wanted to ask if everything is correct with my syntax? Or if I can even use multiple file_exists functions like this.
Or any other reason why this might not work.

PHP - SplFileObject - Wrong output for second line when using seek() method

Go to UPDATE to read what's the actual problem now. Old question was already resolved with the first answer submitted by Bert Peters.
OLD QUESTION:
I have few files named as file.1.txt, file.2.txt, file.3.txt, ... I'm reading first file with SplFileObject and using foreach loop to iterate through its content:
$file = new SplFileObject("file.1.txt");
foreach ($file as $row) {
// ...
}
Other files may be or may not be read, depending on the contents of the first file I'm reading. In all cases there should be only one file of others (file.2.txt or file.3.txt) which may be used in the next step. So somewhere inside foreach loop there is if statement which handles this.
All files have the same structure, so there comes the problem. I wouldn't like to create new foreach for reading next file - as I wrote it may not be needed at all, so I would like to use existing foreach instead of writing new one. Is there any possibility to overwrite $file variable with the contents of other file and iterate over it with using only one foreach or any other loop? For example:
foreach ($file as $row) {
// ...
if ($contentContainsSomething) {
$file = new SplFileObject("file.2.txt");
// somehow reset foreach to read file.2.txt from start
}
}
I wouldn't like to use goto statement to solve this problem. The recursion seems to be appropriate solution, but if there's a way to change object in loop on the fly, I would prefer this solution.
UPDATE:
As mentioned in "old question" all used files (file.1.txt, file.2.txt, ...) have the same structure, so that's why I wouldn't like to write more same loops and copy code. Instead I used code from #Danack (suggested by him on SO chat) which is already a part of solution. Here's the basic code for reading more files without any upgrade I need:
$path = "file.1.txt";
$whileCounter = 0;
while ($path != null) {
$file = new SplFileObject($path);
$file->setFlags(SplFileObject::READ_CSV);
$file->setCsvControl("\t");
$path = null;
foreach ($file as $rowKey => $row) {
// echo row }
$path = "file.2.txt";
if ($whileCounter > 0) {
break; // solution to stop loop, just for now
}
$whileCounter++;
}
So this code is working without any problem and outputs the file's lines as expected. The problem is when I would like to read next line of file with seek() method, because I would like to make decision on some information which is appended to each next line. So if I use seek($rowKey + 1) which helps me to get next line data (I use $file->current() when line is changed) and after that I call seek($rowKey) to get to previous line, then next file will output first line twice and second line will be missed. The third line and all after then are printed well. This is the problem achieved with the code below:
$path = "file.1.txt";
$whileCounter = 0;
while ($path != null) {
$file = new SplFileObject($path);
$file->setFlags(SplFileObject::READ_CSV);
$file->setCsvControl("\t");
$path = null;
foreach ($file as $rowKey => $row) {
if ($whileCounter > 0) {
var_dump($row);
echo "<br>";
}
$file->seek($rowKey + 1);
if ($file->valid()) {
$file->seek($rowKey);
} else {
var_dump($row);
echo "<br>";
$path = "file.2.txt";
}
}
$whileCounter++;
}
If you apply custom .csv files (with at least five non-empty lines) instead of file.1.txt and file.2.txt, you will see that second and third output are the same (second and third output are first and "second" lines of file.2.txt). What could be wrong here?
There is not. Foreach uses an iterator over your $file variable, and that iterator continues to be valid even though you changed the value of $file.
Or, to put this in another way, foreach will continue to look at the previous contents of $file, regardless of what you do with it afterwards. This is because $file is not actually the SplFileObject, but rather a reference to it, and the reference is used by foreach.

How to batch add images with similar name using jquery/ php

I'm adding images to a website but the amount I want to add would take a long time, is there a quicker way of adding these images and for it to automatically find new images if the file name was appended +1 such as image1.jpg, image2.jpg etc.
I am using PHP. Also thought maybe this could be done using a javascript or jquery loop, for loop maybe, im just unsure how.
<img src="images/other/pic2.png"></a>
<img src="images/other/pic3.png"></a>
<img src="images/other/pic4.png"></a>
<img src="images/other/pic5.png"></a>
<img src="images/other/pic6.png"></a>
<img src="images/other/pic7.png"></a>
<img src="images/other/pic8.png"></a>
Its not a good idea to blindly loop a curtain amount of iterations hoping that the file is there and is a valid file, a better way would to loop the directory of files, check that the file is first a valid image and contains the expected filename prefix. This way you can add as may images to the dir knowing that there be added without changing code.
<?php
$img_path = './images/other/';
$prefix = 'img';
if ($fh = opendir($img_path)) {
while (false !== ($file = readdir($fh))) {
if ($file != "." && $file != "..") {
//Validate its an image and get size, also check that the image filename starts with the $prefix
$attr = getimagesize($img_path.$file);
if(isset($attr[3]) && substr($file,0,strlen($prefix)) == $prefix){
echo '<img src="'.$img_path.$file.'" '.$attr[3].' alt="'.$file.'"/>';
}
}
}
closedir($fh);
}
?>
Well judging by your description, doing something like this would probably be suitable:
$initialImageNumber = 2;
$endingImageNumber = 9;
for ($i = $initialImageNumber; $i <= $endingImageNumber; $i++)
echo '<img src="images/other/pic' . $i . '.png">';

PHP help for a beginner. Scanning file structure to return folder names in an array

I am looking for some help with my code, I have looked elsewhere but am having difficulty to really understand what is going on with the code given elsewhere and I am hoping someone can help me.
I have one gallery page that uses $_POST to change the folder the gallery gets it images form based on the link clicked.
What I want now is to code a search function that looks through them all for a string (a jpg) when it finds it, it returns its img tags and displays the image.
I am having trouble making scandir work and display currently using this code
<?php
$dir = "/galleries/images/adult-cakes/images/";
$scan = scandir($dir);
echo $dir;
print_r($scan);
foreach ($scan as $output) {
echo "$output" . "<br />";
}
?>
that returns the echo dir but nothing else ( please note print was something I tried it was echo before and neither is working.
Then I need to get the output of all the gallery types, adult, anniversary etc and put them into a loop like so
search criteria = cake 1(.jpg)
put scandir info into $folderarray
search this folder until found -
galleries/images/$folderarray/images/
loop
if found then echo img tags with link to pic
if not display not found
This will get an array of all the files in directory $dir
<?php
$dir = "/galleries/images/adult-cakes/images/";
$images = glob($dir . '*');
?>
Do this to get all subdirectories of $Dir into array $DirArray:
$Dir = '/galleries/images/'; //
foreach ( $DirArray = array_filter(glob($Dir . '*'), 'is_dir') as $DirName ) {
$DirName = str_replace($Dir, '', $DirName); // Optionally, remove path from name to display
echo "Dir Name: $DirName <br />\n"; // Test
}
echo var_dump($DirArray); // Test
Modify accordingly

Categories