How can I stop PHP sleep() affecting my whole PHP code? - php

So, on my arcade, howlingdoggames.com. I have a points system that gives you a point every time you visit a page with a game on. To reduce abuse of this, I would like to make some sort of delay, so its only awarded after 45 seconds. Here's what I've tried:
if ($_SESSION['lastgame'] != $gameid) {
sleep(45);
$points = $points + $game_points;
$_SESSION['lastgame'] = $gameid;
}
But this just seems to halt my whole website for 45 seconds, because this is in index.php, along with a lot of other code for my site.
Is there anyway I can isolate that bit of code, so it only makes the statement
$points = $points + $game_points;
wait for 45 seconds?

There is (mostly) no multithreading in PHP. You can sort of do this with forking processes on Unix systems but that's irrelevant because multithreading isn't really what you're after. You just want simple logic like this:
$now = time();
session_start();
$last = $_SESSION['lastvisit'];
if (!isset($last) || $now - $last > 45) {
$points = $_SESSION['points'] ?? 0;
$_SESSION['points'] = $points + 10;
$_SESSION['lastvisit'] = $now;
}
Basically only give the points if the increment between the last time you gave points is greater than 45 seconds.

It is session block your script. not "There is no multithreading in PHP".
session_write_close() before sleep() will solve block your whole script. but may not fit in your problem.
so you had to save the bonus using settimeout of js and AJAX.
from comment of sleep() in php.net:
http://www.php.net/manual/en/function.sleep.php#96592
Notice that sleep() delays execution for the current session, not just the script. Consider the following sample, where two computers invoke the same script from a browser, which doesn't do anything but sleep.

No, not directly. You need to take a different approach, like remembering the timestamp of last visit and only add points if sufficient amount of time has passed since that.

There is no multithreading in PHP, so sleep() is always going to block your whole script.
The way you should solve this is to record the the time of the last game, and only award points if it is more than 45 seconds later than that.
<?php
session_start();
if (!isset($_SESSION['last_game_time'])
|| (time() - $_SESSION['last_game_time']) > 45) {
// code to award points here
$_SESSION['last_game_time'] = time();
}
Bear in mind that users could still abuse this if they disable cookies (thus they will have no session data). So if that really worries you, check that they have cookies enabled before allowing them to use the feature (there are probably several questions that cover this).

Instead of blocking the script, save the current time in the session, don't add the points and let the page render. Then on later page views if you see that the saved time in session is older than 45 seconds, add the points, store them wherever you need, and clear the time.

You cannot, but you can make this code a javascript one, and save the bonus using AJAX.

Problem is session_start();
Try
if ($_SESSION['lastgame'] != $gameid) {
session_write_close();
sleep(45);
session_start();
$points = $points + $game_points;
$_SESSION['lastgame'] = $gameid;
}

Related

Conserve variable after refresh php

I have a PHP script that read and export CSV to a database. At the beginning of each execution, the script get a customer name with $_POST. It runs around 7 minutes to send 120k row. Nevertheless, my host allow PHP scripts to run up to 165 seconds.
My idea was then to refresh the page before the 165s and start the export again, at the row it ended. I've succedeed to refresh the page, but I struggle to conserve the variable saving the row position at which the script ended in order to use it after the refresh.
I could use $_POST or $_SESSION, but my script may run several time at the same moment, exporting a different CSV each run. I'm afraid that changing these super global variable from scripts that may run at the same time make them collide, and change their value when I don't want to.
First : is the above affirmation true?
Then if it is, how can I store the number of row the script ended before refreshing the page. I though about creating a file, putting the informations inside and then read it. That may look like this :
customer_name : Jon
row_ended : 10584
customer_name : Jane
row_ended : 11564
But isn't there a more easier and efficient solution?
You can create a run ID and save it on the session.
Ex.
session_start();
$_SESSION['run']['id'] = 1; // or some unique ID
$_SESSION['run']['user'] = 'jon';
$_SESSION['run']['lastRow']= 0;
$startTime = time() + 160; // total secs
if($starTime > time() ){
// time of 160 passed redirect to same page.
$_SESSION['run']['lastRow']= 100000;
header("location: page.php");
exit;
}
But this will not solve the problem, can be be a redirect hell
You can try to increase the max execution time at runtime.
ini_set('max_execution_time',0); //will run forever
or the best solution run it as a shell command with max_execition_time = 0
users may navigate away the page if it takes too long.

Using php to display object at a specific time

