Dealing with infinite loops - php

I'm trying to learn PHP programming through trial, error and lots and lots of practice.
I've been working on a directory bases image gallery for the last few days and it seems to work fine. I can upload pictures and create new albums. Plus whenever I see a full size picture I have links to the previous and next pictures in the directory.
Now this is where I ran into problems. Once you got to the end of the directory the code would start an infinite loop while it searches for the next file, which isn't there.
So I altered my code and it now looks something like this:
$x = 1;
$dir = opendir($base.'/'.$get_album);
while ((($file = readdir($dir)) !== FALSE) && ($x == 1)) {
while ($img < $file) {
$img++;
$image_exists = file_exists($base.'/'.$get_album.'/'.$img);
if ($image_exists) {
echo "<a href='member.php?album=$get_album&imgID=$img'>
<img src='$base/$get_album/$img' width='70' align='right'>
</a>";
break;
}
$x++;
}
}
This works when I get to the last picture in the directory. So I thought I'd do the same for when I get to the first picture and just invert the operators like so:
$x = 1;
$dir = opendir($base.'/'.$get_album);
while ((($file = readdir($dir)) !== FALSE) && ($x == 1)) {
while ($img > $file) {
$img--;
$image_exists = file_exists($base.'/'.$get_album.'/'.$img);
if ($image_exists) {
echo "<a href='member.php?album=$get_album&imgID=$img'>
<img src='$base/$get_album/$img' width='70' align='right'>
</a>";
break;
}
$x++;
}
}
This however DOES NOT work. I can't understand why that would be the case and I've tried to change things around a few dozen times but I cant seem to make it stop looping.
What am I doing wrong?
Thanks in advance for your help (and for reading through all this).

The issue could likely be related to the fact that readdir returns a string, and you are treating it as if you know its a number. You might find that it is returning you something at the start or end, such as the parent directory '..' as a string or the current directory as a string '.'.
If you want to iterate over the directories, you should check that the return value from readdir is not '.' or '..' specifically.

