Im trying to implement a solution for database user limit exceed problem by using a different database user every 3 minutes.
I created 4 users and the script works fine with 3 users but at the forth one, it returns the first username again and keep returning it a while.
<?php
function GetUser()
{
$file = $_SERVER['DOCUMENT_ROOT'] .'/dbUsers.txt';
$users = array("user1", "user2", "user3","user4");
$user = "";
$userIndex = 0;
if (file_exists($file)) {
if (filemtime($file) < time()-100) //0.5*3600
{
$userIndex = file_get_contents($file);
if($userIndex >4)
$userIndex =0;
file_put_contents($file, $userIndex + 1);
}
}
else
{
file_put_contents($file, $userIndex);
}
$user = $users[$userIndex];
return $user;
}
?>
Thanks in advance.
Why using a file and file time. You said "every 30 minutes"
function GetUser()
{
# static: define once on scan/compile time
static $users = array("user1","user2","user3","user4");
$index = intval( time() / (30*60) ) % count($users);
return $users[$index];
}
Notes: time() returns the number of seconds since epoch (1971-01-01 0:00:00 UTC). Then I divided it by 30 minutes (30*60). The modulo operator % iterates through the user list.
So I'd like to add the current time to the database, to a specific user when he does something, and later on read it, and check if that time has passed (by checking current time and substracting that from the one in database; to check if it has passed or not)
So how would I do this? I tried with something like this:
$date = date("YmWjis");
$calculate = $date - $info['lastvisit'];
if($calculate <= -1)
{
echo "you need to wait before visiting again"; // (just an example)
} else {
//do something
}
I also tried both:
!$calculate < 0
$calculate < 0
etc. But I can't get it to work. Can anyone help me? :P
edit for Parag;
$date = date("YmWjis");
$dote = date("YmWjis") + $time; // ($time is set earlier and is 30 seconds)
echo "wait " . $date = $date - $dote . " seconds until next visit";
work?
It says like "wait 20138269786674 seconds until next visit".
You can try something like this:
$dateDiff = new DateTime("2014-04-27 22:00:15");
$date = new DateTime();
$diff = $date->diff($dateDiff);
if($diff->invert == 0)
{
echo "you need to wait before visiting again"; // (just an example)
} else {
//do something
}
$db_time = "2014/04/28 15:15:15";
$cur_time = "2014/04/28 18:15:15";
if(strtotime($cur_time) > strtotime($db_time))
{
// Current time exceeds DB time
$diff = date('Y/m/d H:i:s', strtotime($cur_time)-strtotime($db_time));
echo $diff;
}
else
{
// Current time didn't exceeds DB time
}
UPDATE
$date = strtotime(date("YmWjis"));
$dote = strtotime(date("YmWjis")) + $time; // ($time is set earlier and is 30 seconds)
echo "wait " . $date = $date - $dote . " seconds until next visit";
DEMO
http://3v4l.org/LBIXu
Don't use a database. This does the job without the db overhead. It uses PHP sessions.
<?php
session_start();
if (!isset($_SESSION['lastVisitTime'])) {
$_SESSION['lastVisitTime']=new DateTime();
} else {
$now=new DateTime();
if ($_SESSION['lastVisitTime']->diff($now) > $someMaxValueYouDefine) {
echo "You must wait before visiting again.";
}
}
An interesting problem, for a piece of Uni coursework we have been challenged to run a simulation of a server receiving requests and then processing them. I have build and rebuild this multiple times and I think have made it as efficient as I am able, is there anything you can see to improve the efficiency of this program?
The simulation is run for $simulationLength and at each $currentTime there is a 1/$arrival_rate chance of a new request arriving. A queue of size $maxQueueSize holds these requests and rejects them if the queue is full. For each $currentTime a CPU may remove an item from the $queue and work on it for $executionTime seconds at which point the CPU (server) is removed from the busy queue and is free to work on another request.
My code:
<?php
...SNIP error checking...
$queue_size = isset($argv[1]) ? $argv[1] : 10000;
$arrival_rate = isset($argv[2]) ? $argv[2] : 3;
$number_of_servers = isset($argv[3]) ? $argv[3] : 2;
$execution_time = isset($argv[4]) ? $argv[4] : 25;
...SNIP error checking...
$simulationLength = 1000000;
$arrivalRate = $arrival_rate;
$executionTime = $execution_time;
$busyServers = array();
$freeServers = $number_of_servers;
$currentTime = 0;
$currentQueueSize = 0;
$maxQueueSize = $queue_size; //Max
$queue = array();
//Stats
$totalRequests = 0;
$rejectedRequests = 0;
$queueSize = array_fill(0, 100, $simulationLength);
$totalWaitingTime = 0;
//while the simulation is running
while($currentTime++ < $simulationLength) {
//a request has arrived
if(mt_rand(1, $arrival_rate)==1) {
$totalRequests++;
//Adding to the queue
if($currentQueueSize < $maxQueueSize) {
$currentQueueSize++;
array_push($queue, $currentTime); //add to the end of the queue
} else {
$rejectedRequests++;
}
} //end request arrived
//Only one server can fetch requests at a time
if(!empty($busyServers)&&reset($busyServers) < $currentTime) {
unset($busyServers[key($busyServers)]); //remove first element - efficient
$freeServers++; //increase free servers
}
//Only one server can fetch requests at a time
if($currentQueueSize>0&&$freeServers>1) {
$currentQueueSize--;
reset($queue); //reset pointer
$queueTime = $queue[key($queue)]; //read of the front
unset($busyServers[key($busyServers)]); //delete off print
$freeServers--; //use up a server
$busyServers[] = $currentTime + $executionTime; //mark when free
$totalWaitingTime += ($currentTime - $queueTime) + $executionTime;
}
$queueSize[$currentTime] = $currentQueueSize;
}
printf("Requests served %d\n", $totalRequests);
printf("Rejected requests %d\n", $rejectedRequests);
printf("Total waiting time %d\n", $totalWaitingTime);
printf("Percentage of rejected requests %0.1f\n", $rejectedRequests/$totalRequests);
printf("The average queue size %d\n", array_sum($queueSize)/sizeof($queueSize));
printf("Average response time %d\n", $totalWaitingTime/$totalRequests);
?>
Thanks for your time,
Micro-optimisations but:
When in a heavy loop like this, --$preIncrement is faster than
$postIncrement++
array_push($queue, $currentTime); is a function call
overhead: use $queue[] = $currentTime; instead
$currentTime + $executionTime is being calculated twice, calculate it once and store the result, then use that
I want to block visitor between 2 to 5 minutes every 100 view.. if user view 100 page between 2 to 5 minutes then block user, if user view 100 view in 6 minutes then don't block and reset the counter.
I already create the counter script but i have issue with creating the function which can block visitor between 2-5 mint.
I need help to fix this problem... I try to create a if condition but no luck.. help me please...
$sb_current_time = date("Y-m-d H:i:s", Time());
/////////////////// Cookies Encryption //////////////
function encrypt($text)
{
$key = "E4HD9h4DhS23DYfhHemkS3Nf"; // 24 bit Key
$iv = "fYfhHeDm"; // 8 bit IV
$bit_check = 8;
$text_num = str_split($text, $bit_check);
$text_num = $bit_check - strlen($text_num[count($text_num) - 1]);
for ($i = 0; $i < $text_num; $i++) {
$text = $text . chr($text_num);
}
$cipher = mcrypt_module_open(MCRYPT_TRIPLEDES, '', 'cbc', '');
mcrypt_generic_init($cipher, $key, $iv);
$decrypted = mcrypt_generic($cipher, $text);
mcrypt_generic_deinit($cipher);
return base64_encode($decrypted);
}
//////////////// Encription end /////////
////// Cookies decription /////
function decrypt($encrypted_text)
{
$key = "E4HD9h4DhS23DYfhHemkS3Nf"; // 24 bit Key
$iv = "fYfhHeDm"; // 8 bit IV
$bit_check = 8;
$cipher = mcrypt_module_open(MCRYPT_TRIPLEDES, '', 'cbc', '');
mcrypt_generic_init($cipher, $key, $iv);
if ($encrypted_text != "") {
$decrypted = mdecrypt_generic($cipher, base64_decode($encrypted_text));
mcrypt_generic_deinit($cipher);
$last_char = substr($decrypted, -1);
for ($i = 0; $i < $bit_check - 1; $i++) {
if (chr($i) == $last_char) {
$decrypted = substr($decrypted, 0, strlen($decrypted) - $i);
break;
}
}
}
return $decrypted;
}
///////// Coookies decription end /////////////////
//$sb_check_ban_time = date($sb_current_time, strtotime("+20 minute"));
if ($_COOKIE['spamer_check_time'] == "") {
setcookie('spamer_check_time', encrypt(time()));
}
function time_deff($date2)
{
$date1 = time();
//sleep(2000);
// $date2 = decrypt($_COOKIE['spamer_check_time']);
//echo $date2;
$mins = ($date1 - $date2) / 60;
//echo $mins;
return $mins;
}
//$sb_cookie_expiration = time() + 1200;
//echo $sb_cookie_expiration;
if ($_COOKIE['view2'] != "") {
$explod = explode("-", decrypt($_COOKIE["view2"]));
}
$i_print = $explod[0];
// $i2=$explod[1];
//echo $i2;
$i = 1 + $i_print;
setcookie("view2", encrypt($i . "-123456789")); //// Need to add extra bit to block unwanted text and secure the cookes more..
//
$i = $i++;
// echo $i_print;
//echo "empty".decrypt($_COOKIE["spamer_check_time"]);
$spammer_blocker = decrypt($_COOKIE["spammer_blocker"]);
// or $spammer_blocker==""
$mins = time_deff(decrypt($_COOKIE['spamer_check_time']));
$diff_time = .1; /// User BLock Time
if ($mins >=1 or $mins <=2) {
$block_user=1;
} elseif ($mins >= 2.1) {
$block_user=2;
} else {
}
/* if (.2>$mint) {
// echo "not done";
$block_user=0;
} elseif (.2 <= $mint) {
echo "block User";
$block_user=1;
} elseif ($mins>=1) {
echo "reset cookies";
$block_user=2;
}*/
if ($block_user==1 and $i_print >= 15) {
if ($spammer_blocker == "") {
setcookie("spammer_blocker", encrypt(time()));
header('HTTP/1.1 403 Forbidden');
$time_rev = $diff_block_time - $diff_time;
$round_time = round($time_rev, 2);
$time_reverse = str_replace('-', '', $round_time);
echo "Wait " . $time_reverse . " Minuts before using this site..";
exit(0);
} else {
//$sb_check_ban_time = $spammer_blocker;
$diff_block_time = time_deff($spammer_blocker);
//echo $diff_block_time;
//$sb_check_ban_time = date($spammer_blocker, strtotime("+1 minute"));
if ($diff_time <= $diff_block_time) {
/// echo "Delete the IP and cookies";
setcookie("spammer_blocker", "");
setcookie("view2", "");
setcookie("spamer_check_time", "");
} else {
//echo "Still Block"; /// echo "Still Block";
header('HTTP/1.1 403 Forbidden');
// echo "IP Block for Spaming wait few mint";
$time_rev = $diff_block_time - $diff_time;
$round_time = round($time_rev, 2);
$time_reverse = str_replace('-', '', $round_time);
echo "Wait " . $time_reverse . " Minuts before using this site..";
exit(0);
}
}
} elseif ($block_user==2) {
setcookie("spammer_blocker", "");
setcookie("view2", "");
setcookie("spamer_check_time", "");
echo "cookies reset";
} else {
}
First, you need to know who they are...
For casual users, you can rely on cookies. But if you are having problem with an abuser, then they will simply ignore your attempt to stop them and not send a cookie.
There are various levels of knowing "who" someone is.
ID in URL
Cookies
IP Address
And they can ALL be overcome with different levels of diffulculty...
Way too easy (just spoof a different ID, etc...)
Cookies are the same as #1
IP addresses are harder to overcome unless you have a botnet or similar
For your case, you should likely block the IP address as it's the only reasonable way for you to get done what you are looking for.
--
Next, you need to be able to keep track of their connections. iptables in Linux has a way to track the number of connections and block for a specific number of minutes after a certian threshold is reached.
Using only PHP, you need to record each hit, and the IP address of that hit. An SQL database would be one of the more efficient ways of doing this.
If you don't care about history, then simply (mysql):
INSERT INTO HitTable SET IP=..., Visits=1
ON DUPLICATE KEY UPDATE Visits=Visits+1
A background crontab could run a query like this every minute?
UPDATE HitTable SET Visits = Visits - 10
DELETE FROM HitTable WHERE Visits < 1
Finally, when a visitor visits, you would check the database table for
SELECT Visits<100 WHERE IP=...
AND if that returns True, let them in, else block them.
Hope this helps a bit.
Storing the timeout value in a cookie will be absolutely trivial for a user to change/delete the cookie
Storing it in a session variable is a bit more reliable, but again - the user could just delete the session cookie, get a new session going, and start reading again.
That being said, you'd do something like this:
<?php
session_start();
if (user_should_be_blocked()) {
$_SESSION['blocked_start_time'] = time();
header("Location: timeout.html");
}
if ($_SESSION['blocked_start_time'] > (time() - 300)) {
header("Location: timeout.html");
}
// got here, must not be blocked and/or timeout has expired
$_SESSION['blocked'] = false;
$_SESSION['block_start_time'] = null;
.... continue on
I would use the header funciton to redirect them to another page, either empty or just less bankwidth intensive (assuming that's why you're making this anyway). Soemthing like...
if ($block_user == 1)
header("Location: blockPage.php");
At the top of all pages you need to block.
Edit: actually, come to think of it, (2) is of course not necessary, if 2 people or 2 computers are logged in they'll only consume their alloted amount of views faster..
You can do this provided:
A user needs to be logged in to see the pages.
You don't allow the same user(name) to be logged in twice with different sessions.
You store the count per-user, not per-session or per-ip/whatever.
(2) is not possible with default file based sessions. A custom database or other persistent storage solution is needed in which you can scan for other session-id's of a current user-id. In a database you would just store a user-id field, a custom memcached solution could also be built, etc. To prevent users being locked out of a session they no longer have my solution was always to destroy any old session a user had the moment they log in. Effectively, if it's tried with multiple sessions/ips, they'll have to log in again and again invalidating the previous session.
(3) again some persistent storage with a timestamp+userid+count (in MySQL's case an INSERT INTO tablename (user_id,time,count) VALUES (<id>,NOW(),1) ON DUPLICATE KEY UPDATE count=count+1 comes to mind to easily increment view counts.
And on every view query the database again and again about how many views the visitor had the last X minutes.
PHP must track the amount of CPU time a particular script has used in order to enforce the max_execution_time limit.
Is there a way to get access to this inside of the script? I'd like to include some logging with my tests about how much CPU was burnt in the actual PHP (the time is not incremented when the script is sitting and waiting for the database).
I am using a Linux box.
If all you need is the wall-clock time, rather than the CPU execution time, then it is simple to calculate:
//place this before any script you want to calculate time
$time_start = microtime(true);
//sample script
for($i=0; $i<1000; $i++){
//do anything
}
$time_end = microtime(true);
//dividing with 60 will give the execution time in minutes otherwise seconds
$execution_time = ($time_end - $time_start)/60;
//execution time of the script
echo '<b>Total Execution Time:</b> '.$execution_time.' Mins';
// if you get weird results, use number_format((float) $execution_time, 10)
Note that this will include the time that PHP is sat waiting for external resources such as disks or databases, which is not used for max_execution_time.
On unixoid systems (and in php 7+ on Windows as well), you can use getrusage, like:
// Script start
$rustart = getrusage();
// Code ...
// Script end
function rutime($ru, $rus, $index) {
return ($ru["ru_$index.tv_sec"]*1000 + intval($ru["ru_$index.tv_usec"]/1000))
- ($rus["ru_$index.tv_sec"]*1000 + intval($rus["ru_$index.tv_usec"]/1000));
}
$ru = getrusage();
echo "This process used " . rutime($ru, $rustart, "utime") .
" ms for its computations\n";
echo "It spent " . rutime($ru, $rustart, "stime") .
" ms in system calls\n";
Note that you don't need to calculate a difference if you are spawning a php instance for every test.
Shorter version of talal7860's answer
<?php
// At start of script
$time_start = microtime(true);
// Anywhere else in the script
echo 'Total execution time in seconds: ' . (microtime(true) - $time_start);
As pointed out, this is 'wallclock time' not 'cpu time'
<?php
// Randomize sleeping time
usleep(mt_rand(100, 10000));
// As of PHP 5.4.0, REQUEST_TIME_FLOAT is available in the $_SERVER superglobal array.
// It contains the timestamp of the start of the request with microsecond precision.
$time = microtime(true) - $_SERVER["REQUEST_TIME_FLOAT"];
echo "Did nothing in $time seconds\n";
?>
I created an ExecutionTime class out of phihag answer that you can use out of box:
class ExecutionTime
{
private $startTime;
private $endTime;
public function start() {
$this->startTime = getrusage();
}
public function end() {
$this->endTime = getrusage();
}
private function runTime($ru, $rus, $index) {
return ($ru["ru_$index.tv_sec"]*1000 + intval($ru["ru_$index.tv_usec"]/1000))
- ($rus["ru_$index.tv_sec"]*1000 + intval($rus["ru_$index.tv_usec"]/1000));
}
public function __toString() {
return "This process used " . $this->runTime($this->endTime, $this->startTime, "utime") .
" ms for its computations\nIt spent " . $this->runTime($this->endTime, $this->startTime, "stime") .
" ms in system calls\n";
}
}
Usage:
$executionTime = new ExecutionTime();
$executionTime->start();
// Code
$executionTime->end();
echo $executionTime;
Note: In PHP 5, the getrusage function only works in Unix-oid systems. Since PHP 7, it also works on Windows.
It is going to be prettier if you format the seconds output like:
echo "Process took ". number_format(microtime(true) - $start, 2). " seconds.";
will print
Process took 6.45 seconds.
This is much better than
Process took 6.4518549156189 seconds.
Gringod at developerfusion.com gives this good answer:
<!-- put this at the top of the page -->
<?php
$mtime = microtime();
$mtime = explode(" ",$mtime);
$mtime = $mtime[1] + $mtime[0];
$starttime = $mtime;
;?>
<!-- put other code and html in here -->
<!-- put this code at the bottom of the page -->
<?php
$mtime = microtime();
$mtime = explode(" ",$mtime);
$mtime = $mtime[1] + $mtime[0];
$endtime = $mtime;
$totaltime = ($endtime - $starttime);
echo "This page was created in ".$totaltime." seconds";
;?>
From (http://www.developerfusion.com/code/2058/determine-execution-time-in-php/)
To show minutes and seconds you can use:
$startTime = microtime(true);
$endTime = microtime(true);
$diff = round($endTime - $startTime);
$minutes = floor($diff / 60); // Only minutes
$seconds = $diff % 60; // Remaining seconds, using modulo operator
echo "script execution time: minutes:$minutes, seconds:$seconds"; // Value in seconds
The cheapest and dirtiest way to do it is simply make microtime() calls at places in your code you want to benchmark. Do it right before and right after database queries and it's simple to remove those durations from the rest of your script execution time.
A hint: your PHP execution time is rarely going to be the thing that makes your script timeout. If a script times out it's almost always going to be a call to an external resource.
PHP microtime documentation:
http://us.php.net/microtime
I think you should look at xdebug. The profiling options will give you a head start toward knowing many process related items.
http://www.xdebug.org/
$_SERVER['REQUEST_TIME']
check out that too. i.e.
...
// your codes running
...
echo (time() - $_SERVER['REQUEST_TIME']);
when there is closure functionality in PHP, why not we get benefit out of it.
function startTime(){
$startTime = microtime(true);
return function () use ($startTime){
return microtime(true) - $startTime;
};
}
Now with the help of the above function, we can track time like this
$stopTime = startTime();
//some code block or line
$elapsedTime = $stopTime();
Every call to startTime function will initiate a separate time tracker. So you can initiate as many as you want and can stop them wherever you want them.
Small script that print, centered in bottom of the page, the script execution that started at server call with microsecond precision.
So as not to distort the result and to be 100% compatible with content in page, I used, to write the result on the page, a browser-side native javascript snippet.
//Uncomment the line below to test with 2 seconds
//usleep(2000000);
$prec = 5; // numbers after comma
$time = number_format(microtime(true) - $_SERVER['REQUEST_TIME_FLOAT'], $prec, '.', '');
echo "<script>
if(!tI) {
var tI=document.createElement('div');
tI.style.fontSize='8px';
tI.style.marginBottom='5px';
tI.style.position='absolute';
tI.style.bottom='0px';
tI.style.textAlign='center';
tI.style.width='98%';
document.body.appendChild(tI);
}
tI.innerHTML='$time';
</script>";
Another approach is to make the snippet as small as possible, and style it with a class in your stylesheet.
Replace the echo ...; part with the following:
echo "<script>if(!tI){var tI=document.createElement('div');tI.className='ldtme';document.body.appendChild(tI);}tI.innerHTML='$time';</script>";
In your CSS create and fill the .ldtme{...} class.
I wrote a function that check remaining execution time.
Warning: Execution time counting is different on Windows and on Linux platform.
/**
* Check if more that `$miliseconds` ms remains
* to error `PHP Fatal error: Maximum execution time exceeded`
*
* #param int $miliseconds
* #return bool
*/
function isRemainingMaxExecutionTimeBiggerThan($miliseconds = 5000) {
$max_execution_time = ini_get('max_execution_time');
if ($max_execution_time === 0) {
// No script time limitation
return true;
}
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
// On Windows: The real time is measured.
$spendMiliseconds = (microtime(true) - $_SERVER["REQUEST_TIME_FLOAT"]) * 1000;
} else {
// On Linux: Any time spent on activity that happens outside the execution
// of the script such as system calls using system(), stream operations
// database queries, etc. is not included.
// #see http://php.net/manual/en/function.set-time-limit.php
$resourceUsages = getrusage();
$spendMiliseconds = $resourceUsages['ru_utime.tv_sec'] * 1000 + $resourceUsages['ru_utime.tv_usec'] / 1000;
}
$remainingMiliseconds = $max_execution_time * 1000 - $spendMiliseconds;
return ($remainingMiliseconds >= $miliseconds);
}
Using:
while (true) {
// so something
if (!isRemainingMaxExecutionTimeBiggerThan(5000)) {
// Time to die.
// Safely close DB and done the iteration.
}
}
Further expanding on Hamid's answer, I wrote a helper class that can be started and stopped repeatedly (for profiling inside a loop).
class ExecutionTime
{
private $startTime;
private $endTime;
private $compTime = 0;
private $sysTime = 0;
public function Start() {
$this->startTime = getrusage();
}
public function End() {
$this->endTime = getrusage();
$this->compTime += $this->runTime($this->endTime, $this->startTime, "utime");
$this->systemTime += $this->runTime($this->endTime, $this->startTime, "stime");
}
private function runTime($ru, $rus, $index) {
return ($ru["ru_$index.tv_sec"]*1000 + intval($ru["ru_$index.tv_usec"]/1000)) - ($rus["ru_$index.tv_sec"]*1000 + intval($rus["ru_$index.tv_usec"]/1000));
}
public function __toString() {
return "This process used " . $this->compTime . " ms for its computations\n" . "It spent " . $this->systemTime . " ms in system calls\n";
}
}
You may only want to know the execution time of parts of your script. The most flexible way to time parts or an entire script is to create 3 simple functions (procedural code given here but you could turn it into a class by putting class timer{} around it and making a couple of tweaks). This code works, just copy and paste and run:
$tstart = 0;
$tend = 0;
function timer_starts()
{
global $tstart;
$tstart=microtime(true); ;
}
function timer_ends()
{
global $tend;
$tend=microtime(true); ;
}
function timer_calc()
{
global $tstart,$tend;
return (round($tend - $tstart,2));
}
timer_starts();
file_get_contents('http://google.com');
timer_ends();
print('It took '.timer_calc().' seconds to retrieve the google page');
Just to contribute to this conversation:
what happens if the measurement targets two points A and B in different php files?
what if we need different measurements like time based, code execution duration, external resource access duration?
what if we need to organize our measurements in categories where every one has a different starting point?
As you suspect we need some global variables to be accessed by a class object or a static method: I choose the 2nd approach and here it is:
namespace g3;
class Utils {
public function __construct() {}
public static $UtilsDtStart = [];
public static $UtilsDtStats = [];
public static function dt() {
global $UtilsDtStart, $UtilsDtStats;
$obj = new \stdClass();
$obj->start = function(int $ndx = 0) use (&$UtilsDtStart) {
$UtilsDtStart[$ndx] = \microtime(true) * 1000;
};
$obj->codeStart = function(int $ndx = 0) use (&$UtilsDtStart) {
$use = \getrusage();
$UtilsDtStart[$ndx] = ($use["ru_utime.tv_sec"] * 1000) + ($use["ru_utime.tv_usec"] / 1000);
};
$obj->resourceStart = function(int $ndx = 0) use (&$UtilsDtStart) {
$use = \getrusage();
$UtilsDtStart[$ndx] = $use["ru_stime.tv_usec"] / 1000;
};
$obj->end = function(int $ndx = 0) use (&$UtilsDtStart, &$UtilsDtStats) {
$t = #$UtilsDtStart[$ndx];
if($t === null)
return false;
$end = \microtime(true) * 1000;
$dt = $end - $t;
$UtilsDtStats[$ndx][] = $dt;
return $dt;
};
$obj->codeEnd = function(int $ndx = 0) use (&$UtilsDtStart, &$UtilsDtStats) {
$t = #$UtilsDtStart[$ndx];
if($t === null)
return false;
$use = \getrusage();
$dt = ($use["ru_utime.tv_sec"] * 1000) + ($use["ru_utime.tv_usec"] / 1000) - $t;
$UtilsDtStats[$ndx][] = $dt;
return $dt;
};
$obj->resourceEnd = function(int $ndx = 0) use (&$UtilsDtStart, &$UtilsDtStats) {
$t = #$UtilsDtStart[$ndx];
if($t === null)
return false;
$use = \getrusage();
$dt = ($use["ru_stime.tv_usec"] / 1000) - $t;
$UtilsDtStats[$ndx][] = $dt;
return $dt;
};
$obj->stats = function(int $ndx = 0) use (&$UtilsDtStats) {
$s = #$UtilsDtStats[$ndx];
if($s !== null)
$s = \array_slice($s, 0);
else
$s = false;
return $s;
};
$obj->statsLength = function() use (&$UtilsDtStats) {
return \count($UtilsDtStats);
};
return $obj;
}
}
Now all you have is to call the method that belongs to the specific category with the index that denotes it's unique group:
File A
------
\call_user_func_array(\g3\Utils::dt()->start, [0]); // point A
...
File B
------
$dt = \call_user_func_array(\g3\Utils::dt()->end, [0]); // point B
Value $dt contains the milliseconds of wall clock duration between points A and B.
To estimate the time took for php code to run:
File A
------
\call_user_func_array(\g3\Utils::dt()->codeStart, [1]); // point A
...
File B
------
$dt = \call_user_func_array(\g3\Utils::dt()->codeEnd, [1]); // point B
Notice how we changed the index that we pass at the methods.
The code is based on the closure effect that happens when we return an object/function from a function (see that \g3\Utils::dt() repeated at the examples).
I tested with php unit and between different test methods at the same test file it behaves fine so far!
Hope that helps someone!
As an alternative you can just put this line in your code blocks and check php logs, for really slow functions it's pretty useful:
trigger_error("Task done at ". strftime('%H:%m:%S', time()), E_USER_NOTICE);
For serious debugging use XDebug + Cachegrind, see https://blog.nexcess.net/2011/01/29/diagnosing-slow-php-execution-with-xdebug-and-kcachegrind/
There are several way of doing this, listed here. But each have their own pro's and con's. And (in my opinion) the readability of all longer answers are terrible.
So I decided to put it all together in one answer, that is easily usable and readable.
Usage
$start = get_timers();
for( $i = 0; $i < 100000; $i++ ){
// Code to check
}
$end = get_timers();
display_timer_statistics( $start, $end );
Function definitions
function display_timer_statistics( $start_timers, $end_timers ){
// Settings
$key_width = '100px';
$decimals = 4;
$decimals_wallclock = $decimals;
$decimals_request_time_float = $decimals;
// Variables
$start_resource_usage_timer = $start_timers[0];
$start_wallclock = $start_timers[1];
$end_resource_usage_timer = $end_timers[0];
$end_wallclock = $end_timers[1];
// # User time
// Add seconds and microseconds for the start/end, and subtract from another
$end_user_time_seconds = $end_resource_usage_timer["ru_utime.tv_sec"]*1000;
$end_user_time_microseconds = intval($end_resource_usage_timer["ru_utime.tv_usec"]/1000);
$start_user_time_seconds = $start_resource_usage_timer["ru_utime.tv_sec"]*1000;
$start_user_time_microseconds = intval($start_resource_usage_timer["ru_utime.tv_usec"]/1000);
$total_user_time = ($end_user_time_seconds + $end_user_time_microseconds) - ($start_user_time_seconds + $start_user_time_microseconds);
// # System time
// Add seconds and microseconds for the start/end, and subtract from another
$end_system_time_seconds = $end_resource_usage_timer["ru_stime.tv_sec"]*1000;
$end_system_time_microseconds = intval($end_resource_usage_timer["ru_stime.tv_usec"]/1000);
$start_system_time_seconds = $start_resource_usage_timer["ru_stime.tv_sec"]*1000;
$start_system_time_microseconds = intval($start_resource_usage_timer["ru_stime.tv_usec"]/1000);
$total_system_time = ($end_system_time_seconds + $end_system_time_microseconds) - ($start_system_time_seconds + $start_system_time_microseconds);
// Wallclock
$total_wallclock_time = number_format( ( $end_wallclock - $start_wallclock), $decimals_wallclock );
// Server request_time_float
$request_time_float = microtime(true) - $_SERVER["REQUEST_TIME_FLOAT"];
$request_time_float = number_format( $request_time_float, $decimals_request_time_float );
// Print
$span_start = "<span style='width: $key_width; display: inline-block;'>";
$span_end = "</span>";
$output = "# RUNTIME AND TIMERS " . PHP_EOL ;
$output .= PHP_EOL;
$output .= $span_start . $total_user_time . $span_end . " User time (utime)" . PHP_EOL;
$output .= $span_start . $total_system_time . $span_end . " System time (stime)" . PHP_EOL;
$output .= PHP_EOL;
$output .= $span_start . $total_wallclock_time . $span_end . " Wallclock" . PHP_EOL;
$output .= PHP_EOL;
$output .= $span_start . $request_time_float . $span_end . " REQUEST_TIME_FLOAT" . PHP_EOL . PHP_EOL . PHP_EOL;
echo nl2br( $output );
}
function get_timers(){
return [ getrusage(), microtime( true ) ];
}
Glossary
All gotten from PHP docs for getrusage
Wallclock = How long it takes
ru = Resource usage
utime = User time used
stime = System time used
tv_sec = In seconds.
tv_usec = In microseconds.
tv = ?? Dunno
return microtime(true) - $_SERVER["REQUEST_TIME_FLOAT"];