This may seem like a simple thing but I just can't get my head around it. How do I use php to display a div on a website at a specific time for only a duration? Eg. Show object for 10min every hr.
Ok, I have an object ie ahajsjajshaksjaksjiajsns which is displayed on a website when visitors visit the site. But I don't want it to show all the time but say every hr. And to disappear from the website after 10min.
if(date("i") < 10) echo "...";
This code will echo ... every hour from minute 0 to minute 9. e.g. 8.00-8.09, 9.00-9.09, 10.00-10.09, ...
PHPs date function is able to give you values you can check against a specific date. For more information see the docs.
I haven't coded anything web in a few years, so forgive me if I'm rusty but:
You can't do this all serverside. The page will compile but unless the user refreshes the page, the object in question will be forever available.
What you want to do, is use kekub's example to generate the following code only if it's within the time range, but also include JavaScript to destroy it when time is up:
$time = date("i");
if($time < 10){
$timeToExpire = 10 - $time;
echo "<div id="yourObject">I will expire soon!</div>;
echo"<script type = 'text/javascript'>setTimeout(function() {
$('#yourObject').fadeOut('fast');
}, ".$timeToExpire * 10000.");</script>"; // * milliseconds e.g 6 minutes
}
I haven't tested it but what should happen is, the webpage will generate the div and also the code needed to hide it when the time is up (say there is only 6 minutes left to show it).
Although I think personally you should do this all in Javascript.
you can set time for two divs using setTimeout and can call divs in that function
setTimeout(function(){page2(mintime)},10000);
setTimeout(function(){page1(mintime)},10000);
This kind of function usually should not be done in server side. Anyway if you want to achieve this using PHP you can have something like this:
while (true) {
$result = yourfunction;
if (resultIsGood) {
break;
}
sleep(3);
}
You can sleep in a loop

PHP - Stop and catch code which takes too long

I'd like to limit a specific section of PHP to X seconds - if it takes longer, kill the currently executing code (just the section, not the entire script) and run an alternate code.
Pseudo code example (Example use case here is an unstable API which is sometimes fast and other times its a black hole):
$completed = 1;
$seconds = 60;
while ($completed != -1 && $completed < 5) {
limit ($seconds) {
$api = new SomeAPI('user','secret','key');
$data = $api->getStuff('user="bob"');
$completed = -1;
} catch () {
$completed++;
sleep(10);
}
}
if ($completed === 5) echo "Error: API black-hole'd 5 times.\n";
else {
//Notice: data processing is OUTSIDE of the time limit
foreach ($data as $row) {
echo $row['name'].': '.$row['message']."\n";
}
}
HOWEVER, this should work for anything. Not just API/HTTP requests. E.g. an intensive database procedure.
In case you're reading too fast: set_time_limit and max_execution_time are not the answer as they affect the time limit for the entire script rather than just a section (unless I'm wrong on how those work, of course).
In the case of an API call, I would suggest using cURL, for which you can set a specific timeout for the API call.
For generic use, you can look at forking processes, which would give you the ability to time each process and kill it if it exceeds the expected time.
Of course if the section of code might be subject to long execution times due to a highly repetitive loop structure, you can provide your own timers to break out of the loop after a specified time interval.
I might not have directly answered your question, but really the point I wanted to get to is that you might have to use a different approach depending on what the code block actually does.

PHP spreading a script into multiple parts to avoid server timeout

I have a script that is very long to execute, so when i run it it hit the max execution time on my webserver and end up timing out.
To illustrate that imagine i have a for loop that make some pretty intensive manipulation one million time. How could i spread this loop execution in several parts so that i don t hit the max execution time of my Webserver?
Many thanks,
If you have an application that is going to loop a known number of times (i.e. you are sure that it's going to finish some time) you can increase time limit inside the loop:
foreach ($data as $row) {
set_time_limit(10);
// do your stuff here
}
This solution will protect you from having one run-away iteration, but will let your whole script run undisturbed as long as you need.
Best solution is to use http://php.net/manual/en/function.set-time-limit.php to change the timeout. Otherwise, you can use 301 redirects to send to an updated URL on a timeout.
$threshold = 10000;
$t = microtime();
$i = isset( $_GET['i'] ) ? $_GET['i'] : 0;
for( $i; $i < 10000000; $i++ )
{
if( microtime - $t > $threshold )
{
header('Location: http://www.example.com/?i='.$i);
exit;
}
// Your code
}
The browser will only respect a few redirects before it stops, you're better to use javascript to force a page reload.
I someday used a technique where I splitted the work from one file into three parts. It was just an array of 120.000 elements with intensive operation. I created a splitter script which stored the arrays in a database of the size of 40.000 each one. Then I created an HTML file with a redirect to the first PHP file to compute the first 40.000 elements. After computing the first 40.000 elments I had again a HTML forward to the next PHP file and so on.
Not very elegant, but it worked :-)
If you have the right permissions on your hosting server, you could use the php interpreter to execute a php script and have it run in the background.
See Asynchronous shell exec in PHP.
if you are running a script that needs to execute for unknown time, you can use:
set_time_limit(0);
If possible you can make the script so that it handles a portion of the wanted operations. Once it completes say 10%, you via AJAX call the script again to execute the next 10%. But there are circumstances where this is not an ideal solution, it really depends on what you are doing.
I used this method to create a web-based crawler which only ran on my computer for instance. If it had to do the operations at once it would time out as well. So it was split into 200 "tasks", each called via Ajax once the previous completes. Works perfectly, and it's been over a year since it started running (crawling?)

best way to measure (and refine) performance with PHP?

