Page 1 of 1
How to avoid an infinite loop?
Posted: Tue Apr 19, 2005 8:06 pm
by ashley
I'm currently working on a script to help websites deal with http error codes, it serves up an error page, and records the event with pertinent information, nothing to track a person with, just requested page, referring page, et cetera.
I'm in the middle of trying to create a function to parse the requested url for each "folder" in the requested url to check to see what (if any) resources exist within the url.
If the resource exists, a link to that directory is made, if the resource doesn't exists, it doesn't create a link.
My problem runs into using fopen(). I check each directory with that one function, so, when the script rolls around to the resource with a problem, I get an "infinite loop" (of sorts, apache usually just kills the thread after a while).
The function file_exists() doesn't work, because it uses the file structure, and thus doesn't take .htaccess files into account, which means rewrite_rules which do point to real resources can fail, when they actually do exist "somewhere".
I've also tried fsockopen(), but had some trouble getting the port setting to work properly. I also don't think this is the right path to take.
So, then, how can I get a script, called from an http error page to call itself (which doesn't "exist"), and fail gracefully?
Any suggestions?
Posted: Tue Apr 19, 2005 9:06 pm
by John Cartwright
Post some code. (and please read
Posting Code in the Forums too)
Posted: Tue Apr 19, 2005 11:49 pm
by feyd
A properly constructed rewrite rule set for handling the errors can do it by not rewriting the url when the request is internal should handle it. If you used fsockopen() or curl, you could simple request the header information, which will contain the http status code for your script.
Posted: Wed Apr 20, 2005 5:01 am
by malcolmboston
im not sure on how this could be implemented atm as im not on my machine but would something like this work.....
Functions Needed
Code: Select all
function GetMicrotime ()
{
list($usec, $sec) = explode(" ", microtime());
return ((float)$usec + (float)$sec);
}
code to stop looping for too long
Code: Select all
$max_allowed_time = 10; // Allow 10 seconds max
// something to put in the for loop
$query = "SELECT something FROM somewhere";
$result = mysql_query($query) or die (mysql_error()):
//assume we're getting a record
while ($array = mysql_fetch_array($result))
{
if (!isset($i))
{
$i = 1;
}
$super_array[$i]['something'] = $array['something'];
$i++;
}
$count = count($super_array);
// now an example loop firtly getting start time
$start_time = GetMicrotime();
for ($i = 1; $i <= $count; $i++;)
{
$end_time = GetMicrotime();
$time_taken = ($end_time - $start_time);
if ($time_taken >= $max_allowed_time)
{
print "Script Exceeded the Max Allowed Execution Time, Execution was suspended";
break 2;
}
else
{
print "Something = {$super_array[$i]['something']}<br>\n";
}
}
in theory, to me at least, this should work
edit: if this works, i may actually implement it into a couple of my projects
Posted: Wed Apr 20, 2005 6:27 am
by JayBird
Yes, that would work Mal
Posted: Wed Apr 20, 2005 6:31 am
by malcolmboston
i was 99% sure it would, just i had to write it in notepad (yuck!)
Posted: Wed Apr 20, 2005 6:14 pm
by ashley
malcolmboston: that function is fine and all, it just doesn't do what I need it to do. I'm not using a database, I'm opening a file. Openning the file takes too long, because as I said earlier, the script is called from the error page, and is requesting itself with the fopen() call, which means apache will request the page forever.
As far as I can tell, PHP can't stop the execution of something if it takes too long, while loops, do-while loops, for, and foreach all test the expression after (or before) the iteration. If I was to use a loop, I would still test the page once (or not at all), and once is too long, especially in an infinite loop.
As for feyd, how would I construct this rewrite rule to handle internal errors? To be frank, I'm not even sure I know what that first sentence of yours means; I couldn't even wrap my head around that one, links to resources, or even a little pseudo-code would definitely help.
I'd like to stay away from curl, as it's not standard. Currently, fsockopen() is an option, I'm going to look into it more.
Thanks for the help so far guys :)
Posted: Wed Apr 20, 2005 7:41 pm
by feyd
my code often will implement varying paths and support levels if curl is available, versus fsockopen.
As for some direction to go on the rewrite rule:
RewriteCond is involved.. a lot.
Posted: Thu Apr 21, 2005 4:58 am
by malcolmboston
ashley wrote:malcolmboston: that function is fine and all, it just doesn't do what I need it to do. I'm not using a database, I'm opening a file. Openning the file takes too long, because as I said earlier, the script is called from the error page, and is requesting itself with the fopen() call, which means apache will request the page forever.
replace the for loop with the with your own for loop, thought it was rather obvious :/
Posted: Thu Apr 21, 2005 2:00 pm
by ashley
malcolmboston wrote:
replace the for loop with the with your own for loop, thought it was rather obvious :/
I did that, then after some googling, and testing I discovered that the expression, in this case fopen(), is still going to be executed at least once during almost any type of loop, which is too much-especially in an infinite loop.
Hmm... Maybe that's the problem, my use of the term "infinite loop", I didn't mean that a for/foreach/do/do-while loop was repeating forever. I meant that the execution of my fopen() call was being called from my apache error page, which fopen() will eventually call (calling itself), then when the missing page is called, it will generate another error, my http-error page will be called as a replacement, and the cycle will continue on-and-on forever, or close to it
Something like this:
http://example.com/path/to/dir/
Let's say that the first two directories exist, but the last one doesn't. fopen() will return success on those, the problem developes when it requests the page that doesn't exist.
So, the page
http://example.com/path/to/dir/ places a call for
http://example.com/path/to/dir/ which doesn't exist, generating another error, and Apache, not knowing any better, gives my error page as the "replacement", so there is another request for
http://example.com/path/to/dir.
And this very annoying cycle continues, and continues, each error page calling the very page it's trying to replace.
I don't even know if I explained it properly, I hope I did though, feel free to flame me if I didn't.
That's my infinite loop, not a control structure infinite loop. If that was the problem, I'm sorry for my mistake, I hope this clarification helps the matter.
I can't stop a loop during the execution of the expression, only in-between each iteration, so even if the values expressed in for() change during an iteration, it will continue to execute until it is time to re-interpret the for() loop.
Don't get me wrong, I could be wrong. If I am, please correct me, it's just what I interpreted.
feyd wrote:
As for some direction to go on the rewrite rule: RewriteCond is involved.. a lot.
Thanks for the pointer feyd, never would of thought of looking into mod_rewrite, checking it out currently, I'll post back some responses/remarks when I get a handle on it.
Posted: Sat Apr 30, 2005 12:55 pm
by ashley
Actually, none of that is needed. I setup a simple if question in the beginning, before the loop is started to check the HTTP_USER_AGENT.
Code: Select all
if (($_SERVER['HTTP_USER_AGENT'] == '') OR ($_SERVER['HTTP_USER_AGENT'] == 'PHP')) {
die('Error: Infinite loop detected.');
}
It does have it's problems. Depending upon what the php.ini file defines as the HTTP_USER_AGENT. It can vary host-to-host, so checking with a host beforehand is a good thing. PHP is a pretty safe bet. But safe bet isn't a sure thing.
I also assume that somewhere out there, there is a real user agent(browser, bot) that doesn't have anything set for this field either. Haven't met one yet though, so the chances are slim. This also doesn't mean that it's safe either.
It's not perfect, but it's a start.