Please use a better format to your code (it's really painful read it), for instance, in netbeans you can use shiftalt F to format automatically.
I want address your attention to this line:
$image_exists= file_exists($base.'/'.$get_album.'/'.$img);
That is a possible source of errors. If only $base.'/'.$get_album.'/' exists then:
$image_exists= file_exists($base.'/'.$get_album.'/'.$img); // is true even if $img is empty!!!
But moreover:
What is $img? You treat it as a number when do $img++ and then as a string. That is not good for your health.
A good start it should be initialize your vars at the beginning of your code. And then use them in consonance.

I think there is something fundamentally wrong with the design, you are comparing $img, an uninitialized integer, to $file, a string.
It also seems needlessly complicated, as you are reading files from a directory, then check if they exist and break out of your loop if they do.
Perhaps with a clear view of the directory structure and what you are trying to do, I could provide a more detailed answer, but I think you need to go back to the drawing board.

Related

how to search for a string into a lot of files using PHP

First I am new to PHP so I don't have any idea on how to accomplish this. I have a folder that is constantly getting txt files created ranging in size and text. I am trying to create somewhat of a "search engine" on a Linux system written in PHP. So far I am using the code below.
if ( $_SERVER['REQUEST_METHOD'] == 'POST'){
$path = '/example/files';
$findThisString = $_POST['text_box'];
$dir = dir($path);
while (false !== ($file = $dir->read())){
if ($file != '.' && $file != '..'){
if (is_file($path . '/' . $file)){
$data = file_get_contents($path . '/' . $file);
if (stripos($data, $findThisString) !== false){
echo '<p></p><font style="color:white; font-family:Arial">Found Match - '. $file .' <br>';
}
}
}
}
}
$dir->close();
Now this code works great! But one problem, once the folder gets around 40,000 files, the search takes a good amount of time to pull any results. Now I can't use any commands such as greb. It has to be written in pure PHP like the code above.
Is there anyway to optimize the code above to work any faster? Or is there a better search function I can use in PHP?
There are many reasons for why the script is so slow, and exactly what you need to do in order to decrease the time it takes depends completely upon what exact parts of the code causes the slow down.
That means that you need to put the code through a profiler, and then tweak the parts of the code that it reports are the cause. Without the profiler, all we can do is guess. Not necessarily correctly.
As noted in the comments to your question, using an already-made search engine would be the far better solution. Especially something which is purpose made for something like this, as it will cut down the time drastically.
Even the built-in grep command for Linux shells would be an improvement.
That said, I do suspect that the reason your code is so slow is because of the fact that you're reading and searching through the contents of all of the files in PHP. stripos() is particularly a likely suspect here, as that's a rather slow search.
Another factor might be the read() calls in the loop, as I believe they do a IO-operation on each call. Also, having a lot of calls to echo in a script can/will also cause a slow-down, depending upon how many of those you have. Couple of hundred is not really noticeable, but having a few thousand will be.
Taking these last points into consideration, and some other general changes I recommend to make your code easier to maintain, I've made the following changes to your code.
<?php
if (isset ($_POST['text_box'])) {
$path = '/example/files';
$result = search_files ($_POST['text_box'], $path);
}
/**
* Searches through the files in the given path, for the search term.
*
* #param string $term The term to search for, only "word characters" as defined by RegExp allowed.
* #param string $path The path which contains the files to be searched.
*
* #return string Either a list of links to the files, or an error message.
*/
function search_files ($term, $path) {
// Ensuring that we have a closing slash at the end of the path, so that
// we can add a file-descriptor for glob() to use.
if (substr ($path, -1) != '/') {
$path .= '/';
}
// If we don't have a valid/readable path we ened to throw an error now.
// This only happens if the code itself is wrong, as it's not user-supplied,
// thus an exception is thrown.
if (!is_dir ($path) || !is_readable ($path)) {
throw new InvalidArgumentException ("Not a valid search path!");
}
// This should be validated to ensure you get sane input,
// in order to avoid erroneous responses to the user and
// possible attacks.
// Addded a simple test to ensure we only accept "word characters".
if (!preg_match ('/^\w+\\z/', $term)) {
// Invalid input. Show warning to user.
return 'Not a valid search string.';
}
// Using glob so that we retrieve a list of all files in one operation.
$contents = glob ($path.'*');
// Using a holding variable, as this many echo statements take
// noticable longer time than just concatenating strings and
// echoing it out once.
$output = '';
// Using printf() templates to make the code easier to reach.
// Ideally the HTML-code shouldn't be in this string either, but adding
// a templating system is far beyond the reach of this Q&A.
$outTemplate = '<p class="found">Found Match - %2$s</p>';
foreach ($contents as $file) {
// Skip the hardlinks for parent and current folder.
if ($file == '.' || $file == '..') {
continue;
}
// Skip if the path isn't a file.
if (!is_file ($path . '/' . $file)) {
continue;
}
// This one is the big issue. Reading all of the files one by one will take time!
$data = file_get_contents ($path . '/' . $file);
// Same with running a case-insensitive search!
if (stripos ($data, $term) !== false) {
// Added output escaping to prevent issues with possible meta-characters.
// (A problem also known as XSS attacks)
$output .= sprintf ($outTemplate, htmlspecialchars (rawurlencode($file)), htmlspecialchars($file));
}
}
// Lastly, if the output string is empty we haven't found anything.
if (empty($output)) {
return "Term not found";
}
return $output;
}
if u cant use linux command when u have two ways:
1) It's save files in the Database and after this, when u need find u call query from database for search files.
2) It's create one indexed file(files which will be save in the him list files)
1 and 2 ways help u save time for execute script. For update files u can write Cron task which will be start import new files in the database or file.

Variable + Wildcard image removal