A site I am working with is starting to get a little sluggish, and I would like to refine it. I think the problem is with the PHP, but I can't be sure. How can I see how long functions are taking to perform?
If you want to test the execution time :
<?php
$startTime = microtime(true);
// Your content to test
$endTime = microtime(true);
$elapsed = $endTime - $startTime;
echo "Execution time : $elapsed seconds";
?>
Try the profiler feature in XDebug or Zend Debugger?
Two things you can do.
place Microtime calls everywhere although its not convenient if you want to test more than one function. So there is a simpler way to do it a better solution if you want to test many functions which i assume you would like to do.
just have a class (click on link to follow tutorial) where you can test how long all your functions take. Rather than place microtime everywhere. you just use this class. which is very convenient
http://codeaid.net/php/calculate-script-execution-time-%28php-class%29
the second thing you can do is to optimize your script is by taking a look at the memory usage.
By observing the memory usage of your scripts, you may be able optimize your code better.
PHP has a garbage collector and a pretty complex memory manager. The amount of memory being used by your script. can go up and down during the execution of a script. To get the current memory usage, we can use the memory_get_usage() function, and to get the highest amount of memory used at any point, we can use the memory_get_peak_usage() function.
view plaincopy to clipboardprint?
echo "Initial: ".memory_get_usage()." bytes \n";
/* prints
Initial: 361400 bytes
*/
// let's use up some memory
for ($i = 0; $i < 100000; $i++) {
$array []= md5($i);
}
// let's remove half of the array
for ($i = 0; $i < 100000; $i++) {
unset($array[$i]);
}
echo "Final: ".memory_get_usage()." bytes \n";
/* prints
Final: 885912 bytes
*/
echo "Peak: ".memory_get_peak_usage()." bytes \n";
/* prints
Peak: 13687072 bytes
*/
http://net.tutsplus.com/tutorials/php/9-useful-php-functions-and-features-you-need-to-know/
PK
You can also make it manually, by recording microtime() value in various places, like this:
<?
$TIMER['start']=microtime(TRUE);
// some code
$query="SELECT ...";
$TIMER['before q']=microtime(TRUE);
$res=mysql_query($query);
$TIMER['after q']=microtime(TRUE);
while ($row = mysql_fetch_array($res)) {
// some code
}
$TIMER['array filled']=microtime(TRUE);
// some code
$TIMER['pagination']=microtime(TRUE);
/and so on
?>
and then visualize it
<?
if ('127.0.0.1' === $_SERVER['REMOTE_ADDR']) {
echo "<table border=1><tr><td>name</td><td>so far</td><td>delta</td><td>per cent</td></tr>";
reset($TIMER);
$start=$prev=current($TIMER);
$total=end($TIMER)-$start;
foreach($TIMER as $name => $value) {
$sofar=round($value-$start,3);
$delta=round($value-$prev,3);
$percent=round($delta/$total*100);
echo "<tr><td>$name</td><td>$sofar</td><td>$delta</td><td>$percent</td></tr>";
$prev=$value;
}
echo "</table>";
}
?>
an IP address check implies that we are doing this profiling on the working site
Though I doubt it's PHP itself. Most likely it's database. So, pay most attention to query execution timing.
however, a "site" term is very broad. It includes also JS, CSS, images and stuff. So, I'd suggest to start form FirebFug's Net page to see what part of whole page takes more time.
Of course, refining can be done only after analysis of profiling results, and cannot be advised here without it.
Your best bet is Xdebug. Im happy as it comes bundled in my PHPed IDE. I can get profiler data at the click of a button.
So maybe you could consider that.
I had similar issues and so I created 2 new tables on the database and two new functions. One was audit_sql and the other was audit_code. Because I used an SQL abstraction class it was easy to time every single SQL call (I used php microtime as some others have suggested). So, I called microtime before and after the SQL call and stored the results on the database.
Similarly with pages. I called microtime at the start and end of each page and if necessary at the start and end of functons, divs - whatever I thought might be a culprit.
The general results were:
SQL calls to MySQL were almost instantaneous and were nto a problem at all. The only thing I would say is that even I was surprised at the number being executed! The site is generated from the database - even the menus, permissions etc. To produce the home page the SQL calls were measured in the 100s.
PHP was not the culprit. This was even more instantaneous that MySQL.
The culprit was.... (big build up!) calls to You Tube and Picassa and other sites like that. I host videos and photo albums on the site (well, I don't actually store them - they are stored on YT etc.) and on the home page are thumbnails that are extracted from You Tube and the like via the You Tube PHP API/Zend Framework. Because this is all http based to the other sites, each one was taking 1, 2 or 3 seconds. This was causing those divs containing these to take between 6 and 12 seconds and the home page up to 17 seconds.
The solution - store all thumbnails on my server. The first time one has to be served from the remote site (YT, Picassa etc.) so do that and then store it on your own site. Future times, you check if you have it and if so serve it always from your server. Cuts the page load time down to 2-3 seconds tops. Granted the first person to view the first home page load after someone has loaded more videos/images will take some time, but not thereafter. People will put a long one-off page load time down to their connection/the internet in general. Too many slow loads of your site and they will stop visiting!
I hope that helps somewhat.

Categories