I want to create a piece of code that will remove images based on set parameters and a wildcard.
The number of images and naming will vary, though the first two parameters will remain as a constant.
// Example of images to be deleted / removed.
/images/1-50-variablename-A.jpg
/images/1-50-variablename-B.jpg
/images/1-50-variablename-C.jpg
/images/1-50-variablename-D.jpg
/images/1-50-variablename-E.jpg
Essentially I am after a loop to make this happen though I am not too sure on the best logic to make this happen.
$menuid = "1";
$imageid = "50"
$fileName = "images/".$menuid."-".$imageid."-*.jpg";
if (file_exists ($fileName)) {
unlink ($fileName);
}
You can use the php glob function (http://php.net/manual/fr/function.glob.php). Feed it with your pattern (it supports wildcards) and then iterate over the result and unlink each file.
Hope it helped
Solution presented itself in Glob form.
$menuid ="9999";
$imageid="5";
array_map('unlink', glob("../images/".$menuid."-".$imageid."-*.jpg"));

PHP Cut unknown file extensions

I need help about file manipulation in PHP.
I have 4 file with known names and UNKNOWN extensions.
Like that:
Y923BBBB.E120506
Y924BBBB.E120606
Y925BBBB.E120706
Y926BBBB.E120806
and the file extensions changes everyday.
How i can cut or strip for every file the file extension, so that will stay only the names like that:
Y923BBBB
Y924BBBB
Y925BBBB
Y926BBBB
Anybody an idea?
Think about it the other way around: you want to extract the filename, not "delete the extension":
echo pathinfo($file, PATHINFO_FILENAME);
http://php.net/pathinfo
Use strrpos to find the last . and substr to get only the substring up to that point. To find the files and rename them, use glob and rename:
foreach(glob('*') as $f) {
if ($f == '.' || $f == '..') continue;
$stripped = substr($f, 0, strrpos($f, '.'));
rename($f, $stripped);
}
Take care that glob('*') works differently on windows and linux (compare with answer). Use DirectoryIterator instead if you want a more stable code. Also that one provides the needed functions already to process the file-extension and won't break - as in this example - when a file does not have a dot inside. And take real care with rename, using glob returns the file-name only, rename handles this as full path, you will move files to locations you might not want to move them.
foreach(new DirectoryIterator('.') as $f) {
/* #var $f splFileInfo*/
if (!$f->isFile()) continue;
($ext = strlen($f->getExtension())) && $ext++;
if (!$ext) continue;
$path = $f->getRealPath();
rename($path, substr($path, 0, -$ext));
}
Take care. You should always takes care with rename operations. Every operation related to the file-system and changing it needs more care as let's say read-only proceedings.

php glob() not returning all files

I searched this site and found a very useful snippet of code that i've been able to use.
$counter = 0;
foreach (glob("images/gallery/photo_gallery/resized/*.jpg") as $pathToThumb)
{
$filename = basename($pathToThumb);
$pathToLarge = 'images/gallery/photo_gallery/' . $filename;
echo ('<img src="'.$pathToThumb.'" />');
$counter++;
}
But for some reason this will only return the first 30 images in my directory. (there are 81) Can anyone think why this is happening?
Thanks.
As I have said above
$path = 'images/gallery/photo_gallery/resized/*';
would be enough. or, if you stubbornly wants only jpg only,
$path = 'images/gallery/photo_gallery/resized/*.[Jj][Pg][Gg]';
as manual suggests
Thanks to everyone for input.
Here's the answer - file extensions are CASE-SENSITIVE when used in glob() (something I was un-aware of)
30 of my files end in .jpg whilst the remaining files have been auto renamed through a resizing program to .JPG
So this means glob("imagesPath/*.jpg") only returned the lower-case matches.
Another lesson learnt :)
Hopefully this answer can help someone else too. :)

How can I make a simple path generator?

I have a link that I have to repeat 50 times, for each folder, and I have 15 folders.the link that I have to repeat looks like this:
now, the jpg files are named car 1- car 50. and I would really like to be able to generate this script so that I can input the path "update/images/Cars/" the picture title (car) and the input the number of times that I need this link, and then have it spit out something that looks like this:
and then it keeps repeating, I'm assuming this can be done with a counter, but I'm not sure. Thanks!
You can do it with a for loop:
$path = "update/images/Cars/";
$title = "car";
$times = 50;
for($i = 1; $i <= $times; $i++)
echo "\n";
I used $title for the lightbox argument since you didn't specify
Use a powerful text editor. ;-)
For example, in Vim, I can use the following sequence of keystrokes to create your required text:
i
Esc
qa (start recording macro into register a)
Y (yank (= copy) whole line)
p (paste into the following line)
/ ( Return (search for opening brace)
Space (advance cursor one character so it now sits on the number)
Ctrl+a (increment the number)
q (stop recording the macro)
49#a (invoke the macro 49 times)
If you're going to add or remove images from the folder, then you might get better results using the DirectoryIterator object from the Standard PHP Library. Using it would require PHP5, but there's an old-school way of handling it, too. This snippet assumes that all of the files in the directory are the images you want to list:
$link = '%s';
$dir = new DirectoryIterator("/path/to/update/images/Cars");
foreach($dir as $file) if(!$file->isDot()) echo sprintf($link, $file, $file);
Notice that I put the information about the anchor-element into the $link variable and then used sprintf to print those anchors to the screen. If you don't have PHP5 available to you, you'd want to do it this way:
$link = '%s';
$dir = opendir("/path/to/update/images/Cars");
while(($file = readdir($dir)!==false) if($file != "." && $file != "..") echo sprintf($link, $file, $file);
closedir($dir);
These would only be necessary if you're adding more car photos into the library and don't want to update the page that produces all the links. Both of these snippets should automatically search through the directory of car images and create the links you need.
You can also alter these snippets to search through sub-directories, so you could slam out the links to the images in all 15 folders all with a little bit more code. Let me know if you want to see that code, too.

Categories